aboutsummaryrefslogtreecommitdiff
path: root/cddl/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'cddl/contrib')
-rw-r--r--cddl/contrib/opensolaris/OPENSOLARIS.LICENSE384
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/dtrace.1785
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/dtrace.c2012
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/README32
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/cmd/baddof/baddof.c207
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/cmd/badioctl/badioctl.c145
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/cmd/chkargs/chkargs.c149
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/Getopt.java453
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/JDTrace.java1042
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/exception.lst79
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/jdtrace.c60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/manifest/jdtrace.jar-manifest3
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl240
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dtest.pl706
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.rax.c43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.rax.d36
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.uregsarray.d82
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_FUNC.bad.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_MDIM.bad.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_NULL.bad.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_REDEF.redef.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.avgtoofew.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.maxnoarg.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.mintoofew.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.quantizetoofew.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.stddevtoofew.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.sumtoofew.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_CLEAR_AGGARG.bad.d77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_CLEAR_PROTO.bad.d77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_FUNC_IDENT.bad.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_FUNC_UNDEF.badaggfunc.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.badexpr.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.badkey3.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.noeffect.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey1.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey2.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey4.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASETYPE.lqbad1.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASETYPE.lqshort.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASEVAL.bad.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_LIMTYPE.lqbad1.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_LIMVAL.bad.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHBASE.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHBASE.order.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHLIM.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHLIM.order.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHSTEP.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MISMATCH.lqbadarg.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPLARGE.lqtoofew.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPSMALL.bad.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPTYPE.lqbadinc.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPVAL.bad.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_AGGARG.bad.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_PROTO.bad.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_SCALAR.bad.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_ARG.lquantizetoofew.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.avgnoarg.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.avgtoomany.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.counttoomany.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.lquantizenoarg.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.lquantizetoomany.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.maxnoarg.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.maxtoomany.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.minnoarg.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.mintoomany.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.quantizenoarg.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.quantizetoomany.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.stddevnoarg.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.stddevtoomany.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.sumnoarg.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.sumtoomany.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_AGGARG.bad.d35
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_PROTO.badmany.d34
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_PROTO.badnone.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_SCALAR.bad.d34
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggencoding.d32
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggencoding.d.out646
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.agghist.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.agghist.d.out38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpack.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpack.d.out124
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackbanner.ksh75
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackbanner.ksh.out102
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackzoom.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackzoom.d.out149
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggzoom.d35
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggzoom.d.out211
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.allquant.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.allquant.d.out131
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg_neg.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg_neg.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clear.d75
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clear.d.out22
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg2.d63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg2.d.out16
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.cleardenormalize.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.cleardenormalize.d.out22
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearlquantize.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearlquantize.d.out94
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearnormalize.d77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearnormalize.d.out22
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearstddev.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearstddev.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count2.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count2.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count3.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalize.d63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalize.d.out7
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalizeonly.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalizeonly.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.fmtnormalize.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.fmtnormalize.d.out7
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.forms.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.forms.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.goodkey.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.keysort.d108
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.keysort.d.out160
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantize.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantize.d.out61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantnormal.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantnormal.d.out16
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantrange.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantrange.d.out23
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantround.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantround.d.out9
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantzero.d96
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantzero.d.out910
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max.d58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max_neg.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max_neg.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min_neg.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min_neg.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs1.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs2.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs2.d.out37
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs3.d74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs3.d.out38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multinormalize.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multinormalize.d.out15
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.neglquant.d150
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.neglquant.d.out64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negorder.d85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negorder.d.out376
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negquant.d115
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negquant.d.out55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtrunc.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtrunc.d.out11
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtruncquant.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtruncquant.d.out46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.normalize.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.normalize.d.out7
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.order.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.order.d.out33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantize.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantize.d.out61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantmany.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantmany.d.out1208
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantround.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantround.d.out9
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantzero.d63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantzero.d.out146
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signature.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeys.d120
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeys.d.out44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeyspos.d115
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeyspos.d.out61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d35
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.normalize.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.normalize.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.subr.d115
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sum.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sum.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc.d.out11
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc0.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc0.d.out7
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.truncquant.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.truncquant.d.out46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.valsortkeypos.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.valsortkeypos.d.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0_1.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0_2.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.modby0.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.addmin.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.divmin.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.muladd.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.muldiv.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d.out8
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d.out10
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d36
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d.out10
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_ARR_BADREF.bad.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRBIG.toobig.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRNULL.bad.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRSUB.bad.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_PROTO_TYPE.badtuple.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_IDENT_UNDEF.badureg.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic1.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic2.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic3.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic4.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic5.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic6.d58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.uregsarray.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.dupgtype.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.dupttype.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.this.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_ARG.badsig.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_LEN.toofew.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_LEN.toomany.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_SYNTAX.errassign.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.tupoflow.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.cpyarray.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.diffprofile.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.initialize.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.invalidref.d75
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.misc.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.orthogonality.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.this.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.valassign.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/err.D_PDESC_ZERO.begin.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/err.D_PDESC_ZERO.tick.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.begin.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.begin.d.out5
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.multibegin.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.multibegin.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_ADDROF_BITFIELD.BitfieldAddress.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFCONST.NegBitField.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFCONST.ZeroBitField.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFSIZE.ExceedBaseType.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFSIZE.GreaterThan64.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFTYPE.badtype.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_OFFSETOF_BITFIELD.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_SIZEOF_BITFIELD.SizeofBitfield.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/tst.BitFieldPromotion.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/tst.SizeofBitField.d109
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.end.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize1.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize2.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize3.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.zerobuf.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.alignring.d81
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.cputime.ksh90
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.dynvarsize.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.fill1.d118
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.fill1.d.out9
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize1.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize2.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize3.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring1.d75
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring2.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring2.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring3.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring3.d.out5
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.smallring.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.switch1.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.switch1.d.out11
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.cpuusage.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.nice.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.priority.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.prsize.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.rssize.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg0.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg0clause.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1to8.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1to8clause.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.caller.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.caller1.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.epid.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.epid1.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.errno.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.errno1.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.execname.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.hpriority.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.id.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.id1.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.ipl.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.ipl1.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.lwpsinfo.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.lwpsinfo1.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.pid.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.pid1.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.psinfo.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.psinfo1.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.tid.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.tid1.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.timestamp.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.vtimestamp.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cg/err.D_NOREG.noreg.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cg/err.baddif.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.aggfun.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.aggtup.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.arrtup.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.body.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.both.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.pred.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.nopred.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.pred.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.predfirst.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.predlast.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.lowfrequency.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.malformedoverflow.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.nonexistentevent.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart1.ksh78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart2.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cputrackfailtostart.ksh77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cputrackterminates.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.toomanyenablings.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.allcpus.ksh107
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.genericevent.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.platformevent.ksh81
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_LOCASSC.NonLocalAssoc.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_LONGINT.LongStruct.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PARMCLASS.BadStorageClass.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_NAME.VoidName.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_TYPE.Dyn.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_VARARGS.VarLenArgs.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_VOID.NonSoleVoid.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_SIGNINT.UnsignedStruct.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_VOIDATTR.ShortVoidDecl.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.arrays.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.basics.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.funcs.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.pointers.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.varargsfuncs.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/badptr.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/countdown.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/counter.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/errorpath.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/hello.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/kstat.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/ksyms.d63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/renormalize.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rtime.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rw.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rwinfo.d74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rwtime.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/specopen.d79
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/truss.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/trussrw.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/userfunc.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_AGGREGATION.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_DBLERROR.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_DYNAMIC.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_PRINCIPAL.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_PRINCIPAL.end.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_SPEC.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_SPECUNAVAIL.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_STKSTROVERFLOW.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/err.D_PDESC_ZERO.InvalidDescription1.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.APIVersion.d37
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.AddSearchPath.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.CoalesceTrace.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ELFGeneration.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.IncludedFilePath.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithFunctions99
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithIDs77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithModules91
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithNames128
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithProviders82
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ShowCompilerCode.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceFunctions115
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceIDs70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceModule114
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceNames129
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceProvider83
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.VerboseStabilityReport.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.AddSearchPath.d.ksh82
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeGiga.d.ksh45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeKilo.d.ksh45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeMega.d.ksh45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeTera.d.ksh45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DataModel32.d.ksh73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DataModel64.d.ksh74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DefineNameWithCPP.d.ksh68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DefineNameWithCPP.d.ksh.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithFunction.d.ksh69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithFunction.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithID.d.ksh54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithID.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithModule.d.ksh54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithModule.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithName.d.ksh54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithName.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithProvider.d.ksh54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithProvider.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithoutW.d.ksh55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ELFGenerationOut.d.ksh73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ELFGenerationWithO.d.ksh74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExitStatus1.d.ksh56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExitStatus2.d.ksh55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExtraneousProbeIds.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidFuncName1.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidFuncName2.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId1.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId2.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId3.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule1.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule2.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule3.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule4.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProbeIdentifier.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider1.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider2.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider3.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider4.d.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc1.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc2.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc3.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc4.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc5.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc6.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc7.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc8.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc9.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID1.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID2.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID3.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID4.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID5.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID6.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID7.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule1.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule2.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule3.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule4.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule5.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule6.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule7.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule8.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName1.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName2.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName3.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName4.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName5.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName6.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName7.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName8.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName9.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider1.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider2.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider3.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider4.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider5.d.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.MultipleInvalidProbeId.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.PreprocessorStatement.d.ksh69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.QuietMode.d.ksh65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.QuietMode.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.TestCompile.d.ksh67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.TestCompile.d.ksh.out0
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.UnDefineNameWithCPP.d.ksh71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroFunctionProbes.d.ksh72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroFunctionProbes.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroModuleProbes.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroModuleProbes.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroNameProbes.d.ksh56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroNameProbes.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProbeIdentfier.d.ksh53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProbesWithoutZ.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProviderProbes.d.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProviderProbes.d.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/err.D_IDENT_UNDEF.timespent.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.end.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.endwithoutbegin.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.multibeginend.d77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.multiend.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/err.D_DECL_IDRED.EnumSameName.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/err.D_UNKNOWN.RepeatIdentifiers.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumEquality.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumSameValue.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumValAssign.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d25
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d25
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv3.ksh34
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv3.ksh.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh35
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_BADADDR.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_DIVZERO.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_UNKNOWN.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.error.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.errorend.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/err.D_PROTO_LEN.noarg.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/err.exitarg1.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/tst.basic1.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/err.D_PDESC_ZERO.notreturn.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.basic.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.functionentry.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.functionreturnvalue.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.ioctlargs.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.offset.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.offsetzero.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.return.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.return0.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.tailcall.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_FUNC_UNDEF.progenyofbad1.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_OP_VFPTR.badop.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.chillbadarg.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.copyoutbadarg.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.mobadarg.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.raisebadarg.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.tolower.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.toupper.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.allocanoarg.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.badbreakpoint.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.chilltoofew.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.chilltoomany.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyoutstrbadarg.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyoutstrtoofew.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyouttoofew.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyouttoomany.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.motoofew.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.motoomany.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtabadarg.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtatoofew.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtatoomany.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.panicbadarg.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.progenyofbad2.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.stopbadarg.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.tolower.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.tolowertoomany.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.toupper.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.touppertoomany.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_STRINGOF_TYPE.badstringof.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_VAR_UNDEF.badvar.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badalloca.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badalloca2.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy1.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy2.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy3.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy4.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy5.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy6.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badchill.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.chillbadarg.ksh69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyout.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyoutbadaddr.ksh71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyoutstrbadaddr.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntoa6badaddr.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntoabadaddr.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntopbadaddr.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntopbadarg.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.badfreopen.ksh102
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.basename.d106
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.basename.d.out163
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.bcopy.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.chill.ksh77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.cleanpath.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.cleanpath.d.out22
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.copyin.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.copyinto.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ddi_pathname.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.default.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.freopen.ksh111
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ftruncate.ksh64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ftruncate.ksh.out11
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.hton.d99
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.index.d226
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.index.d.out1126
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa.d58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa.d.out5
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa6.d95
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa6.d.out8
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntop.d135
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntop.d.out13
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostr.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostr.d.out8
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostrbase.d80
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostrbase.d.out302
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_owned.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_owner.d63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_type_adaptive.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.progenyof.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.rand.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strchr.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strchr.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strjoin.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strjoin.d.out5
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strstr.d89
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strstr.d.out10
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok.d146
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok.d.out5
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok_null.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substr.d231
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substr.d.out254
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substrminate.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substrminate.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.system.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.system.d.out17
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.tolower.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.toupper.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/err.D_ADDROF_LVAL.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/err.D_EMPTY.empty.d34
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/tst.clauses.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/tst.stmts.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/include/tst.includefirst.ksh76
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_DECL_IDRED.redef1.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_DECL_IDRED.redef2.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_IDENT_UNDEF.recur.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.baddef1.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.baddef2.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.badxlate.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineDataAssign.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineExpression.d80
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineKinds.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineKinds.d.out7
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineTypedef.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineWritableAssign.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.c101
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.d.out36
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/get.ipv4remote.pl107
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/get.ipv6remote.pl97
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh.out8
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localsctp.ksh153
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localsctp.ksh.out7
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh135
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh.out7
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh124
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh.out7
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudplite.ksh125
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudplite.ksh.out7
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh81
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh.out3
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotesctp.ksh130
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotesctp.ksh.out7
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh131
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh.out7
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh112
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh.out5
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudplite.ksh113
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudplite.ksh.out5
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6localicmp.ksh83
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6localicmp.ksh.out8
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6remoteicmp.ksh88
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6remoteicmp.ksh.out3
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localsctpstate.ksh175
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localsctpstate.ksh.out13
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh190
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh.out18
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotesctpstate.ksh149
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotesctpstate.ksh.out12
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh172
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh.out15
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/manifest/test.jar-manifest2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestAbort.java158
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestBean.java706
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestClose.java90
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestDrop.java169
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestEnable.java151
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestFunctionLookup.java114
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestGetAggregate.java252
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestMaxConsumers.java97
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestMultiAggPrinta.java144
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestProbeData.java110
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestProbeDescription.java55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestStateMachine.java627
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestStopLock.java67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Abort.ksh39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Abort.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Bean.ksh41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Bean.ksh.out722
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Close.ksh38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Close.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Drop.ksh38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Drop.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Enable.ksh40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Enable.ksh.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.c51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.ksh39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.GetAggregate.ksh36
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MaxConsumers.ksh47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MaxConsumers.ksh.out17
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MultiAggPrinta.ksh38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MultiAggPrinta.ksh.out78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.c93
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.ksh38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.ksh.out50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeDescription.ksh45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeDescription.ksh.out8
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StateMachine.ksh40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StateMachine.ksh.out70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StopLock.ksh39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StopLock.ksh.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.printa.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.printa.d.out47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d179
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d.out218
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d.out13
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.c63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d.out11
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/usdt.d27
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_CHR_NL.char.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_CHR_NULL.char.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_INT_DIGIT.InvalidDigit.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_INT_OFLOW.BigInt.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_STR_NL.string.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brace1.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brace2.d37
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack1.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack2.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack3.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren1.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren2.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren3.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/tst.D_MACRO_OFLOW.ParIntOvflow.d.ksh54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTOREVEN.nodivide.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTOREVEN.notfactor.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORMATCH.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORNSTEPS.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORSMALL.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORTYPE.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORVAL.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHMATCH.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHTYPE.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHVAL.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWMATCH.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWTYPE.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWVAL.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGRANGE.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGTOOBIG.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGTOOBIG.offbyone.d25
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPMATCH.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPTYPE.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPVAL.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.bases.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.bases.d.out177
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.basic.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.basic.d.out25
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negorder.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negorder.d.out148
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negvalue.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negvalue.d.out25
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.normal.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.normal.d.out26
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.range.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.range.d.out29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.steps.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.steps.d.out2033
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.trunc.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.trunc.d.out34
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mdb/tst.dtracedcmd.ksh85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.icmp.ksh79
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.tcp.ksh155
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.udp.ksh74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/err.D_PRAGMA_OPTSET.d34
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.badopt.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.boolopt.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.boolopt.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dofmax.ksh97
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dynopt.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dynopt.d.out31
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.enablerace.ksh89
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.haslam.d63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.include.ksh129
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.macroglob.ksh42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.macroglob.ksh.out22
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.roch.d93
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.schrock.ksh79
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/err.D_PRINTA_AGGKEY.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/err.D_PRINTA_AGGPROTO.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.many.d311
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.many.d.out265
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.same.d37
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.same.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sort.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sort.d.out201
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sortpos.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sortpos.d.out1021
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.tuplecompat.d37
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.tuplecompat.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero.d.out55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero2.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero2.d.out72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero3.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero3.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call.c120
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call.d70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call3.c442
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call3.d91
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_BITFIELD.bitfield.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_TYPE.badtype.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_TYPE.notsou.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_UNKNOWN.OffsetofNULL.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_UNKNOWN.badmemb.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofAlias.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofArith.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofUnion.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.struct.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.struct.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.union.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.union.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/operators/tst.ternary.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/operators/tst.ternary.d.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badlib.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badlib.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badproc1.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_BADPID.badproc2.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_CREATEFAIL.many.d36
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_CREATEFAIL.many.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_FUNC.badfunc.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_FUNC.badfunc.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_LIB.libdash.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_LIB.libdash.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.alldash.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.alldash.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.badname.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.badname.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.globdash.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.globdash.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_OFF.toobig.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_OFF.toobig.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.addprobes.ksh61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.c53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.d75
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.coverage.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.coverage.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.float.c46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.float.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.fork.c63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.fork.d86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.gcc.c66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.gcc.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.killonerror.ksh41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.main.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.manypids.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh.out7
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.probemod.ksh54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex1.ksh93
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex2.ksh131
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex2.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex3.ksh102
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex3.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex4.ksh154
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex4.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret1.c65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret1.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret2.c59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret2.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.vfork.c65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.vfork.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak1.c59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak1.d83
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.c59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.d83
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.available.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.available.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.libmap.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.libmap.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.BadAlign.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.ArrayVar.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.DynamicVar.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.agg.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_DEREF_NONPTR.noptr.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_DEREF_VOID.VoidPointerDeref.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_ARRFUN.ArrayAssignment.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_INCOMPAT.VoidPointerArith.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_LVAL.AddressChange.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_PTR.NonPointerAccess.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_PTR.badpointer.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_SOU.BadPointerAccess.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_SOU.badpointer.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress1.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress2.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress3.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress4.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress5.d84
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer1.d174
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer2.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer3.d72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.GlobalVar.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.IntegerArithmetic1.d72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic1.d58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic2.d72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic3.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerAssignment.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ValidPointer1.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ValidPointer2.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.VoidCast.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.basic1.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.basic2.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGERR.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_DEPEND.main.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_INVAL.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_MALFORM.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_UNUSED.UnusedPragma.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.circlibdep.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.invalidlibdep.ksh57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libchain.ksh58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdep.ksh66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdepfullyconnected.ksh100
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdepsepdir.ksh76
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh106
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal2.ksh102
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal3.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_PRED_SCALAR.NonScalarPred.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_SYNTAX.invalid.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_SYNTAX.operr.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.argsnotcached.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.basics.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.basics.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.complex.d126
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.complex.d.out83
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.predcache.ksh197
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_IDENT_UNDEF.afterprobe.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_PRAGCTL_INVAL.tabdefine.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_SYNTAX.withoutpound.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.defincomp.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefelsenotendif.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefincomp.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefnotendif.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.incompelse.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.mulelse.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifdef.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifdef.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifndef.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifndef.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifnotdef.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifnotdef.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicaland.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicaland.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalandor.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalandor.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalor.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalor.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.muland.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.muland.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.mulor.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.mulor.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.precondi.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.precondi.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.predicatedeclare.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexp.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexp.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpelse.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpelse.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpif.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpif.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpifelse.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpifelse.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.withinprobe.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PRINT_AGG.bad.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PRINT_VOID.bad.d34
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PROTO_LEN.bad.d34
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.array.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.array.d.out23
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.bitfield.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.bitfield.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.dyn.d28
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.enum.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.enum.d.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.primitive.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.primitive.d.out11
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.struct.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.struct.d.out12
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.xlate.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.xlate.d.out8
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badagg.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badfmt.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badval.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_PROTO.bad.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.jstack.d36
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.stack.d36
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.ustack.d36
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.basics.d58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.basics.d.out19
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.def.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.def.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.dynwidth.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.dynwidth.d.out5
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.fmt.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.fmt.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.largeusersym.ksh83
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.many.d76
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.manyval.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.manyval.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.stack.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.tuple.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.tuple.d.out8
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.walltimestamp.ksh62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.walltimestamp.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_AGG_CONV.aggfmt.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_EXTRA.toomany.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_EXTRA.widths.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_FMT.badfmt.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_PROTO.novalue.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_TYPE.aggarg.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_TYPE.recursive.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_PROTO.noprec.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_PROTO.nowidth.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_TYPE.badprec.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_TYPE.badwidth.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PROTO_LEN.toofew.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv1.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv2.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv3.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out26
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.flags.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.flags.d.out7
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.hello.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.hello.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.ints.d87
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.ints.d.out45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.precs.d58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.precs.d.out14
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.print-f.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.print-f.d.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printT.ksh56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printT.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printY.ksh56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printY.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printcont.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printcont.d.out16
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printeE.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printeE.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printgG.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printgG.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.rawfmt.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.rawfmt.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.signs.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.signs.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.uints.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.uints.d.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths.d.out14
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths1.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.wp.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.wp.d.out22
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.fds.ksh91
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.func_access.ksh87
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.getf.ksh98
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.kpriv.ksh112
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.op_access.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.procpriv.ksh138
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.providers.ksh126
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.unpriv_funcs.ksh79
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.probeqtn.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.probestar.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.tickstar.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.assign.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.declare.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.declarein.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.lbraces.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.probespec.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.rbraces.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.recdec.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.basic1.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.check.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.declare.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.declareafter.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.emptyprobe.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragma.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmaaftertab.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmainside.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmaoutside.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.probestar.c47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.probestar.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.create.ksh67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.discard.ksh75
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exec.ksh73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.execfail.ENOENT.ksh84
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.execfail.ksh86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitcore.c36
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitcore.ksh86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitexit.ksh67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitkilled.ksh75
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.signal.ksh85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.sigwait.c78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.sigwait.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.startexit.ksh89
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZERO.profile.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROonens.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROonensec.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROoneus.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROoneusec.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.argtest.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.argtest.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.basic.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.basic.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.func.ksh74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.mod.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilehz.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilehz.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilems.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilems.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilemsec.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilemsec.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilenhz.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilenhz.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilens.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilens.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilensec.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilensec.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profiles.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profiles.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilesec.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilesec.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileus.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileus.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileusec.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileusec.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.sym.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufunc.ksh71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.c78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.ksh66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.ksh.out6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_INVAL.wrongdec4.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.nonprofile.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec1.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec2.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec3.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.basics.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.basics.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginexit.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginprof.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginprof.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probattrs.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probattrs.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probefunc.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probefunc.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probemod.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probemod.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probename.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probename.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probprov.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probprov.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profend.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profend.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profexit.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profexit.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.trace.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.trace.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.twoprof.d58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.twoprof.d.out1
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise1.c47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise1.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise2.c53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise2.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise3.c53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise3.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.aggrate.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.aggrate.d.out101
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.statusrate.d72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.switchrate.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.switchrate.d.out101
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.basename.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.caller.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.cleanpath.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.copyin.d85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.copyin2.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ddi_pathname.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.dirname.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.errno.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.execname.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.gid.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.hton.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.index.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.jailname.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.jid.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.msgdsize.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.msgsize.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.null.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.pid.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ppid.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.progenyof.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.random.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.rw.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.shortstr.d77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stack.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stackdepth.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stddev.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strchr.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strjoin.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strstr.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strtok.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.substr.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ucaller.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.uid.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.unalign.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.uregs.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ustack.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ustackdepth.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.vahole.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.violentdeath.ksh51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.zonename.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_ARR_LOCAL.thisarray.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_CLASS.selfthis.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_CLASS.thisself.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_IDRED.errval.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dec.err.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupgtype.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupltype.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupttype.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_SYNTAX.declare.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.bigglobal.d26
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.biglocal.d26
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.16kglobal.d32
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.16klocal.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.basicvar.d57
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.basicvar.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.localvar.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.misc.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.self.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfarray.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfarray2.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfthis.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.this.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.thisself.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.enqueue.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.oncpu.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.stackdepth.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_MACRO_UNDEF.invalidargs.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_OP_LVAL.rdonly.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_OP_WRITE.usepidmacro.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.concat.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.desc.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.inval.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.pid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.D_MACRO_UNUSED.overflow.ksh80
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.arg0.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.arguments.ksh90
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.assign.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.basic.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.egid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.egid.ksh97
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.euid.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.euid.ksh86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.gid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.gid.ksh86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.pgid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.pid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.ppid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.ppid.ksh86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.projid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.projid.ksh86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.quite.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.sid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.sid.ksh86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.stringmacro.ksh78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.taskid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.taskid.ksh86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.trace.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.uid.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.uid.ksh86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.c49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_IDENT_BADREF.SizeofAssoc.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SIZEOF_TYPE.badstruct.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SIZEOF_TYPE.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SYNTAX.SizeofBadType.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofArray.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofDataTypes.d122
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofExpression.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofNULL.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofStrConst.d42
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofStrConst.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString1.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString1.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString2.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString2.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/bug.1001148.SpecSizeVariations.d87
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations1.d84
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations2.d90
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithBreakPoint.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithChill.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithCopyOut.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithCopyOutStr.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithPanic.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithRaise.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithStop.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_COMM.AggAftCommit.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithAvg.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithCount.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithLquant.d72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithMax.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithMin.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithQuant.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithStddev.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithSum.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_COMM.CommitAftCommit.d82
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_COMM.DisjointCommit.d102
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_DREC.CommitAftDataRec.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_DREC_COMM.DataRecAftCommit.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_DREC_COMM.ExitAfterCommit.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_EXIT_SPEC.ExitAftSpec.d70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_MALFORM.NspecExpr.d77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.HugeNspecValue.d76
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.InvalidSpecSize.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.NegSpecSize.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PROTO_LEN.SpecNoId.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_COMM.SpecAftCommit.d72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_DREC.SpecAftDataRec.d70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_SPEC.SpecAftSpec.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeBufSize.d88
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeNspec.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeSpecSize.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.SpecSizeVariations1.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.SpecSizeVariations2.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.CommitAfterDiscard.d86
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.CommitWithZero.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DataRecAftDiscard.d77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftCommit.d85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftDataRec.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftDiscard.d85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardWithZero.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.ExitAftDiscard.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.NoSpecBuffer.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.NoSpecBuffer.exe30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations1.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations2.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations3.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculateWithRandom.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationCommit.d75
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationDiscard.d74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationID.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationWithZero.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.TwoSpecBuffers.d77
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.negcommit.d37
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.negspec.d37
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.zerosize.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stability/err.D_ATTR_MIN.MinAttributes.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_STACK_PROTO.bad.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_STACK_SIZE.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_FRAMES.bad.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_PROTO.bad.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_STRSIZE.bad.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/tst.default.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stackdepth/tst.default.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop1.c37
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop1.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop2.c37
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop2.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strlen/tst.strlen1.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooLarge.d35
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooSmall.d34
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d.out20
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_ADDROF_VAR.StructPointer.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_COMBO.StructWithoutColon.d74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_COMBO.StructWithoutColon1.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.circular.d66
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.order.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.order2.d108
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.recursive.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.simple.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_VOIDOBJ.baddec.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_PROTO_ARG.DupStructAssoc.d80
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructAssoc.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructDataTypes.d133
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructInside.d124
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.clauselocal.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.clauselocal.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.else.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if2.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d31
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.args.c43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.args.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.openret.ksh75
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post.c45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post.d88
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.d87
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZERO.tick.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROonens.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROonensec.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROoneus.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROoneusec.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickarg0.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickms.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickms.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickmsec.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickmsec.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickns.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickns.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticknsec.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticknsec.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticks.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticks.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticksec.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticksec.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickus.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickus.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickusec.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickusec.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_PROTO_LEN.bad.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_TRACE_AGG.bad.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_TRACE_VOID.bad.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.dyn.d28
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.misc.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.qstring.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.qstring.d.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.string.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_ARG.badsize.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_LEN.toofew.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_ADDR.badaddr.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_ARGS.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_DYNSIZE.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_SIZE.negsize.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_SIZE.zerosize.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.dynsize.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.dynsize.d.out1313
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.rootvp.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_DECL_TYPERED.BadTransDecl.d64
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_OP_INCOMPLETE.NonExistentInput1.d54
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl1.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl3.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl4.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_TYPE_MEMBER.NonExistentInput2.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_INCOMPAT.BadInputType1.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_MEMB.NonExistentOutput2.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_NONE.BadTransDecl6.d72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_REDECL.RepeatTransDecl.d67
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.BadTransDecl8.d58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.BadTransInt.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.NonExistentOutput1.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.CircularTransDecl.d100
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.EmptyTransDecl.d79
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.ForwardTag.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.InputAliasTrans.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.InputIntTrans.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.OutputAliasTrans.d63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.PartialDereferencing.d85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.PartialOutputTransDefn.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.ProcModelTrans.d53
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.RepeatDeclaration.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.SimultaneousTranslators.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.StructureAssignment.d85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh.out14
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh.out14
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransNonPointer.d84
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransOutputPointer.d80
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransPointer.d63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TranslateSelf.d76
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.UnionInputTrans.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.UnionOutputTrans.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_DECL_IDRED.DupTypeDef.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_SYNTAX.BadExistingTypedef.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_SYNTAX.TypedefInClause.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/tst.ChainTypedef.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/tst.TypedefDataAssign.d118
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CAST_INVAL.badcast.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CG_DYN.ResultDynType.d47
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CHR_OFLOW.charconst.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_BADCLASS.bad.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_CHARATTR.badtype3.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_COMBO.badtype4.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_COMBO.badtype5.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENCONST.badeval.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENOFLOW.enoflow.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENOFLOW.enuflow.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_SCOPE.scopeop.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_USELESS.baddec.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_ACT.badcond.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_ARITH.badoperand.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INCOMPAT.badassign.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INT.badbitop.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INT.badshift.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badcond.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badincop.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badlogop.d43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_PROTO_LEN.badcond1.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badenum.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badid.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badstruct.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.badtype1.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.badtype2.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.dupenum.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.dupstruct.d39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_XLATE_REDECL.ResultDynType.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.assignops.d82
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.badshiftops.d49
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.basics.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.basics.d.out16
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.bitops.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.charconstants.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.complex.d74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.condexpr.d61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.const.d29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.constants.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.conv.d109
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.enum.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.intincop.d70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.intops.d70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.inttypes.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.ptrincop.d72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.ptrops.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.relenum.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.relstring.d70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.shiftops.d62
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.stringconstants.d51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.struct.d84
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.typedef.d85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.unaryop.d50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid.d21
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid2.d21
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid3.d21
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidtype.ksh35
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidtype2.ksh36
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.user64mode.ksh90
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.aouttype.c46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.aouttype.ksh45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.c79
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.ksh76
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.ksh.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.libtype.c29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.libtype.ksh46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.linkmap.ksh44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.pidprint.ksh69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.pidprinttarg.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.c72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.ksh69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.ksh.out16
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtypetarg.ksh70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userlandkey.ksh83
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userlandkey.ksh.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userstrings.ksh72
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userstrings.ksh.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_ADDROF_VAR.UnionPointer.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_COMBO.UnionWithoutColon.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_COMBO.UnionWithoutColon1.d68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.circular.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.order.d69
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.recursive.d59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.simple.d58
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_PROTO_ARG.DupUnionAssoc.d80
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionAssoc.d71
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionDataTypes.d132
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionInside.d85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/argmap.d31
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/args.d31
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/forker.d31
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/prov.d3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/prov.h46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.andpid.ksh46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.argmap.c39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.argmap.d65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.args.c39
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.args.d60
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.badguess.ksh84
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.corruptenv.ksh107
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose1.ksh162
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose1.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose2.ksh160
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose2.ksh.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose3.ksh170
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.eliminate.ksh106
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled.ksh96
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled.ksh.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh113
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.entryreturn.ksh118
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.entryreturn.ksh.out10
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.fork.ksh105
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.fork.ksh.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.forker.c51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.forker.ksh55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.guess32.ksh96
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.guess64.ksh100
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.header.ksh85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.include.ksh61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.linkpriv.ksh82
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.linkunpriv.ksh84
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiple.ksh99
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiple.ksh.out5
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiprov.ksh106
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiprov.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.nodtrace.ksh90
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noprobes.ksh59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noreap.ksh128
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noreapring.ksh124
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.onlyenabled.ksh82
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.reap.ksh115
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.reeval.ksh98
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.sameprovmulti.ksh99
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.sameprovmulti.ksh.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static.ksh98
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static.ksh.out5
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static2.ksh108
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static2.ksh.out5
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.user.ksh96
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.user.ksh.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.bigstack.c61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.bigstack.d45
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.depth.ksh110
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.spin.c61
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.spin.ksh139
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.gid.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.nullassign.d94
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ppid.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ucaller.ksh65
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ucaller.ksh.out3
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.uid.d41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.walltimestamp.d55
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/version/tst.1.0.d48
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/arrays/tst.uregsarray.d63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyin.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyinstr.d52
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyout.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyoutstr.d56
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.badinstr.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.badinstr.s41
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.branch.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.branch.s73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.embedded.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.embedded.s68
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.ret.d76
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.ret.s114
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.retlist.ksh50
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.retlist.s51
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/annotated_helper.d32
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/helper_helper.d32
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.c43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.d35
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.d.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.circstack.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.circstack.s43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.c82
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.d.out4
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.basic.ksh77
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.hvmenable.ksh64
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.memenable.ksh65
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.schedargs.ksh121
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.schedenable.ksh74
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/arrays/tst.uregsarray.d85
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/err.D_PROC_ALIGN.misaligned.d40
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/err.D_PROC_ALIGN.misaligned.exe29
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.d70
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.d.out23
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.s81
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.branch.d78
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.branch.s63
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.embedded.d73
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.embedded.s59
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/usdt/tst.tailcall.ksh132
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/annotated_helper.d32
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/helper_helper.d32
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.c43
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.d35
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.d.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.circstack.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.circstack.s44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.c81
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.d44
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.d.out4
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.trapstat.ksh87
-rw-r--r--cddl/contrib/opensolaris/cmd/lockstat/lockstat.1402
-rw-r--r--cddl/contrib/opensolaris/cmd/lockstat/lockstat.c2005
-rw-r--r--cddl/contrib/opensolaris/cmd/lockstat/sym.c293
-rw-r--r--cddl/contrib/opensolaris/cmd/mdb/tools/common/die.c87
-rw-r--r--cddl/contrib/opensolaris/cmd/mdb/tools/common/util.h51
-rw-r--r--cddl/contrib/opensolaris/cmd/plockstat/plockstat.c1022
-rw-r--r--cddl/contrib/opensolaris/cmd/pyzfs/pyzfs.py79
-rw-r--r--cddl/contrib/opensolaris/cmd/stat/common/statcommon.h50
-rw-r--r--cddl/contrib/opensolaris/cmd/stat/common/timestamp.c49
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.8409
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.c5734
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.h33
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb_il.c424
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs-program.8551
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs.83965
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_iter.c497
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_iter.h62
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_main.c7579
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_util.h42
-rw-r--r--cddl/contrib/opensolaris/cmd/zhack/zhack.c535
-rw-r--r--cddl/contrib/opensolaris/cmd/zinject/translate.c492
-rw-r--r--cddl/contrib/opensolaris/cmd/zinject/zinject.c1093
-rw-r--r--cddl/contrib/opensolaris/cmd/zinject/zinject.h70
-rw-r--r--cddl/contrib/opensolaris/cmd/zlook/zlook.c411
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool-features.7672
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool.82480
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_iter.c255
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_main.c6728
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_util.c86
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_util.h73
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_vdev.c1729
-rw-r--r--cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.171
-rw-r--r--cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c644
-rw-r--r--cddl/contrib/opensolaris/cmd/ztest/ztest.c7135
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_create.c1558
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_decl.c184
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_error.c100
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_hash.c178
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_impl.h340
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_labels.c153
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_lookup.c315
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_open.c1045
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_types.c887
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_util.c152
-rw-r--r--cddl/contrib/opensolaris/common/util/strtolctype.h79
-rw-r--r--cddl/contrib/opensolaris/head/atomic.h34
-rw-r--r--cddl/contrib/opensolaris/head/libintl.h97
-rw-r--r--cddl/contrib/opensolaris/head/nlist.h51
-rw-r--r--cddl/contrib/opensolaris/head/note.h55
-rw-r--r--cddl/contrib/opensolaris/head/stdio_ext.h32
-rw-r--r--cddl/contrib/opensolaris/head/storclass.h79
-rw-r--r--cddl/contrib/opensolaris/head/syms.h230
-rw-r--r--cddl/contrib/opensolaris/head/synch.h218
-rw-r--r--cddl/contrib/opensolaris/head/thread.h104
-rw-r--r--cddl/contrib/opensolaris/lib/libcmdutils/common/nicenum.c130
-rw-r--r--cddl/contrib/opensolaris/lib/libcmdutils/libcmdutils.h235
-rw-r--r--cddl/contrib/opensolaris/lib/libctf/common/ctf.51224
-rw-r--r--cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c528
-rw-r--r--cddl/contrib/opensolaris/lib/libctf/common/ctf_subr.c83
-rw-r--r--cddl/contrib/opensolaris/lib/libctf/common/libctf.h60
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/aarch64/dt_isadep.c139
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c188
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/drti.c219
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c2198
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c503
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.h64
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.c177
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.h69
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c2612
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c2140
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c3084
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c1129
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h129
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c526
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c976
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.h66
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c241
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h276
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y885
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c485
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c1052
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.h183
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h756
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.c115
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.h69
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l884
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c1964
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.c111
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.h53
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c493
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c1782
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h66
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c1746
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c1113
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c5192
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h301
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.c187
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.h103
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c999
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h68
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.c157
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.h51
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c564
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c706
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c2083
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h135
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c1262
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h118
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c626
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.h63
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c900
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h118
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.c133
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.h57
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.c309
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.h47
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c298
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h72
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c995
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c516
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_work.c320
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c388
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.h87
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h618
-rwxr-xr-xcddl/contrib/opensolaris/lib/libdtrace/common/mkerrno.sh40
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/mkerrtags.sh59
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/mknames.sh55
-rwxr-xr-xcddl/contrib/opensolaris/lib/libdtrace/common/mksignal.sh40
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/i386/dt_isadep.c520
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/i386/regs.d.in117
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/i386/regs.sed.in82
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/mips/dt_isadep.c75
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c197
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/riscv/dt_isadep.c139
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/sparc/dt_isadep.c338
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/sparc/regs.d120
-rw-r--r--cddl/contrib/opensolaris/lib/libgen/common/gmatch.c175
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c1286
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h196
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c59
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c406
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h391
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h35
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h181
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c135
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c570
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c128
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c122
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c718
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c277
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c70
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c205
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c56
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c300
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h885
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c736
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c121
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h44
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c469
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c5289
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c834
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c452
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h228
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c1917
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c546
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c1713
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c4631
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c3882
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c511
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c1621
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c1164
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h112
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.c189
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.h47
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/kernel.c1238
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h838
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/taskq.c353
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/util.c196
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/zfs.d36
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/__init__.py27
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/allow.py398
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/dataset.py234
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/groupspace.py28
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/holds.py75
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c544
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/table.py70
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/unallow.py27
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/userspace.py246
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/util.py141
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/common/ctf_headers.h72
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/common/list.c228
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/common/list.h58
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/common/memory.c103
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/common/memory.h52
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/common/symbol.c62
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/common/symbol.h44
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/common/utils.c104
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/common/utils.h53
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/alist.c215
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/alist.h57
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/barrier.c92
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/barrier.h62
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/compare.c92
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c1382
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/ctfconvert.c263
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.c1024
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.h90
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h454
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c2019
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/fifo.c153
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/fifo.h54
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/fixup_tdescs.c279
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/hash.c291
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/hash.h59
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/iidesc.c197
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/input.c422
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/merge.c1134
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/output.c775
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/st_parse.c1214
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/stabs.c381
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/stack.c112
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/stack.h53
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/strtab.c258
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/strtab.h69
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/tdata.c487
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/traverse.c226
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/traverse.h71
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/util.c283
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/dump/dump.c1028
1925 files changed, 253771 insertions, 0 deletions
diff --git a/cddl/contrib/opensolaris/OPENSOLARIS.LICENSE b/cddl/contrib/opensolaris/OPENSOLARIS.LICENSE
new file mode 100644
index 000000000000..da23621dc843
--- /dev/null
+++ b/cddl/contrib/opensolaris/OPENSOLARIS.LICENSE
@@ -0,0 +1,384 @@
+Unless otherwise noted, all files in this distribution are released
+under the Common Development and Distribution License (CDDL).
+Exceptions are noted within the associated source files.
+
+--------------------------------------------------------------------
+
+
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0
+
+1. Definitions.
+
+ 1.1. "Contributor" means each individual or entity that creates
+ or contributes to the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Software, prior Modifications used by a Contributor (if any),
+ and the Modifications made by that particular Contributor.
+
+ 1.3. "Covered Software" means (a) the Original Software, or (b)
+ Modifications, or (c) the combination of files containing
+ Original Software with files containing Modifications, in
+ each case including portions thereof.
+
+ 1.4. "Executable" means the Covered Software in any form other
+ than Source Code.
+
+ 1.5. "Initial Developer" means the individual or entity that first
+ makes Original Software available under this License.
+
+ 1.6. "Larger Work" means a work which combines Covered Software or
+ portions thereof with code not governed by the terms of this
+ License.
+
+ 1.7. "License" means this document.
+
+ 1.8. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed
+ herein.
+
+ 1.9. "Modifications" means the Source Code and Executable form of
+ any of the following:
+
+ A. Any file that results from an addition to, deletion from or
+ modification of the contents of a file containing Original
+ Software or previous Modifications;
+
+ B. Any new file that contains any part of the Original
+ Software or previous Modifications; or
+
+ C. Any new file that is contributed or otherwise made
+ available under the terms of this License.
+
+ 1.10. "Original Software" means the Source Code and Executable
+ form of computer software code that is originally released
+ under this License.
+
+ 1.11. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by
+ grantor.
+
+ 1.12. "Source Code" means (a) the common form of computer software
+ code in which modifications are made and (b) associated
+ documentation included in or with such code.
+
+ 1.13. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms
+ of, this License. For legal entities, "You" includes any
+ entity which controls, is controlled by, or is under common
+ control with You. For purposes of this definition,
+ "control" means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by
+ contract or otherwise, or (b) ownership of more than fifty
+ percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants.
+
+ 2.1. The Initial Developer Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and
+ subject to third party intellectual property claims, the Initial
+ Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer, to use,
+ reproduce, modify, display, perform, sublicense and
+ distribute the Original Software (or portions thereof),
+ with or without Modifications, and/or as part of a Larger
+ Work; and
+
+ (b) under Patent Claims infringed by the making, using or
+ selling of Original Software, to make, have made, use,
+ practice, sell, and offer for sale, and/or otherwise
+ dispose of the Original Software (or portions thereof).
+
+ (c) The licenses granted in Sections 2.1(a) and (b) are
+ effective on the date Initial Developer first distributes
+ or otherwise makes the Original Software available to a
+ third party under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: (1) for code that You delete from the Original
+ Software, or (2) for infringements caused by: (i) the
+ modification of the Original Software, or (ii) the
+ combination of the Original Software with other software
+ or devices.
+
+ 2.2. Contributor Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and
+ subject to third party intellectual property claims, each
+ Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor to use, reproduce,
+ modify, display, perform, sublicense and distribute the
+ Modifications created by such Contributor (or portions
+ thereof), either on an unmodified basis, with other
+ Modifications, as Covered Software and/or as part of a
+ Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or
+ selling of Modifications made by that Contributor either
+ alone and/or in combination with its Contributor Version
+ (or portions of such combination), to make, use, sell,
+ offer for sale, have made, and/or otherwise dispose of:
+ (1) Modifications made by that Contributor (or portions
+ thereof); and (2) the combination of Modifications made by
+ that Contributor with its Contributor Version (or portions
+ of such combination).
+
+ (c) The licenses granted in Sections 2.2(a) and 2.2(b) are
+ effective on the date Contributor first distributes or
+ otherwise makes the Modifications available to a third
+ party.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: (1) for any code that Contributor has deleted
+ from the Contributor Version; (2) for infringements caused
+ by: (i) third party modifications of Contributor Version,
+ or (ii) the combination of Modifications made by that
+ Contributor with other software (except as part of the
+ Contributor Version) or other devices; or (3) under Patent
+ Claims infringed by Covered Software in the absence of
+ Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Availability of Source Code.
+
+ Any Covered Software that You distribute or otherwise make
+ available in Executable form must also be made available in Source
+ Code form and that Source Code form must be distributed only under
+ the terms of this License. You must include a copy of this
+ License with every copy of the Source Code form of the Covered
+ Software You distribute or otherwise make available. You must
+ inform recipients of any such Covered Software in Executable form
+ as to how they can obtain such Covered Software in Source Code
+ form in a reasonable manner on or through a medium customarily
+ used for software exchange.
+
+ 3.2. Modifications.
+
+ The Modifications that You create or to which You contribute are
+ governed by the terms of this License. You represent that You
+ believe Your Modifications are Your original creation(s) and/or
+ You have sufficient rights to grant the rights conveyed by this
+ License.
+
+ 3.3. Required Notices.
+
+ You must include a notice in each of Your Modifications that
+ identifies You as the Contributor of the Modification. You may
+ not remove or alter any copyright, patent or trademark notices
+ contained within the Covered Software, or any notices of licensing
+ or any descriptive text giving attribution to any Contributor or
+ the Initial Developer.
+
+ 3.4. Application of Additional Terms.
+
+ You may not offer or impose any terms on any Covered Software in
+ Source Code form that alters or restricts the applicable version
+ of this License or the recipients' rights hereunder. You may
+ choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of
+ Covered Software. However, you may do so only on Your own behalf,
+ and not on behalf of the Initial Developer or any Contributor.
+ You must make it absolutely clear that any such warranty, support,
+ indemnity or liability obligation is offered by You alone, and You
+ hereby agree to indemnify the Initial Developer and every
+ Contributor for any liability incurred by the Initial Developer or
+ such Contributor as a result of warranty, support, indemnity or
+ liability terms You offer.
+
+ 3.5. Distribution of Executable Versions.
+
+ You may distribute the Executable form of the Covered Software
+ under the terms of this License or under the terms of a license of
+ Your choice, which may contain terms different from this License,
+ provided that You are in compliance with the terms of this License
+ and that the license for the Executable form does not attempt to
+ limit or alter the recipient's rights in the Source Code form from
+ the rights set forth in this License. If You distribute the
+ Covered Software in Executable form under a different license, You
+ must make it absolutely clear that any terms which differ from
+ this License are offered by You alone, not by the Initial
+ Developer or Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred
+ by the Initial Developer or such Contributor as a result of any
+ such terms You offer.
+
+ 3.6. Larger Works.
+
+ You may create a Larger Work by combining Covered Software with
+ other code not governed by the terms of this License and
+ distribute the Larger Work as a single product. In such a case,
+ You must make sure the requirements of this License are fulfilled
+ for the Covered Software.
+
+4. Versions of the License.
+
+ 4.1. New Versions.
+
+ Sun Microsystems, Inc. is the initial license steward and may
+ publish revised and/or new versions of this License from time to
+ time. Each version will be given a distinguishing version number.
+ Except as provided in Section 4.3, no one other than the license
+ steward has the right to modify this License.
+
+ 4.2. Effect of New Versions.
+
+ You may always continue to use, distribute or otherwise make the
+ Covered Software available under the terms of the version of the
+ License under which You originally received the Covered Software.
+ If the Initial Developer includes a notice in the Original
+ Software prohibiting it from being distributed or otherwise made
+ available under any subsequent version of the License, You must
+ distribute and make the Covered Software available under the terms
+ of the version of the License under which You originally received
+ the Covered Software. Otherwise, You may also choose to use,
+ distribute or otherwise make the Covered Software available under
+ the terms of any subsequent version of the License published by
+ the license steward.
+
+ 4.3. Modified Versions.
+
+ When You are an Initial Developer and You want to create a new
+ license for Your Original Software, You may create and use a
+ modified version of this License if You: (a) rename the license
+ and remove any references to the name of the license steward
+ (except to note that the license differs from this License); and
+ (b) otherwise make it clear that the license contains terms which
+ differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+ COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
+ BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+ INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+ SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+ PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
+ PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY
+ COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+ INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+ NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
+ WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+ DISCLAIMER.
+
+6. TERMINATION.
+
+ 6.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to
+ cure such breach within 30 days of becoming aware of the breach.
+ Provisions which, by their nature, must remain in effect beyond
+ the termination of this License shall survive.
+
+ 6.2. If You assert a patent infringement claim (excluding
+ declaratory judgment actions) against Initial Developer or a
+ Contributor (the Initial Developer or Contributor against whom You
+ assert such claim is referred to as "Participant") alleging that
+ the Participant Software (meaning the Contributor Version where
+ the Participant is a Contributor or the Original Software where
+ the Participant is the Initial Developer) directly or indirectly
+ infringes any patent, then any and all rights granted directly or
+ indirectly to You by such Participant, the Initial Developer (if
+ the Initial Developer is not the Participant) and all Contributors
+ under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
+ notice from Participant terminate prospectively and automatically
+ at the expiration of such 60 day notice period, unless if within
+ such 60 day period You withdraw Your claim with respect to the
+ Participant Software against such Participant either unilaterally
+ or pursuant to a written agreement with Participant.
+
+ 6.3. In the event of termination under Sections 6.1 or 6.2 above,
+ all end user licenses that have been validly granted by You or any
+ distributor hereunder prior to termination (excluding licenses
+ granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+ INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+ COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+ LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+ CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+ LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+ STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+ INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+ APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO
+ NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+ APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+ The Covered Software is a "commercial item," as that term is
+ defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
+ computer software" (as that term is defined at 48
+ C.F.R. 252.227-7014(a)(1)) and "commercial computer software
+ documentation" as such terms are used in 48 C.F.R. 12.212
+ (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48
+ C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+ U.S. Government End Users acquire Covered Software with only those
+ rights set forth herein. This U.S. Government Rights clause is in
+ lieu of, and supersedes, any other FAR, DFAR, or other clause or
+ provision that addresses Government rights in computer software
+ under this License.
+
+9. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed
+ by the law of the jurisdiction specified in a notice contained
+ within the Original Software (except to the extent applicable law,
+ if any, provides otherwise), excluding such jurisdiction's
+ conflict-of-law provisions. Any litigation relating to this
+ License shall be subject to the jurisdiction of the courts located
+ in the jurisdiction and venue specified in a notice contained
+ within the Original Software, with the losing party responsible
+ for costs, including, without limitation, court costs and
+ reasonable attorneys' fees and expenses. The application of the
+ United Nations Convention on Contracts for the International Sale
+ of Goods is expressly excluded. Any law or regulation which
+ provides that the language of a contract shall be construed
+ against the drafter shall not apply to this License. You agree
+ that You alone are responsible for compliance with the United
+ States export administration regulations (and the export control
+ laws and regulation of any other countries) when You use,
+ distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or
+ indirectly, out of its utilization of rights under this License
+ and You agree to work with Initial Developer and Contributors to
+ distribute such responsibility on an equitable basis. Nothing
+ herein is intended or shall be deemed to constitute any admission
+ of liability.
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
new file mode 100644
index 000000000000..8f651bc39f03
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
@@ -0,0 +1,785 @@
+.\" 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 (c) 2006, Sun Microsystems, Inc. All Rights Reserved.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2018
+.Dt DTRACE 1
+.Os
+.Sh NAME
+.Nm dtrace
+.Nd dynamic tracing compiler and tracing utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl 32 | Fl 64
+.Op Fl aACeFGhHlqSvVwZ
+.Op Fl b Ar bufsz
+.Op Fl c Ar cmd
+.Op Fl D Ar name Op Ns = Ns value
+.Op Fl I Ar path
+.Op Fl L Ar path
+.Op Fl o Ar output
+.Op Fl s Ar script
+.Op Fl U Ar name
+.Op Fl x Ar arg Op Ns = Ns value
+.Op Fl X Cm a | c | s | t
+.Op Fl p Ar pid
+.Op Fl P Ar provider Oo Oo Ar predicate Oc Ar action Oc
+.Op Fl m Oo Ar provider : Oc Ar module Oo Oo Ar predicate Oc Ar action Oc
+.Op Fl f Oo Oo Ar provider : Oc Ar module : Oc Ar function Oo Oo Ar predicate \
+ Oc Ar action Oc
+.Op Fl n Oo Oo Oo Ar provider : Oc Ar module : Oc Ar function : Oc Ar name \
+ Oo Oo Ar predicate Oc Ar action Oc
+.Op Fl i Ar probe-id Oo Oo Ar predicate Oc Ar action Oc
+.Sh DESCRIPTION
+DTrace is a comprehensive dynamic tracing framework ported from Solaris.
+DTrace provides a powerful infrastructure that permits administrators,
+developers, and service personnel to concisely answer arbitrary questions about
+the behavior of the operating system and user programs.
+.Pp
+The
+.Nm
+command provides a generic interface to the essential services provided by the
+DTrace facility, including:
+.Bl -bullet -offset indent
+.It
+Options that list the set of probes and providers currently published by DTrace
+.It
+Options that enable probes directly using any of the probe description
+specifiers (provider, module, function, name)
+.It
+Options that run the D compiler and compile one or more D program files or
+programs written directly on the command line
+.It
+Options that generate anonymous tracing programs
+.It
+Options that generate program stability reports
+.It
+Options that modify DTrace tracing and buffering behavior and enable
+additional D compiler features
+.El
+.Pp
+You can use
+.Nm
+to create D scripts by using it in a shebang declaration to create an
+interpreter file.
+You can also use
+.Nm
+to attempt to compile D programs and determine their properties without
+actually enabling traces using the
+.Fl e
+option.
+.Sh OPTIONS
+The arguments accepted by the
+.Fl P ,
+.Fl m ,
+.Fl f ,
+.Fl n ,
+and
+.Fl i
+options can include an optional D language
+.Ar predicate
+enclosed in slashes and an optional D language
+.Ar action
+statement list enclosed in braces.
+D program code specified on the command line must be appropriately quoted to
+avoid interpretation of meta-characters by the shell.
+.Pp
+The following options are supported:
+.Bl -tag -width indent
+.It Fl 32 | Fl 64
+The D compiler produces programs using the native data model of the operating
+system kernel.
+If the
+.Fl 32
+option is specified,
+.Nm
+forces the D compiler to compile a D program using the 32-bit data model.
+If the
+.Fl 64
+option is specified,
+.Nm
+forces the D compiler to compile a D program using the 64-bit data model.
+These options are typically not required as
+.Nm
+selects the native data model as the default.
+The data model affects the sizes of integer types and other language properties.
+D programs compiled for either data model can be executed on both 32-bit and
+64-bit kernels.
+The
+.Fl 32
+and
+.Fl 64
+options also determine the
+.Xr elf 5
+file format (ELF32 or ELF64) produced by the
+.Fl G
+option.
+.It Fl a
+Claim anonymous tracing state and display the traced data.
+You can combine the
+.Fl a
+option with the
+.Fl e
+option to force
+.Nm
+to exit immediately after consuming the anonymous tracing state rather than
+continuing to wait for new data.
+.It Fl A
+Generate directives for anonymous tracing and write them to
+.Pa /boot/dtrace.dof .
+This option constructs a set of dtrace configuration file directives to enable
+the specified probes for anonymous tracing and then exits.
+By default,
+.Nm
+attempts to store the directives to the file
+.Pa /boot/dtrace.dof .
+This behavior can be modified using the
+.Fl o
+option to specify an alternate output file.
+.It Fl b Ar bufsz
+Set the principal trace buffer size to
+.Ar bufsz .
+The trace buffer size can include any of the size suffixes k, m, g, or t.
+If the buffer space cannot be allocated,
+.Nm dtrace
+attempts to reduce the buffer size or exit depending on the setting of the
+bufresize property.
+.It Fl c Ar cmd
+Run the specified command
+.Ar cmd
+and exit upon its completion.
+If more than one
+.Fl c
+option is present on the command line,
+.Nm dtrace
+exits when all commands have exited, reporting the exit status for each child
+process as it terminates.
+The process ID of the first command is made available to any D programs
+specified on the command line or using the
+.Fl s
+option through the
+.Li $target
+macro variable.
+.It Fl C
+Run the C preprocessor
+.Xr cpp 1
+over D programs before compiling them.
+You can pass options to the C preprocessor using the
+.Fl D ,
+.Fl U ,
+.Fl I ,
+and
+.Fl H
+options.
+You can select the degree of C standard conformance if you use the
+.Fl X
+option.
+For a description of the set of tokens defined by the D compiler when invoking
+the C preprocessor, see
+.Fl X .
+.It Fl D Ar name Op Ns = Ns value
+Define
+.Ar name
+when invoking
+.Xr cpp 1
+(enabled using the
+.Fl C
+option).
+If you specify an additional
+.Ar value ,
+the name is assigned the corresponding value.
+This option passes the
+.Fl D
+option to each
+.Xr cpp 1
+invocation.
+.It Fl e
+Exit after compiling any requests and consuming anonymous tracing state
+.Fl ( a
+option) but prior to enabling any probes.
+You can combine this option with the
+.Fl a
+option to print anonymous tracing data and exit.
+You can also combine this option with D compiler options.
+This combination verifies that the programs compile without actually executing
+them and enabling the corresponding instrumentation.
+.It Fl f Oo Oo Ar provider : Oc Ar module : Oc Ar function Oo Oo Ar predicate \
+ Oc Ar action Oc
+Specify function name to trace or list
+.Fl ( l
+option).
+The corresponding argument can include any of the probe description forms
+.Ar provider:module:function ,
+.Ar module:function ,
+or
+.Ar function .
+Unspecified probe description fields are left blank and match any probes
+regardless of the values in those fields.
+If no qualifiers other than
+.Ar function
+are specified in the description, all probes with the corresponding
+.Ar function
+are matched.
+The
+.Fl f
+argument can be suffixed with an optional D probe clause.
+You can specify more than one
+.Fl f
+option on the command line at a time.
+.It Fl F
+Coalesce trace output by identifying function entry and return.
+Function entry probe reports are indented and their output is prefixed with
+.Ql -> .
+Function return probe reports are unindented and their output is prefixed with
+.Ql <- .
+System call entry probe reports are indented and their output is prefixed with
+.Ql => .
+System call return probe reports are unindented and their output is prefixed
+with
+.Ql <= .
+.It Fl G
+Generate an ELF file containing an embedded DTrace program.
+The DTrace probes specified in the program are saved inside of a relocatable ELF
+object which can be linked into another program.
+If the
+.Fl o
+option is present, the ELF file is saved using the pathname specified as the
+argument for this operand.
+If the
+.Fl o
+option is not present and the DTrace program is contained with a file whose name
+is
+.Ar filename.d ,
+then the ELF file is saved using the name
+.Ar filename.o .
+Otherwise the ELF file is saved using the name d.out.
+.It Fl h
+Generate a header file containing macros that correspond to probes in the
+specified provider definitions.
+This option should be used to generate a header file that is included by other
+source files for later use with the
+.Fl G
+option.
+If the
+.Fl o
+option is present, the header file is saved using the pathname specified as the
+argument for that option.
+If the
+.Fl o
+option is not present and the DTrace program is contained within a file whose
+name is
+.Ar filename.d ,
+then the header file is saved using the name
+.Ar filename.h .
+.It Fl H
+Print the pathnames of included files when invoking
+.Xr cpp 1
+(enabled using the
+.Fl C
+option).
+This option passes the
+.Fl H
+option to each
+.Xr cpp 1
+invocation, causing it to display the list of pathnames, one for each line, to
+standard error.
+.It Fl i Ar probe-id Op Oo Ar predicate Oc Ar action
+Specify probe identifier
+.Ar ( probe-id )
+to trace or list
+.Ar ( l
+option).
+You can specify probe IDs using decimal integers as shown by `dtrace -l`.
+The
+.Fl i
+argument can be suffixed with an optional D probe clause.
+You can specify more than one
+.Fl i
+option at a time.
+.It Fl I Ar path
+Add the specified directory
+.Ar path
+to the search path for #include files when invoking
+.Xr cpp 1
+(enabled using the
+.Fl C
+option).
+This option passes the
+.Fl I
+option to each
+.Xr cpp 1
+invocation.
+The specified
+.Ar path
+is inserted into the search path ahead of the default directory list.
+.It Fl l
+List probes instead of enabling them.
+If the
+.Fl l
+option is specified,
+.Nm
+produces a report of the probes matching the descriptions given using the
+.Fl P , m , f , n , i ,
+and
+.Fl s
+options.
+If none of these options are specified, this option lists all probes.
+.It Fl L Ar path
+Add the specified directory
+.Ar path
+to the search path for DTrace libraries.
+DTrace libraries are used to contain common definitions that can be used when
+writing D programs.
+The specified
+.Ar path
+is added after the default library search path.
+.It Fl m Oo Ar provider : Oc Ar module Oo Oo Ar predicate Oc Ar action Oc
+Specify module name to trace or list
+.Fl ( l
+option).
+The corresponding argument can include any of the probe description forms
+.Ar provider:module
+or
+.Ar module .
+Unspecified probe description fields are left blank and match any probes
+regardless of the values in those fields.
+If no qualifiers other than
+.Ar module
+are specified in the description, all probes with a corresponding
+.Ar module
+are matched.
+The
+.Fl m
+argument can be suffixed with an optional D probe clause.
+More than one
+.Fl m
+option can be specified on the command line at a time.
+.It Fl n Oo Oo Oo Ar provider : Oc Ar module : Oc Ar function : Oc Ar name \
+ Oo Oo Ar predicate Oc Ar action Oc
+Specify probe name to trace or list
+.Fl ( l
+option).
+The corresponding argument can include any of the probe description forms
+.Ar provider:module:function:name , module:function:name , function:name ,
+or
+.Ar name .
+Unspecified probe description fields are left blank and match any probes
+regardless of the values in those fields.
+If no qualifiers other than
+.Ar name
+are specified in the description, all probes with a corresponding
+.Ar name
+are matched.
+The
+.Fl n
+argument can be suffixed with an optional D probe clause.
+More than one
+.Fl n
+option can be specified on the command line at a time.
+.It Fl o Ar output
+Specify the
+.Ar output
+file for the
+.Fl A , G ,
+and
+.Fl l
+options, or for the traced data itself.
+If the
+.Fl A
+option is present and
+.Fl o
+is not present, the default output file is
+.Pa /boot/dtrace.dof .
+If the
+.Fl G
+option is present and the
+.Fl s
+option's argument is of the form
+.Ar filename.d
+and
+.Fl o
+is not present, the default output file is
+.Ar filename.o .
+Otherwise the default output file is
+.Ar d.out .
+.It Fl p Ar pid
+Grab the specified process-ID
+.Ar pid ,
+cache its symbol tables, and exit upon its completion.
+If more than one
+.Fl p
+option is present on the command line,
+.Nm
+exits when all commands have exited, reporting the exit status for each process
+as it terminates.
+The first process-ID is made available to any D programs specified on the
+command line or using the
+.Fl s
+option through the
+.Li $target
+macro variable.
+.It Fl P Ar provider Oo Oo Ar predicate Oc Ar action Oc
+Specify provider name to trace or list
+.Fl ( l
+option).
+The remaining probe description fields module, function, and name are left
+blank and match any probes regardless of the values in those fields.
+The
+.Fl P
+argument can be suffixed with an optional D probe clause.
+You can specify more than one
+.Fl P
+option on the command line at a time.
+.It Fl q
+Set quiet mode.
+.Nm
+suppresses messages such as the number of probes matched by the specified
+options and D programs and does not print column headers, the CPU ID, the probe
+ID, or insert newlines into the output.
+Only data traced and formatted by D program statements such as
+.Ql dtrace()
+and
+.Ql printf()
+is displayed to standard output.
+.It Fl s Ar script
+Compile the specified D program source file.
+If the
+.Fl e
+option is present, the program is compiled but instrumentation is not enabled.
+If the
+.Fl l
+option is present, the program is compiled and the set of probes matched by it
+is listed, but instrumentation is not enabled.
+If none of
+.Fl e , l , G ,
+or
+.Fl A
+are present, the instrumentation specified by the D program is enabled and
+tracing begins.
+.It Fl S
+Show D compiler intermediate code.
+The D compiler produces a report of the intermediate code generated for each D
+program to standard error.
+.It Fl U Ar name
+Undefine the specified
+.Ar name
+when invoking
+.Xr cpp 1
+(enabled using the
+.Fl C
+option).
+This option passes the
+.Fl U
+option to each
+.Xr cpp 1
+invocation.
+.It Fl v
+Set verbose mode.
+If the
+.Fl v
+option is specified,
+.Nm
+produces a program stability report showing the minimum interface stability and
+dependency level for the specified D programs.
+.It Fl V
+Report the highest D programming interface version supported by
+.Nm .
+The version information is printed to standard output and the
+.Nm
+command exits.
+.It Fl w
+Permit destructive actions in D programs specified using the
+.Fl s , P , m , f , n ,
+or
+.Fl i
+options.
+If the
+.Fl w
+option is not specified,
+.Nm
+does not permit the compilation or enabling of a D program that contains
+destructive actions.
+.It Fl x Ar arg Op Ns = Ns value
+Enable or modify a DTrace runtime option or D compiler option.
+Boolean options are enabled by specifying their name.
+Options with values are set by separating the option name and value with an
+equals sign (=).
+.Pp
+A
+.Ar size
+argument may be suffixed with one of
+.Cm K ,
+.Cm M ,
+.Cm G
+or
+.Cm T
+(either upper or lower case) to indicate a multiple of
+Kilobytes, Megabytes, Gigabytes or Terabytes
+respectively.
+.Pp
+A
+.Ar time
+argument may be suffixed with one of
+.Cm ns ,
+.Cm nsec ,
+.Cm us ,
+.Cm usec ,
+.Cm ms ,
+.Cm msec ,
+.Cm s ,
+.Cm sec ,
+.Cm m ,
+.Cm min ,
+.Cm h ,
+.Cm hour ,
+.Cm d ,
+.Cm day ,
+.Cm hz .
+If no suffix is specified
+.Cm hz
+will be used as the unit.
+.Bl -tag -width indent
+.It Sy aggrate Ns = Ns Ar time
+Rate of aggregation reading.
+.It Sy aggsize Ns = Ns Ar size
+Size of the aggregation buffer.
+.It Sy bufpolicy Ns = Ns Cm fill Ns | Ns Cm switch Ns | Ns Cm ring
+Specifies the buffer policy for the principal buffer.
+.It Sy bufresize Ns = Ns Cm auto Ns | Ns Cm manual
+Buffer resizing policy.
+.It Sy bufsize Ns = Ns Ar size
+Size of the per-CPU principal buffer.
+Same as the
+.Fl b
+flag.
+.It Sy cleanrate Ns = Ns Ar time
+Cleaning rate.
+Must be specified in number-per-second with the
+.Dq Li hz
+suffix.
+.It Sy cpu Ns = Ns Ar scalar
+Specifies the CPU on which to enable tracing.
+.It Sy defaultargs
+Allow references to unspecified macro arguments.
+.It Sy destructive
+Allow destructive actions.
+Same as the
+.Fl w
+flag.
+.It Sy dynvarsize Ns = Ns Ar size
+Size of the dynamic variable space.
+.It Sy flowindent
+Turn on flow indentation.
+Same as the
+.Fl F
+flag.
+.It Sy grabanon
+Claim anonymous state.
+Same as the
+.Fl a
+flag.
+.It Sy jstackframes Ns = Ns Ar scalar
+Number of default stack frames for
+.Fn jstack .
+.It Sy jstackstrsize Ns = Ns Ar scalar
+Default string space size for
+.Fn jstack .
+.It Sy nspec Ns = Ns Ar scalar
+Number of speculations.
+.It Sy quiet
+Set quiet mode.
+Same as the
+.Fl q
+flag.
+.It Sy specsize Ns = Ns Ar size
+Size of the speculation buffer.
+.It Sy strsize Ns = Ns Ar size
+Maximum size of strings.
+.It Sy stackframes Ns = Ns Ar scalar
+Maximum number of kernelspace stack frames to unwind when executing the
+.Fn stack
+action.
+.It Sy stackindent Ns = Ns Ar scalar
+Number of whitespace characters to use when indenting
+.Fn stack
+and
+.Fn ustack
+output.
+.It Sy statusrate Ns = Ns Ar time
+Rate of status checking.
+.It Sy switchrate Ns = Ns Ar time
+Rate of buffer switching.
+.It Sy ustackframes Ns = Ns Ar scalar
+Maximum number of userspace stack frames to unwind when executing the
+.Fn ustack
+action.
+.El
+.It Fl X Cm a | c | s | t
+Specify the degree of conformance to the ISO C standard that should be selected
+when invoking
+.Xr cpp 1
+(enabled using the
+.Fl C
+option).
+The
+.Fl X
+option argument affects the value and presence of the __STDC__ macro depending
+upon the value of the argument letter.
+.sp
+The
+.Fl X
+option supports the following arguments:
+.Bl -tag -width indent
+.It a
+Default.
+ISO C plus K&R compatibility extensions, with semantic changes required by ISO
+C.
+This is the default mode if
+.Fl X
+is not specified.
+The predefined macro __STDC__ has a value of 0 when
+.Xr cpp 1
+is invoked in conjunction with the
+.Fl Xa
+option.
+.It c
+Conformance.
+Strictly conformant ISO C, without K&R C compatibility extensions.
+The predefined macro __STDC__ has a value of 1 when
+.Xr cpp 1
+is invoked in conjunction with the
+.Fl \&Xc
+option.
+.It s
+K&R C only.
+The macro __STDC__ is not defined when
+.Xr cpp 1
+is invoked in conjunction with the
+.Fl Xs
+option.
+.It t
+Transition.
+ISO C plus K&R C compatibility extensions, without semantic changes required by
+ISO C.
+The predefined macro __STDC__ has a value of 0 when
+.Xr cpp 1
+is invoked in conjunction with the
+.Fl Xt
+option.
+.El
+.Pp
+As the
+.Fl X
+option only affects how the D compiler invokes the C preprocessor, the
+.Fl Xa
+and
+.Fl Xt
+options are equivalent from the perspective of D and both are provided only to
+ease re-use of settings from a C build environment.
+.Pp
+Regardless of the
+.Fl X
+mode, the following additional C preprocessor definitions are always specified
+and valid in all modes:
+.Bl -bullet -offset indent
+.It
+__sun
+.It
+__unix
+.It
+__SVR4
+.It
+__sparc (on SPARC systems only)
+.It
+__sparcv9 (on SPARC systems only when 64-bit programs are compiled)
+.It
+__i386 (on x86 systems only when 32-bit programs are compiled)
+.It
+__amd64 (on x86 systems only when 64-bit programs are compiled)
+.It
+__`uname -s`_`uname -r` (for example,
+.Ql FreeBSD_9.2-RELEASE .
+.It
+__SUNW_D=1
+.It
+.No __SUNW_D_VERSION=0x Ns Ar MMmmmuuu
+.Pp
+Where
+.Ar MM
+is the major release value in hexadecimal,
+.Ar mmm
+is the minor release value in hexadecimal, and
+.Ar uuu
+is the micro release value in hexadecimal.
+.El
+.It Fl Z
+Permit probe descriptions that match zero probes.
+If the
+.Fl Z
+option is not specified,
+.Nm
+reports an error and exits if any probe descriptions specified in D program
+files
+.Fl ( s
+option) or on the command line
+.Fl ( P , m , f , n ,
+or
+.Fl i
+options) contain descriptions that do not match any known probes.
+.El
+.Sh OPERANDS
+You can specify zero or more additional arguments on the
+.Nm
+command line to define a set of macro variables and so forth).
+The additional arguments can be used in D programs specified using the
+.Fl s
+option or on the command line.
+.Sh FILES
+.Bl -tag -width /boot/dtrace.dof -compact
+.It Pa /boot/dtrace.dof
+File for anonymous tracing directives.
+.El
+.Sh EXIT STATUS
+The following exit statuses are returned:
+.Bl -tag -width indent
+.It 0
+Successful completion.
+.Pp
+For D program requests, an exit status of 0 indicates that programs were
+successfully compiled, probes were successfully enabled, or anonymous state
+was successfully retrieved.
+.Nm
+returns 0 even if the specified tracing requests encountered errors or drops.
+.It 1
+An error occurred.
+.Pp
+For D program requests, an exit status of 1 indicates that program compilation
+failed or that the specified request could not be satisfied.
+.It 2
+Invalid command line options or arguments were specified.
+.El
+.Sh SEE ALSO
+.Xr cpp 1 ,
+.Xr elf 5 ,
+.Xr SDT 9
+.Rs
+.%T Solaris Dynamic Tracing Guide
+.Re
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c
new file mode 100644
index 000000000000..393a7217df25
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c
@@ -0,0 +1,2012 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <dtrace.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <libgen.h>
+#ifdef illumos
+#include <libproc.h>
+#endif
+#ifdef __FreeBSD__
+#include <spawn.h>
+#endif
+
+typedef struct dtrace_cmd {
+ void (*dc_func)(struct dtrace_cmd *); /* function to compile arg */
+ dtrace_probespec_t dc_spec; /* probe specifier context */
+ char *dc_arg; /* argument from main argv */
+ const char *dc_name; /* name for error messages */
+ const char *dc_desc; /* desc for error messages */
+ dtrace_prog_t *dc_prog; /* program compiled from arg */
+ char dc_ofile[PATH_MAX]; /* derived output file name */
+} dtrace_cmd_t;
+
+#define DMODE_VERS 0 /* display version information and exit (-V) */
+#define DMODE_EXEC 1 /* compile program for enabling (-a/e/E) */
+#define DMODE_ANON 2 /* compile program for anonymous tracing (-A) */
+#define DMODE_LINK 3 /* compile program for linking with ELF (-G) */
+#define DMODE_LIST 4 /* compile program and list probes (-l) */
+#define DMODE_HEADER 5 /* compile program for headergen (-h) */
+
+#define E_SUCCESS 0
+#define E_ERROR 1
+#define E_USAGE 2
+
+static const char DTRACE_OPTSTR[] =
+ "3:6:aAb:Bc:CD:ef:FGhHi:I:lL:m:n:o:p:P:qs:SU:vVwx:X:Z";
+
+static char **g_argv;
+static int g_argc;
+static char **g_objv;
+static int g_objc;
+static dtrace_cmd_t *g_cmdv;
+static int g_cmdc;
+static struct ps_prochandle **g_psv;
+static int g_psc;
+static int g_pslive;
+static char *g_pname;
+static int g_quiet;
+static int g_flowindent;
+static int g_intr;
+static int g_impatient;
+static int g_newline;
+#ifdef __FreeBSD__
+static int g_siginfo;
+#endif
+static int g_total;
+static int g_cflags;
+static int g_oflags;
+static int g_verbose;
+static int g_exec = 1;
+static int g_mode = DMODE_EXEC;
+static int g_status = E_SUCCESS;
+static int g_grabanon = 0;
+static const char *g_ofile = NULL;
+static FILE *g_ofp;
+static dtrace_hdl_t *g_dtp;
+#ifdef illumos
+static char *g_etcfile = "/etc/system";
+static const char *g_etcbegin = "* vvvv Added by DTrace";
+static const char *g_etcend = "* ^^^^ Added by DTrace";
+
+static const char *g_etc[] = {
+"*",
+"* The following forceload directives were added by dtrace(1M) to allow for",
+"* tracing during boot. If these directives are removed, the system will",
+"* continue to function, but tracing will not occur during boot as desired.",
+"* To remove these directives (and this block comment) automatically, run",
+"* \"dtrace -A\" without additional arguments. See the \"Anonymous Tracing\"",
+"* chapter of the Solaris Dynamic Tracing Guide for details.",
+"*",
+NULL };
+#endif
+
+static int
+usage(FILE *fp)
+{
+ static const char predact[] = "[[ predicate ] action ]";
+
+ (void) fprintf(fp, "Usage: %s [-32|-64] [-aACeFGhHlqSvVwZ] "
+ "[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] "
+ "[-o output] [-p pid] [-s script] [-U name]\n\t"
+ "[-x opt[=val]] [-X a|c|s|t]\n\n"
+ "\t[-P provider %s]\n"
+ "\t[-m [ provider: ] module %s]\n"
+ "\t[-f [[ provider: ] module: ] func %s]\n"
+ "\t[-n [[[ provider: ] module: ] func: ] name %s]\n"
+ "\t[-i probe-id %s] [ args ... ]\n\n", g_pname,
+ predact, predact, predact, predact, predact);
+
+ (void) fprintf(fp, "\tpredicate -> '/' D-expression '/'\n");
+ (void) fprintf(fp, "\t action -> '{' D-statements '}'\n");
+
+ (void) fprintf(fp, "\n"
+ "\t-32 generate 32-bit D programs and ELF files\n"
+ "\t-64 generate 64-bit D programs and ELF files\n\n"
+ "\t-a claim anonymous tracing state\n"
+ "\t-A generate driver.conf(4) directives for anonymous tracing\n"
+ "\t-b set trace buffer size\n"
+ "\t-c run specified command and exit upon its completion\n"
+ "\t-C run cpp(1) preprocessor on script files\n"
+ "\t-D define symbol when invoking preprocessor\n"
+ "\t-e exit after compiling request but prior to enabling probes\n"
+ "\t-f enable or list probes matching the specified function name\n"
+ "\t-F coalesce trace output by function\n"
+ "\t-G generate an ELF file containing embedded dtrace program\n"
+ "\t-h generate a header file with definitions for static probes\n"
+ "\t-H print included files when invoking preprocessor\n"
+ "\t-i enable or list probes matching the specified probe id\n"
+ "\t-I add include directory to preprocessor search path\n"
+ "\t-l list probes matching specified criteria\n"
+ "\t-L add library directory to library search path\n"
+ "\t-m enable or list probes matching the specified module name\n"
+ "\t-n enable or list probes matching the specified probe name\n"
+ "\t-o set output file\n"
+ "\t-p grab specified process-ID and cache its symbol tables\n"
+ "\t-P enable or list probes matching the specified provider name\n"
+ "\t-q set quiet mode (only output explicitly traced data)\n"
+ "\t-s enable or list probes according to the specified D script\n"
+ "\t-S print D compiler intermediate code\n"
+ "\t-U undefine symbol when invoking preprocessor\n"
+ "\t-v set verbose mode (report stability attributes, arguments)\n"
+ "\t-V report DTrace API version\n"
+ "\t-w permit destructive actions\n"
+ "\t-x enable or modify compiler and tracing options\n"
+ "\t-X specify ISO C conformance settings for preprocessor\n"
+ "\t-Z permit probe descriptions that match zero probes\n");
+
+ return (E_USAGE);
+}
+
+static void
+verror(const char *fmt, va_list ap)
+{
+ int error = errno;
+
+ (void) fprintf(stderr, "%s: ", g_pname);
+ (void) vfprintf(stderr, fmt, ap);
+
+ if (fmt[strlen(fmt) - 1] != '\n')
+ (void) fprintf(stderr, ": %s\n", strerror(error));
+}
+
+/*PRINTFLIKE1*/
+static void
+fatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ verror(fmt, ap);
+ va_end(ap);
+
+ /*
+ * Close the DTrace handle to ensure that any controlled processes are
+ * correctly restored and continued.
+ */
+ if (g_dtp)
+ dtrace_close(g_dtp);
+
+ exit(E_ERROR);
+}
+
+/*PRINTFLIKE1*/
+static void
+dfatal(const char *fmt, ...)
+{
+#if !defined(illumos) && defined(NEED_ERRLOC)
+ char *p_errfile = NULL;
+ int errline = 0;
+#endif
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ (void) fprintf(stderr, "%s: ", g_pname);
+ if (fmt != NULL)
+ (void) vfprintf(stderr, fmt, ap);
+
+ va_end(ap);
+
+ if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') {
+ (void) fprintf(stderr, ": %s\n",
+ dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
+ } else if (fmt == NULL) {
+ (void) fprintf(stderr, "%s\n",
+ dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
+ }
+#if !defined(illumos) && defined(NEED_ERRLOC)
+ dt_get_errloc(g_dtp, &p_errfile, &errline);
+ if (p_errfile != NULL)
+ printf("File '%s', line %d\n", p_errfile, errline);
+#endif
+
+ /*
+ * Close the DTrace handle to ensure that any controlled processes are
+ * correctly restored and continued.
+ */
+ dtrace_close(g_dtp);
+
+ exit(E_ERROR);
+}
+
+/*PRINTFLIKE1*/
+static void
+error(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ verror(fmt, ap);
+ va_end(ap);
+}
+
+/*PRINTFLIKE1*/
+static void
+notice(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (g_quiet)
+ return; /* -q or quiet pragma suppresses notice()s */
+
+ va_start(ap, fmt);
+ verror(fmt, ap);
+ va_end(ap);
+}
+
+/*PRINTFLIKE1*/
+static void
+oprintf(const char *fmt, ...)
+{
+ va_list ap;
+ int n;
+
+ if (g_ofp == NULL)
+ return;
+
+ va_start(ap, fmt);
+ n = vfprintf(g_ofp, fmt, ap);
+ va_end(ap);
+
+ if (n < 0) {
+ if (errno != EINTR) {
+ fatal("failed to write to %s",
+ g_ofile ? g_ofile : "<stdout>");
+ }
+ clearerr(g_ofp);
+ }
+}
+
+static char **
+make_argv(char *s)
+{
+ const char *ws = "\f\n\r\t\v ";
+ char **argv = malloc(sizeof (char *) * (strlen(s) / 2 + 1));
+ int argc = 0;
+ char *p = s;
+
+ if (argv == NULL)
+ return (NULL);
+
+ for (p = strtok(s, ws); p != NULL; p = strtok(NULL, ws))
+ argv[argc++] = p;
+
+ if (argc == 0)
+ argv[argc++] = s;
+
+ argv[argc] = NULL;
+ return (argv);
+}
+
+static void
+dof_prune(const char *fname)
+{
+ struct stat sbuf;
+ size_t sz, i, j, mark, len;
+ char *buf;
+ int msg = 0, fd;
+
+ if ((fd = open(fname, O_RDONLY)) == -1) {
+ /*
+ * This is okay only if the file doesn't exist at all.
+ */
+ if (errno != ENOENT)
+ fatal("failed to open %s", fname);
+ return;
+ }
+
+ if (fstat(fd, &sbuf) == -1)
+ fatal("failed to fstat %s", fname);
+
+ if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL)
+ fatal("failed to allocate memory for %s", fname);
+
+ if (read(fd, buf, sz) != sz)
+ fatal("failed to read %s", fname);
+
+ buf[sz] = '\0';
+ (void) close(fd);
+
+ if ((fd = open(fname, O_WRONLY | O_TRUNC)) == -1)
+ fatal("failed to open %s for writing", fname);
+
+ len = strlen("dof-data-");
+
+ for (mark = 0, i = 0; i < sz; i++) {
+ if (strncmp(&buf[i], "dof-data-", len) != 0)
+ continue;
+
+ /*
+ * This is only a match if it's in the 0th column.
+ */
+ if (i != 0 && buf[i - 1] != '\n')
+ continue;
+
+ if (msg++ == 0) {
+ error("cleaned up old anonymous "
+ "enabling in %s\n", fname);
+ }
+
+ /*
+ * We have a match. First write out our data up until now.
+ */
+ if (i != mark) {
+ if (write(fd, &buf[mark], i - mark) != i - mark)
+ fatal("failed to write to %s", fname);
+ }
+
+ /*
+ * Now scan forward until we scan past a newline.
+ */
+ for (j = i; j < sz && buf[j] != '\n'; j++)
+ continue;
+
+ /*
+ * Reset our mark.
+ */
+ if ((mark = j + 1) >= sz)
+ break;
+
+ i = j;
+ }
+
+ if (mark < sz) {
+ if (write(fd, &buf[mark], sz - mark) != sz - mark)
+ fatal("failed to write to %s", fname);
+ }
+
+ (void) close(fd);
+ free(buf);
+}
+
+#ifdef __FreeBSD__
+/*
+ * Use nextboot(8) to tell the loader to load DTrace kernel modules during
+ * the next boot of the system. The nextboot(8) configuration is removed during
+ * boot, so it will not persist indefinitely.
+ */
+static void
+bootdof_add(void)
+{
+ char * const nbargv[] = {
+ "nextboot", "-a",
+ "-e", "dtraceall_load=\"YES\"",
+ "-e", "dtrace_dof_load=\"YES\"",
+ "-e", "dtrace_dof_name=\"/boot/dtrace.dof\"",
+ "-e", "dtrace_dof_type=\"dtrace_dof\"",
+ NULL,
+ };
+ pid_t child;
+ int err, status;
+
+ err = posix_spawnp(&child, "nextboot", NULL, NULL, nbargv,
+ NULL);
+ if (err != 0) {
+ error("failed to execute nextboot: %s", strerror(err));
+ exit(E_ERROR);
+ }
+
+ if (waitpid(child, &status, 0) != child)
+ fatal("waiting for nextboot");
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ error("nextboot returned with status %d", status);
+ exit(E_ERROR);
+ }
+}
+#else
+static void
+etcsystem_prune(void)
+{
+ struct stat sbuf;
+ size_t sz;
+ char *buf, *start, *end;
+ int fd;
+ char *fname = g_etcfile, *tmpname;
+
+ if ((fd = open(fname, O_RDONLY)) == -1)
+ fatal("failed to open %s", fname);
+
+ if (fstat(fd, &sbuf) == -1)
+ fatal("failed to fstat %s", fname);
+
+ if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL)
+ fatal("failed to allocate memory for %s", fname);
+
+ if (read(fd, buf, sz) != sz)
+ fatal("failed to read %s", fname);
+
+ buf[sz] = '\0';
+ (void) close(fd);
+
+ if ((start = strstr(buf, g_etcbegin)) == NULL)
+ goto out;
+
+ if (strlen(buf) != sz) {
+ fatal("embedded nul byte in %s; manual repair of %s "
+ "required\n", fname, fname);
+ }
+
+ if (strstr(start + 1, g_etcbegin) != NULL) {
+ fatal("multiple start sentinels in %s; manual repair of %s "
+ "required\n", fname, fname);
+ }
+
+ if ((end = strstr(buf, g_etcend)) == NULL) {
+ fatal("missing end sentinel in %s; manual repair of %s "
+ "required\n", fname, fname);
+ }
+
+ if (start > end) {
+ fatal("end sentinel preceeds start sentinel in %s; manual "
+ "repair of %s required\n", fname, fname);
+ }
+
+ end += strlen(g_etcend) + 1;
+ bcopy(end, start, strlen(end) + 1);
+
+ tmpname = alloca(sz = strlen(fname) + 80);
+ (void) snprintf(tmpname, sz, "%s.dtrace.%d", fname, getpid());
+
+ if ((fd = open(tmpname,
+ O_WRONLY | O_CREAT | O_EXCL, sbuf.st_mode)) == -1)
+ fatal("failed to create %s", tmpname);
+
+ if (write(fd, buf, strlen(buf)) < strlen(buf)) {
+ (void) unlink(tmpname);
+ fatal("failed to write to %s", tmpname);
+ }
+
+ (void) close(fd);
+
+ if (chown(tmpname, sbuf.st_uid, sbuf.st_gid) != 0) {
+ (void) unlink(tmpname);
+ fatal("failed to chown(2) %s to uid %d, gid %d", tmpname,
+ (int)sbuf.st_uid, (int)sbuf.st_gid);
+ }
+
+ if (rename(tmpname, fname) == -1)
+ fatal("rename of %s to %s failed", tmpname, fname);
+
+ error("cleaned up forceload directives in %s\n", fname);
+out:
+ free(buf);
+}
+
+static void
+etcsystem_add(void)
+{
+ const char *mods[20];
+ int nmods, line;
+
+ if ((g_ofp = fopen(g_ofile = g_etcfile, "a")) == NULL)
+ fatal("failed to open output file '%s'", g_ofile);
+
+ oprintf("%s\n", g_etcbegin);
+
+ for (line = 0; g_etc[line] != NULL; line++)
+ oprintf("%s\n", g_etc[line]);
+
+ nmods = dtrace_provider_modules(g_dtp, mods,
+ sizeof (mods) / sizeof (char *) - 1);
+
+ if (nmods >= sizeof (mods) / sizeof (char *))
+ fatal("unexpectedly large number of modules!");
+
+ mods[nmods++] = "dtrace";
+
+ for (line = 0; line < nmods; line++)
+ oprintf("forceload: drv/%s\n", mods[line]);
+
+ oprintf("%s\n", g_etcend);
+
+ if (fclose(g_ofp) == EOF)
+ fatal("failed to close output file '%s'", g_ofile);
+
+ error("added forceload directives to %s\n", g_ofile);
+}
+#endif /* !__FreeBSD__ */
+
+static void
+print_probe_info(const dtrace_probeinfo_t *p)
+{
+ char buf[BUFSIZ];
+ char *user;
+ int i;
+
+ oprintf("\n\tProbe Description Attributes\n");
+
+ oprintf("\t\tIdentifier Names: %s\n",
+ dtrace_stability_name(p->dtp_attr.dtat_name));
+ oprintf("\t\tData Semantics: %s\n",
+ dtrace_stability_name(p->dtp_attr.dtat_data));
+ oprintf("\t\tDependency Class: %s\n",
+ dtrace_class_name(p->dtp_attr.dtat_class));
+
+ oprintf("\n\tArgument Attributes\n");
+
+ oprintf("\t\tIdentifier Names: %s\n",
+ dtrace_stability_name(p->dtp_arga.dtat_name));
+ oprintf("\t\tData Semantics: %s\n",
+ dtrace_stability_name(p->dtp_arga.dtat_data));
+ oprintf("\t\tDependency Class: %s\n",
+ dtrace_class_name(p->dtp_arga.dtat_class));
+
+ oprintf("\n\tArgument Types\n");
+
+ for (i = 0; i < p->dtp_argc; i++) {
+ if (p->dtp_argv[i].dtt_flags & DTT_FL_USER)
+ user = "userland ";
+ else
+ user = "";
+ if (ctf_type_name(p->dtp_argv[i].dtt_ctfp,
+ p->dtp_argv[i].dtt_type, buf, sizeof (buf)) == NULL)
+ (void) strlcpy(buf, "(unknown)", sizeof (buf));
+ oprintf("\t\targs[%d]: %s%s\n", i, user, buf);
+ }
+
+ if (p->dtp_argc == 0)
+ oprintf("\t\tNone\n");
+
+ oprintf("\n");
+}
+
+/*ARGSUSED*/
+static int
+info_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
+ dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last)
+{
+ dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc;
+ dtrace_probedesc_t *pdp = &edp->dted_probe;
+ dtrace_probeinfo_t p;
+
+ if (edp == *last)
+ return (0);
+
+ oprintf("\n%s:%s:%s:%s\n",
+ pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
+
+ if (dtrace_probe_info(dtp, pdp, &p) == 0)
+ print_probe_info(&p);
+
+ *last = edp;
+ return (0);
+}
+
+/*
+ * Execute the specified program by enabling the corresponding instrumentation.
+ * If -e has been specified, we get the program info but do not enable it. If
+ * -v has been specified, we print a stability report for the program.
+ */
+static void
+exec_prog(const dtrace_cmd_t *dcp)
+{
+ dtrace_ecbdesc_t *last = NULL;
+ dtrace_proginfo_t dpi;
+
+ if (!g_exec) {
+ dtrace_program_info(g_dtp, dcp->dc_prog, &dpi);
+ } else if (dtrace_program_exec(g_dtp, dcp->dc_prog, &dpi) == -1) {
+ dfatal("failed to enable '%s'", dcp->dc_name);
+ } else {
+ notice("%s '%s' matched %u probe%s\n",
+ dcp->dc_desc, dcp->dc_name,
+ dpi.dpi_matches, dpi.dpi_matches == 1 ? "" : "s");
+ }
+
+ if (g_verbose) {
+ oprintf("\nStability attributes for %s %s:\n",
+ dcp->dc_desc, dcp->dc_name);
+
+ oprintf("\n\tMinimum Probe Description Attributes\n");
+ oprintf("\t\tIdentifier Names: %s\n",
+ dtrace_stability_name(dpi.dpi_descattr.dtat_name));
+ oprintf("\t\tData Semantics: %s\n",
+ dtrace_stability_name(dpi.dpi_descattr.dtat_data));
+ oprintf("\t\tDependency Class: %s\n",
+ dtrace_class_name(dpi.dpi_descattr.dtat_class));
+
+ oprintf("\n\tMinimum Statement Attributes\n");
+
+ oprintf("\t\tIdentifier Names: %s\n",
+ dtrace_stability_name(dpi.dpi_stmtattr.dtat_name));
+ oprintf("\t\tData Semantics: %s\n",
+ dtrace_stability_name(dpi.dpi_stmtattr.dtat_data));
+ oprintf("\t\tDependency Class: %s\n",
+ dtrace_class_name(dpi.dpi_stmtattr.dtat_class));
+
+ if (!g_exec) {
+ (void) dtrace_stmt_iter(g_dtp, dcp->dc_prog,
+ (dtrace_stmt_f *)info_stmt, &last);
+ } else
+ oprintf("\n");
+ }
+
+ g_total += dpi.dpi_matches;
+}
+
+/*
+ * Print out the specified DOF buffer as a set of ASCII bytes appropriate for
+ * storing in a driver.conf(4) file associated with the dtrace driver.
+ */
+static void
+anon_prog(const dtrace_cmd_t *dcp, dof_hdr_t *dof, int n)
+{
+ const uchar_t *p, *q;
+
+ if (dof == NULL)
+ dfatal("failed to create DOF image for '%s'", dcp->dc_name);
+
+ p = (uchar_t *)dof;
+ q = p + dof->dofh_filesz;
+
+#ifdef __FreeBSD__
+ /*
+ * On FreeBSD, the DOF file is read directly during boot - just write
+ * two hex characters per byte.
+ */
+ oprintf("dof-data-%d=", n);
+
+ while (p < q)
+ oprintf("%02x", *p++);
+
+ oprintf("\n");
+#else
+ oprintf("dof-data-%d=0x%x", n, *p++);
+
+ while (p < q)
+ oprintf(",0x%x", *p++);
+
+ oprintf(";\n");
+#endif
+
+ dtrace_dof_destroy(g_dtp, dof);
+}
+
+/*
+ * Link the specified D program in DOF form into an ELF file for use in either
+ * helpers, userland provider definitions, or both. If -o was specified, that
+ * path is used as the output file name. If -o wasn't specified and the input
+ * program is from a script whose name is %.d, use basename(%.o) as the output
+ * file name. Otherwise we use "d.out" as the default output file name.
+ */
+static void
+link_prog(dtrace_cmd_t *dcp)
+{
+ char *p;
+
+ if (g_cmdc == 1 && g_ofile != NULL) {
+ (void) strlcpy(dcp->dc_ofile, g_ofile, sizeof (dcp->dc_ofile));
+ } else if ((p = strrchr(dcp->dc_arg, '.')) != NULL &&
+ strcmp(p, ".d") == 0) {
+ p[0] = '\0'; /* strip .d suffix */
+ (void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile),
+ "%s.o", basename(dcp->dc_arg));
+ } else if (g_cmdc > 1) {
+ (void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile),
+ "d.out.%td", dcp - g_cmdv);
+ } else {
+ (void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile),
+ "d.out");
+ }
+
+ if (dtrace_program_link(g_dtp, dcp->dc_prog, DTRACE_D_PROBES,
+ dcp->dc_ofile, g_objc, g_objv) != 0)
+ dfatal("failed to link %s %s", dcp->dc_desc, dcp->dc_name);
+}
+
+/*ARGSUSED*/
+static int
+list_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg)
+{
+ dtrace_probeinfo_t p;
+
+ oprintf("%5d %10s %17s %33s %s\n", pdp->dtpd_id,
+ pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
+
+ if (g_verbose && dtrace_probe_info(dtp, pdp, &p) == 0)
+ print_probe_info(&p);
+
+ if (g_intr != 0)
+ return (1);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+list_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
+ dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last)
+{
+ dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc;
+
+ if (edp == *last)
+ return (0);
+
+ if (dtrace_probe_iter(g_dtp, &edp->dted_probe, list_probe, NULL) != 0) {
+ error("failed to match %s:%s:%s:%s: %s\n",
+ edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod,
+ edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ *last = edp;
+ return (0);
+}
+
+/*
+ * List the probes corresponding to the specified program by iterating over
+ * each statement and then matching probes to the statement probe descriptions.
+ */
+static void
+list_prog(const dtrace_cmd_t *dcp)
+{
+ dtrace_ecbdesc_t *last = NULL;
+
+ (void) dtrace_stmt_iter(g_dtp, dcp->dc_prog,
+ (dtrace_stmt_f *)list_stmt, &last);
+}
+
+static void
+compile_file(dtrace_cmd_t *dcp)
+{
+ char *arg0;
+ FILE *fp;
+
+ if ((fp = fopen(dcp->dc_arg, "r")) == NULL)
+ fatal("failed to open %s", dcp->dc_arg);
+
+ arg0 = g_argv[0];
+ g_argv[0] = dcp->dc_arg;
+
+ if ((dcp->dc_prog = dtrace_program_fcompile(g_dtp, fp,
+ g_cflags, g_argc, g_argv)) == NULL)
+ dfatal("failed to compile script %s", dcp->dc_arg);
+
+ g_argv[0] = arg0;
+ (void) fclose(fp);
+
+ dcp->dc_desc = "script";
+ dcp->dc_name = dcp->dc_arg;
+}
+
+static void
+compile_str(dtrace_cmd_t *dcp)
+{
+ char *p;
+
+ if ((dcp->dc_prog = dtrace_program_strcompile(g_dtp, dcp->dc_arg,
+ dcp->dc_spec, g_cflags | DTRACE_C_PSPEC, g_argc, g_argv)) == NULL)
+ dfatal("invalid probe specifier %s", dcp->dc_arg);
+
+ if ((p = strpbrk(dcp->dc_arg, "{/;")) != NULL)
+ *p = '\0'; /* crop name for reporting */
+
+ dcp->dc_desc = "description";
+ dcp->dc_name = dcp->dc_arg;
+}
+
+/*ARGSUSED*/
+static void
+prochandler(struct ps_prochandle *P, const char *msg, void *arg)
+{
+#ifdef illumos
+ const psinfo_t *prp = Ppsinfo(P);
+ int pid = Pstatus(P)->pr_pid;
+ char name[SIG2STR_MAX];
+#else
+ int wstatus = proc_getwstat(P);
+ int pid = proc_getpid(P);
+#endif
+
+ if (msg != NULL) {
+ notice("pid %d: %s\n", pid, msg);
+ return;
+ }
+
+#ifdef illumos
+ switch (Pstate(P)) {
+#else
+ switch (proc_state(P)) {
+#endif
+ case PS_UNDEAD:
+#ifdef illumos
+ /*
+ * Ideally we would like to always report pr_wstat here, but it
+ * isn't possible given current /proc semantics. If we grabbed
+ * the process, Ppsinfo() will either fail or return a zeroed
+ * psinfo_t depending on how far the parent is in reaping it.
+ * When /proc provides a stable pr_wstat in the status file,
+ * this code can be improved by examining this new pr_wstat.
+ */
+ if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) {
+ notice("pid %d terminated by %s\n", pid,
+ proc_signame(WTERMSIG(prp->pr_wstat),
+ name, sizeof (name)));
+#else
+ if (WIFSIGNALED(wstatus)) {
+ notice("pid %d terminated by %d\n", pid,
+ WTERMSIG(wstatus));
+#endif
+#ifdef illumos
+ } else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) {
+ notice("pid %d exited with status %d\n",
+ pid, WEXITSTATUS(prp->pr_wstat));
+#else
+ } else if (WEXITSTATUS(wstatus) != 0) {
+ notice("pid %d exited with status %d\n",
+ pid, WEXITSTATUS(wstatus));
+#endif
+ } else {
+ notice("pid %d has exited\n", pid);
+ }
+ g_pslive--;
+ break;
+
+ case PS_LOST:
+ notice("pid %d exec'd a set-id or unobservable program\n", pid);
+ g_pslive--;
+ break;
+ }
+}
+
+/*ARGSUSED*/
+static int
+errhandler(const dtrace_errdata_t *data, void *arg)
+{
+ error(data->dteda_msg);
+ return (DTRACE_HANDLE_OK);
+}
+
+/*ARGSUSED*/
+static int
+drophandler(const dtrace_dropdata_t *data, void *arg)
+{
+ error(data->dtdda_msg);
+ return (DTRACE_HANDLE_OK);
+}
+
+/*ARGSUSED*/
+static int
+setopthandler(const dtrace_setoptdata_t *data, void *arg)
+{
+ if (strcmp(data->dtsda_option, "quiet") == 0)
+ g_quiet = data->dtsda_newval != DTRACEOPT_UNSET;
+
+ if (strcmp(data->dtsda_option, "flowindent") == 0)
+ g_flowindent = data->dtsda_newval != DTRACEOPT_UNSET;
+
+ return (DTRACE_HANDLE_OK);
+}
+
+#define BUFDUMPHDR(hdr) \
+ (void) printf("%s: %s%s\n", g_pname, hdr, strlen(hdr) > 0 ? ":" : "");
+
+#define BUFDUMPSTR(ptr, field) \
+ (void) printf("%s: %20s => ", g_pname, #field); \
+ if ((ptr)->field != NULL) { \
+ const char *c = (ptr)->field; \
+ (void) printf("\""); \
+ do { \
+ if (*c == '\n') { \
+ (void) printf("\\n"); \
+ continue; \
+ } \
+ \
+ (void) printf("%c", *c); \
+ } while (*c++ != '\0'); \
+ (void) printf("\"\n"); \
+ } else { \
+ (void) printf("<NULL>\n"); \
+ }
+
+#define BUFDUMPASSTR(ptr, field, str) \
+ (void) printf("%s: %20s => %s\n", g_pname, #field, str);
+
+#define BUFDUMP(ptr, field) \
+ (void) printf("%s: %20s => %lld\n", g_pname, #field, \
+ (long long)(ptr)->field);
+
+#define BUFDUMPPTR(ptr, field) \
+ (void) printf("%s: %20s => %s\n", g_pname, #field, \
+ (ptr)->field != NULL ? "<non-NULL>" : "<NULL>");
+
+/*ARGSUSED*/
+static int
+bufhandler(const dtrace_bufdata_t *bufdata, void *arg)
+{
+ const dtrace_aggdata_t *agg = bufdata->dtbda_aggdata;
+ const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc;
+ const dtrace_probedesc_t *pd;
+ uint32_t flags = bufdata->dtbda_flags;
+ char buf[512], *c = buf, *end = c + sizeof (buf);
+ int i, printed;
+
+ struct {
+ const char *name;
+ uint32_t value;
+ } flagnames[] = {
+ { "AGGVAL", DTRACE_BUFDATA_AGGVAL },
+ { "AGGKEY", DTRACE_BUFDATA_AGGKEY },
+ { "AGGFORMAT", DTRACE_BUFDATA_AGGFORMAT },
+ { "AGGLAST", DTRACE_BUFDATA_AGGLAST },
+ { "???", UINT32_MAX },
+ { NULL }
+ };
+
+ if (bufdata->dtbda_probe != NULL) {
+ pd = bufdata->dtbda_probe->dtpda_pdesc;
+ } else if (agg != NULL) {
+ pd = agg->dtada_pdesc;
+ } else {
+ pd = NULL;
+ }
+
+ BUFDUMPHDR(">>> Called buffer handler");
+ BUFDUMPHDR("");
+
+ BUFDUMPHDR(" dtrace_bufdata");
+ BUFDUMPSTR(bufdata, dtbda_buffered);
+ BUFDUMPPTR(bufdata, dtbda_probe);
+ BUFDUMPPTR(bufdata, dtbda_aggdata);
+ BUFDUMPPTR(bufdata, dtbda_recdesc);
+
+ (void) snprintf(c, end - c, "0x%x ", bufdata->dtbda_flags);
+ c += strlen(c);
+
+ for (i = 0, printed = 0; flagnames[i].name != NULL; i++) {
+ if (!(flags & flagnames[i].value))
+ continue;
+
+ (void) snprintf(c, end - c,
+ "%s%s", printed++ ? " | " : "(", flagnames[i].name);
+ c += strlen(c);
+ flags &= ~flagnames[i].value;
+ }
+
+ if (printed)
+ (void) snprintf(c, end - c, ")");
+
+ BUFDUMPASSTR(bufdata, dtbda_flags, buf);
+ BUFDUMPHDR("");
+
+ if (pd != NULL) {
+ BUFDUMPHDR(" dtrace_probedesc");
+ BUFDUMPSTR(pd, dtpd_provider);
+ BUFDUMPSTR(pd, dtpd_mod);
+ BUFDUMPSTR(pd, dtpd_func);
+ BUFDUMPSTR(pd, dtpd_name);
+ BUFDUMPHDR("");
+ }
+
+ if (rec != NULL) {
+ BUFDUMPHDR(" dtrace_recdesc");
+ BUFDUMP(rec, dtrd_action);
+ BUFDUMP(rec, dtrd_size);
+
+ if (agg != NULL) {
+ uint8_t *data;
+ int lim = rec->dtrd_size;
+
+ (void) sprintf(buf, "%d (data: ", rec->dtrd_offset);
+ c = buf + strlen(buf);
+
+ if (lim > sizeof (uint64_t))
+ lim = sizeof (uint64_t);
+
+ data = (uint8_t *)agg->dtada_data + rec->dtrd_offset;
+
+ for (i = 0; i < lim; i++) {
+ (void) snprintf(c, end - c, "%s%02x",
+ i == 0 ? "" : " ", *data++);
+ c += strlen(c);
+ }
+
+ (void) snprintf(c, end - c,
+ "%s)", lim < rec->dtrd_size ? " ..." : "");
+ BUFDUMPASSTR(rec, dtrd_offset, buf);
+ } else {
+ BUFDUMP(rec, dtrd_offset);
+ }
+
+ BUFDUMPHDR("");
+ }
+
+ if (agg != NULL) {
+ dtrace_aggdesc_t *desc = agg->dtada_desc;
+
+ BUFDUMPHDR(" dtrace_aggdesc");
+ BUFDUMPSTR(desc, dtagd_name);
+ BUFDUMP(desc, dtagd_varid);
+ BUFDUMP(desc, dtagd_id);
+ BUFDUMP(desc, dtagd_nrecs);
+ BUFDUMPHDR("");
+ }
+
+ return (DTRACE_HANDLE_OK);
+}
+
+/*ARGSUSED*/
+static int
+chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg)
+{
+ dtrace_actkind_t act;
+ uintptr_t addr;
+
+ if (rec == NULL) {
+ /*
+ * We have processed the final record; output the newline if
+ * we're not in quiet mode.
+ */
+ if (!g_quiet)
+ oprintf("\n");
+
+ return (DTRACE_CONSUME_NEXT);
+ }
+
+ act = rec->dtrd_action;
+ addr = (uintptr_t)data->dtpda_data;
+
+ if (act == DTRACEACT_EXIT) {
+ g_status = *((uint32_t *)addr);
+ return (DTRACE_CONSUME_NEXT);
+ }
+
+ return (DTRACE_CONSUME_THIS);
+}
+
+/*ARGSUSED*/
+static int
+chew(const dtrace_probedata_t *data, void *arg)
+{
+ dtrace_probedesc_t *pd = data->dtpda_pdesc;
+ processorid_t cpu = data->dtpda_cpu;
+ static int heading;
+
+ if (g_impatient) {
+ g_newline = 0;
+ return (DTRACE_CONSUME_ABORT);
+ }
+
+ if (heading == 0) {
+ if (!g_flowindent) {
+ if (!g_quiet) {
+ oprintf("%3s %6s %32s\n",
+ "CPU", "ID", "FUNCTION:NAME");
+ }
+ } else {
+ oprintf("%3s %-41s\n", "CPU", "FUNCTION");
+ }
+ heading = 1;
+ }
+
+ if (!g_flowindent) {
+ if (!g_quiet) {
+ char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2];
+
+ (void) snprintf(name, sizeof (name), "%s:%s",
+ pd->dtpd_func, pd->dtpd_name);
+
+ oprintf("%3d %6d %32s ", cpu, pd->dtpd_id, name);
+ }
+ } else {
+ int indent = data->dtpda_indent;
+ char *name;
+ size_t len;
+
+ if (data->dtpda_flow == DTRACEFLOW_NONE) {
+ len = indent + DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 5;
+ name = alloca(len);
+ (void) snprintf(name, len, "%*s%s%s:%s", indent, "",
+ data->dtpda_prefix, pd->dtpd_func,
+ pd->dtpd_name);
+ } else {
+ len = indent + DTRACE_FUNCNAMELEN + 5;
+ name = alloca(len);
+ (void) snprintf(name, len, "%*s%s%s", indent, "",
+ data->dtpda_prefix, pd->dtpd_func);
+ }
+
+ oprintf("%3d %-41s ", cpu, name);
+ }
+
+ return (DTRACE_CONSUME_THIS);
+}
+
+static void
+go(void)
+{
+ int i;
+
+ struct {
+ char *name;
+ char *optname;
+ dtrace_optval_t val;
+ } bufs[] = {
+ { "buffer size", "bufsize" },
+ { "aggregation size", "aggsize" },
+ { "speculation size", "specsize" },
+ { "dynamic variable size", "dynvarsize" },
+ { NULL }
+ }, rates[] = {
+ { "cleaning rate", "cleanrate" },
+ { "status rate", "statusrate" },
+ { NULL }
+ };
+
+ for (i = 0; bufs[i].name != NULL; i++) {
+ if (dtrace_getopt(g_dtp, bufs[i].optname, &bufs[i].val) == -1)
+ fatal("couldn't get option %s", bufs[i].optname);
+ }
+
+ for (i = 0; rates[i].name != NULL; i++) {
+ if (dtrace_getopt(g_dtp, rates[i].optname, &rates[i].val) == -1)
+ fatal("couldn't get option %s", rates[i].optname);
+ }
+
+ if (dtrace_go(g_dtp) == -1)
+ dfatal("could not enable tracing");
+
+ for (i = 0; bufs[i].name != NULL; i++) {
+ dtrace_optval_t j = 0, mul = 10;
+ dtrace_optval_t nsize;
+
+ if (bufs[i].val == DTRACEOPT_UNSET)
+ continue;
+
+ (void) dtrace_getopt(g_dtp, bufs[i].optname, &nsize);
+
+ if (nsize == DTRACEOPT_UNSET || nsize == 0)
+ continue;
+
+ if (nsize >= bufs[i].val - sizeof (uint64_t))
+ continue;
+
+ for (; (INT64_C(1) << mul) <= nsize; j++, mul += 10)
+ continue;
+
+ if (!(nsize & ((INT64_C(1) << (mul - 10)) - 1))) {
+ error("%s lowered to %lld%c\n", bufs[i].name,
+ (long long)nsize >> (mul - 10), " kmgtpe"[j]);
+ } else {
+ error("%s lowered to %lld bytes\n", bufs[i].name,
+ (long long)nsize);
+ }
+ }
+
+ for (i = 0; rates[i].name != NULL; i++) {
+ dtrace_optval_t nval;
+ char *dir;
+
+ if (rates[i].val == DTRACEOPT_UNSET)
+ continue;
+
+ (void) dtrace_getopt(g_dtp, rates[i].optname, &nval);
+
+ if (nval == DTRACEOPT_UNSET || nval == 0)
+ continue;
+
+ if (rates[i].val == nval)
+ continue;
+
+ dir = nval > rates[i].val ? "reduced" : "increased";
+
+ if (nval <= NANOSEC && (NANOSEC % nval) == 0) {
+ error("%s %s to %lld hz\n", rates[i].name, dir,
+ (long long)NANOSEC / (long long)nval);
+ continue;
+ }
+
+ if ((nval % NANOSEC) == 0) {
+ error("%s %s to once every %lld seconds\n",
+ rates[i].name, dir,
+ (long long)nval / (long long)NANOSEC);
+ continue;
+ }
+
+ error("%s %s to once every %lld nanoseconds\n",
+ rates[i].name, dir, (long long)nval);
+ }
+}
+
+/*ARGSUSED*/
+static void
+intr(int signo)
+{
+ if (!g_intr)
+ g_newline = 1;
+
+ if (g_intr++)
+ g_impatient = 1;
+}
+
+#ifdef __FreeBSD__
+static void
+siginfo(int signo __unused)
+{
+
+ g_siginfo++;
+ g_newline = 1;
+}
+#endif
+
+static void
+installsighands(void)
+{
+ struct sigaction act, oact;
+
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = intr;
+
+ if (sigaction(SIGINT, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
+ (void) sigaction(SIGINT, &act, NULL);
+
+ if (sigaction(SIGTERM, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
+ (void) sigaction(SIGTERM, &act, NULL);
+
+#ifdef __FreeBSD__
+ if (sigaction(SIGPIPE, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
+ (void) sigaction(SIGPIPE, &act, NULL);
+
+ if (sigaction(SIGUSR1, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
+ (void) sigaction(SIGUSR1, &act, NULL);
+
+ act.sa_handler = siginfo;
+ if (sigaction(SIGINFO, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
+ (void) sigaction(SIGINFO, &act, NULL);
+#endif
+}
+
+int
+main(int argc, char *argv[])
+{
+ dtrace_bufdesc_t buf;
+ dtrace_status_t status[2];
+ dtrace_optval_t opt;
+ dtrace_cmd_t *dcp;
+
+ g_ofp = stdout;
+ int done = 0, mode = 0;
+ int err, i, c;
+ char *p, **v;
+ struct ps_prochandle *P;
+ pid_t pid;
+
+ g_pname = basename(argv[0]);
+
+ if (argc == 1)
+ return (usage(stderr));
+
+ if ((g_argv = malloc(sizeof (char *) * argc)) == NULL ||
+ (g_cmdv = malloc(sizeof (dtrace_cmd_t) * argc)) == NULL ||
+ (g_psv = malloc(sizeof (struct ps_prochandle *) * argc)) == NULL)
+ fatal("failed to allocate memory for arguments");
+
+ g_argv[g_argc++] = argv[0]; /* propagate argv[0] to D as $0/$$0 */
+ argv[0] = g_pname; /* rewrite argv[0] for getopt errors */
+
+ bzero(status, sizeof (status));
+ bzero(&buf, sizeof (buf));
+
+ /*
+ * Make an initial pass through argv[] processing any arguments that
+ * affect our behavior mode (g_mode) and flags used for dtrace_open().
+ * We also accumulate arguments that are not affiliated with getopt
+ * options into g_argv[], and abort if any invalid options are found.
+ */
+ for (optind = 1; optind < argc; optind++) {
+ while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) {
+ switch (c) {
+ case '3':
+ if (strcmp(optarg, "2") != 0) {
+ (void) fprintf(stderr,
+ "%s: illegal option -- 3%s\n",
+ argv[0], optarg);
+ return (usage(stderr));
+ }
+ g_oflags &= ~DTRACE_O_LP64;
+ g_oflags |= DTRACE_O_ILP32;
+ break;
+
+ case '6':
+ if (strcmp(optarg, "4") != 0) {
+ (void) fprintf(stderr,
+ "%s: illegal option -- 6%s\n",
+ argv[0], optarg);
+ return (usage(stderr));
+ }
+ g_oflags &= ~DTRACE_O_ILP32;
+ g_oflags |= DTRACE_O_LP64;
+ break;
+
+ case 'a':
+ g_grabanon++; /* also checked in pass 2 below */
+ break;
+
+ case 'A':
+ g_mode = DMODE_ANON;
+ g_exec = 0;
+ mode++;
+ break;
+
+ case 'e':
+ g_exec = 0;
+ done = 1;
+ break;
+
+ case 'h':
+ g_mode = DMODE_HEADER;
+ g_oflags |= DTRACE_O_NODEV;
+ g_cflags |= DTRACE_C_ZDEFS; /* -h implies -Z */
+ g_exec = 0;
+ mode++;
+ break;
+
+ case 'G':
+ g_mode = DMODE_LINK;
+ g_oflags |= DTRACE_O_NODEV;
+ g_cflags |= DTRACE_C_ZDEFS; /* -G implies -Z */
+ g_exec = 0;
+ mode++;
+ break;
+
+ case 'l':
+ g_mode = DMODE_LIST;
+ g_cflags |= DTRACE_C_ZDEFS; /* -l implies -Z */
+ mode++;
+ break;
+
+ case 'V':
+ g_mode = DMODE_VERS;
+ mode++;
+ break;
+
+ default:
+ if (strchr(DTRACE_OPTSTR, c) == NULL)
+ return (usage(stderr));
+ }
+ }
+
+ if (optind < argc)
+ g_argv[g_argc++] = argv[optind];
+ }
+
+ if (mode > 1) {
+ (void) fprintf(stderr, "%s: only one of the [-AGhlV] options "
+ "can be specified at a time\n", g_pname);
+ return (E_USAGE);
+ }
+
+ if (g_mode == DMODE_VERS)
+ return (printf("%s: %s\n", g_pname, _dtrace_version) <= 0);
+
+ /*
+ * If we're in linker mode and the data model hasn't been specified,
+ * we try to guess the appropriate setting by examining the object
+ * files. We ignore certain errors since we'll catch them later when
+ * we actually process the object files.
+ */
+ if (g_mode == DMODE_LINK &&
+ (g_oflags & (DTRACE_O_ILP32 | DTRACE_O_LP64)) == 0 &&
+ elf_version(EV_CURRENT) != EV_NONE) {
+ int fd;
+ Elf *elf;
+ GElf_Ehdr ehdr;
+
+ for (i = 1; i < g_argc; i++) {
+ if ((fd = open64(g_argv[i], O_RDONLY)) == -1)
+ break;
+
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
+ (void) close(fd);
+ break;
+ }
+
+ if (elf_kind(elf) != ELF_K_ELF ||
+ gelf_getehdr(elf, &ehdr) == NULL) {
+ (void) close(fd);
+ (void) elf_end(elf);
+ break;
+ }
+
+ (void) close(fd);
+ (void) elf_end(elf);
+
+ if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
+ if (g_oflags & DTRACE_O_ILP32) {
+ fatal("can't mix 32-bit and 64-bit "
+ "object files\n");
+ }
+ g_oflags |= DTRACE_O_LP64;
+ } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
+ if (g_oflags & DTRACE_O_LP64) {
+ fatal("can't mix 32-bit and 64-bit "
+ "object files\n");
+ }
+ g_oflags |= DTRACE_O_ILP32;
+ } else {
+ break;
+ }
+ }
+ }
+
+ /*
+ * Open libdtrace. If we are not actually going to be enabling any
+ * instrumentation attempt to reopen libdtrace using DTRACE_O_NODEV.
+ */
+ while ((g_dtp = dtrace_open(DTRACE_VERSION, g_oflags, &err)) == NULL) {
+ if (!(g_oflags & DTRACE_O_NODEV) && !g_exec && !g_grabanon) {
+ g_oflags |= DTRACE_O_NODEV;
+ continue;
+ }
+
+ fatal("failed to initialize dtrace: %s\n",
+ dtrace_errmsg(NULL, err));
+ }
+
+#if defined(__i386__)
+ /* XXX The 32-bit seems to need more buffer space by default -sson */
+ (void) dtrace_setopt(g_dtp, "bufsize", "12m");
+ (void) dtrace_setopt(g_dtp, "aggsize", "12m");
+#else
+ (void) dtrace_setopt(g_dtp, "bufsize", "4m");
+ (void) dtrace_setopt(g_dtp, "aggsize", "4m");
+#endif
+ (void) dtrace_setopt(g_dtp, "temporal", "yes");
+
+ /*
+ * If -G is specified, enable -xlink=dynamic and -xunodefs to permit
+ * references to undefined symbols to remain as unresolved relocations.
+ * If -A is specified, enable -xlink=primary to permit static linking
+ * only to kernel symbols that are defined in a primary kernel module.
+ */
+ if (g_mode == DMODE_LINK) {
+ (void) dtrace_setopt(g_dtp, "linkmode", "dynamic");
+ (void) dtrace_setopt(g_dtp, "unodefs", NULL);
+
+ /*
+ * Use the remaining arguments as the list of object files
+ * when in linker mode.
+ */
+ g_objc = g_argc - 1;
+ g_objv = g_argv + 1;
+
+ /*
+ * We still use g_argv[0], the name of the executable.
+ */
+ g_argc = 1;
+ } else if (g_mode == DMODE_ANON)
+ (void) dtrace_setopt(g_dtp, "linkmode", "primary");
+
+ /*
+ * Now that we have libdtrace open, make a second pass through argv[]
+ * to perform any dtrace_setopt() calls and change any compiler flags.
+ * We also accumulate any program specifications into our g_cmdv[] at
+ * this time; these will compiled as part of the fourth processing pass.
+ */
+ for (optind = 1; optind < argc; optind++) {
+ while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) {
+ switch (c) {
+ case 'a':
+ if (dtrace_setopt(g_dtp, "grabanon", 0) != 0)
+ dfatal("failed to set -a");
+ break;
+
+ case 'b':
+ if (dtrace_setopt(g_dtp,
+ "bufsize", optarg) != 0)
+ dfatal("failed to set -b %s", optarg);
+ break;
+
+ case 'B':
+ g_ofp = NULL;
+ break;
+
+ case 'C':
+ g_cflags |= DTRACE_C_CPP;
+ break;
+
+ case 'D':
+ if (dtrace_setopt(g_dtp, "define", optarg) != 0)
+ dfatal("failed to set -D %s", optarg);
+ break;
+
+ case 'f':
+ dcp = &g_cmdv[g_cmdc++];
+ dcp->dc_func = compile_str;
+ dcp->dc_spec = DTRACE_PROBESPEC_FUNC;
+ dcp->dc_arg = optarg;
+ break;
+
+ case 'F':
+ if (dtrace_setopt(g_dtp, "flowindent", 0) != 0)
+ dfatal("failed to set -F");
+ break;
+
+ case 'H':
+ if (dtrace_setopt(g_dtp, "cpphdrs", 0) != 0)
+ dfatal("failed to set -H");
+ break;
+
+ case 'i':
+ dcp = &g_cmdv[g_cmdc++];
+ dcp->dc_func = compile_str;
+ dcp->dc_spec = DTRACE_PROBESPEC_NAME;
+ dcp->dc_arg = optarg;
+ break;
+
+ case 'I':
+ if (dtrace_setopt(g_dtp, "incdir", optarg) != 0)
+ dfatal("failed to set -I %s", optarg);
+ break;
+
+ case 'L':
+ if (dtrace_setopt(g_dtp, "libdir", optarg) != 0)
+ dfatal("failed to set -L %s", optarg);
+ break;
+
+ case 'm':
+ dcp = &g_cmdv[g_cmdc++];
+ dcp->dc_func = compile_str;
+ dcp->dc_spec = DTRACE_PROBESPEC_MOD;
+ dcp->dc_arg = optarg;
+ break;
+
+ case 'n':
+ dcp = &g_cmdv[g_cmdc++];
+ dcp->dc_func = compile_str;
+ dcp->dc_spec = DTRACE_PROBESPEC_NAME;
+ dcp->dc_arg = optarg;
+ break;
+
+ case 'P':
+ dcp = &g_cmdv[g_cmdc++];
+ dcp->dc_func = compile_str;
+ dcp->dc_spec = DTRACE_PROBESPEC_PROVIDER;
+ dcp->dc_arg = optarg;
+ break;
+
+ case 'q':
+ if (dtrace_setopt(g_dtp, "quiet", 0) != 0)
+ dfatal("failed to set -q");
+ break;
+
+ case 'o':
+ g_ofile = optarg;
+ break;
+
+ case 's':
+ dcp = &g_cmdv[g_cmdc++];
+ dcp->dc_func = compile_file;
+ dcp->dc_spec = DTRACE_PROBESPEC_NONE;
+ dcp->dc_arg = optarg;
+ break;
+
+ case 'S':
+ g_cflags |= DTRACE_C_DIFV;
+ break;
+
+ case 'U':
+ if (dtrace_setopt(g_dtp, "undef", optarg) != 0)
+ dfatal("failed to set -U %s", optarg);
+ break;
+
+ case 'v':
+ g_verbose++;
+ break;
+
+ case 'w':
+ if (dtrace_setopt(g_dtp, "destructive", 0) != 0)
+ dfatal("failed to set -w");
+ break;
+
+ case 'x':
+ if ((p = strchr(optarg, '=')) != NULL)
+ *p++ = '\0';
+
+ if (dtrace_setopt(g_dtp, optarg, p) != 0)
+ dfatal("failed to set -x %s", optarg);
+ break;
+
+ case 'X':
+ if (dtrace_setopt(g_dtp, "stdc", optarg) != 0)
+ dfatal("failed to set -X %s", optarg);
+ break;
+
+ case 'Z':
+ g_cflags |= DTRACE_C_ZDEFS;
+ break;
+
+ default:
+ if (strchr(DTRACE_OPTSTR, c) == NULL)
+ return (usage(stderr));
+ }
+ }
+ }
+
+ if (g_ofp == NULL && g_mode != DMODE_EXEC) {
+ (void) fprintf(stderr, "%s: -B not valid in combination"
+ " with [-AGl] options\n", g_pname);
+ return (E_USAGE);
+ }
+
+ if (g_ofp == NULL && g_ofile != NULL) {
+ (void) fprintf(stderr, "%s: -B not valid in combination"
+ " with -o option\n", g_pname);
+ return (E_USAGE);
+ }
+
+ /*
+ * In our third pass we handle any command-line options related to
+ * grabbing or creating victim processes. The behavior of these calls
+ * may been affected by any library options set by the second pass.
+ */
+ for (optind = 1; optind < argc; optind++) {
+ while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) {
+ switch (c) {
+ case 'c':
+ if ((v = make_argv(optarg)) == NULL)
+ fatal("failed to allocate memory");
+
+ P = dtrace_proc_create(g_dtp, v[0], v, NULL, NULL);
+ if (P == NULL)
+ dfatal(NULL); /* dtrace_errmsg() only */
+
+ g_psv[g_psc++] = P;
+ free(v);
+ break;
+
+ case 'p':
+ errno = 0;
+ pid = strtol(optarg, &p, 10);
+
+ if (errno != 0 || p == optarg || p[0] != '\0')
+ fatal("invalid pid: %s\n", optarg);
+
+ P = dtrace_proc_grab(g_dtp, pid, 0);
+ if (P == NULL)
+ dfatal(NULL); /* dtrace_errmsg() only */
+
+ g_psv[g_psc++] = P;
+ break;
+ }
+ }
+ }
+
+ /*
+ * In our fourth pass we finish g_cmdv[] by calling dc_func to convert
+ * each string or file specification into a compiled program structure.
+ */
+ for (i = 0; i < g_cmdc; i++)
+ g_cmdv[i].dc_func(&g_cmdv[i]);
+
+ if (g_mode != DMODE_LIST) {
+ if (dtrace_handle_err(g_dtp, &errhandler, NULL) == -1)
+ dfatal("failed to establish error handler");
+
+ if (dtrace_handle_drop(g_dtp, &drophandler, NULL) == -1)
+ dfatal("failed to establish drop handler");
+
+ if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1)
+ dfatal("failed to establish proc handler");
+
+ if (dtrace_handle_setopt(g_dtp, &setopthandler, NULL) == -1)
+ dfatal("failed to establish setopt handler");
+
+ if (g_ofp == NULL &&
+ dtrace_handle_buffered(g_dtp, &bufhandler, NULL) == -1)
+ dfatal("failed to establish buffered handler");
+ }
+
+ (void) dtrace_getopt(g_dtp, "flowindent", &opt);
+ g_flowindent = opt != DTRACEOPT_UNSET;
+
+ (void) dtrace_getopt(g_dtp, "grabanon", &opt);
+ g_grabanon = opt != DTRACEOPT_UNSET;
+
+ (void) dtrace_getopt(g_dtp, "quiet", &opt);
+ g_quiet = opt != DTRACEOPT_UNSET;
+
+ /*
+ * Now make a fifth and final pass over the options that have been
+ * turned into programs and saved in g_cmdv[], performing any mode-
+ * specific processing. If g_mode is DMODE_EXEC, we will break out
+ * of the switch() and continue on to the data processing loop. For
+ * other modes, we will exit dtrace once mode-specific work is done.
+ */
+ switch (g_mode) {
+ case DMODE_EXEC:
+ if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL)
+ fatal("failed to open output file '%s'", g_ofile);
+
+ for (i = 0; i < g_cmdc; i++)
+ exec_prog(&g_cmdv[i]);
+
+ if (done && !g_grabanon) {
+ dtrace_close(g_dtp);
+ return (g_status);
+ }
+ break;
+
+ case DMODE_ANON:
+ if (g_ofile == NULL)
+#ifdef illumos
+ g_ofile = "/kernel/drv/dtrace.conf";
+#else
+ /*
+ * On FreeBSD, anonymous DOF data is written to
+ * the DTrace DOF file.
+ */
+ g_ofile = "/boot/dtrace.dof";
+#endif
+
+ dof_prune(g_ofile); /* strip out any old DOF directives */
+#ifdef illumos
+ etcsystem_prune(); /* string out any forceload directives */
+#endif
+
+ if (g_cmdc == 0) {
+ dtrace_close(g_dtp);
+ return (g_status);
+ }
+
+ if ((g_ofp = fopen(g_ofile, "a")) == NULL)
+ fatal("failed to open output file '%s'", g_ofile);
+
+ for (i = 0; i < g_cmdc; i++) {
+ anon_prog(&g_cmdv[i],
+ dtrace_dof_create(g_dtp, g_cmdv[i].dc_prog, 0), i);
+ }
+
+ /*
+ * Dump out the DOF corresponding to the error handler and the
+ * current options as the final DOF property in the .conf file.
+ */
+ anon_prog(NULL, dtrace_geterr_dof(g_dtp), i++);
+ anon_prog(NULL, dtrace_getopt_dof(g_dtp), i++);
+
+ if (fclose(g_ofp) == EOF)
+ fatal("failed to close output file '%s'", g_ofile);
+
+ /*
+ * These messages would use notice() rather than error(), but
+ * we don't want them suppressed when -A is run on a D program
+ * that itself contains a #pragma D option quiet.
+ */
+ error("saved anonymous enabling in %s\n", g_ofile);
+
+#ifdef __FreeBSD__
+ bootdof_add();
+#else
+ etcsystem_add();
+ error("run update_drv(1M) or reboot to enable changes\n");
+#endif
+
+ dtrace_close(g_dtp);
+ return (g_status);
+
+ case DMODE_LINK:
+ if (g_cmdc == 0) {
+ (void) fprintf(stderr, "%s: -G requires one or more "
+ "scripts or enabling options\n", g_pname);
+ dtrace_close(g_dtp);
+ return (E_USAGE);
+ }
+
+ for (i = 0; i < g_cmdc; i++)
+ link_prog(&g_cmdv[i]);
+
+ if (g_cmdc > 1 && g_ofile != NULL) {
+ char **objv = alloca(g_cmdc * sizeof (char *));
+
+ for (i = 0; i < g_cmdc; i++)
+ objv[i] = g_cmdv[i].dc_ofile;
+
+ if (dtrace_program_link(g_dtp, NULL, DTRACE_D_PROBES,
+ g_ofile, g_cmdc, objv) != 0)
+ dfatal(NULL); /* dtrace_errmsg() only */
+ }
+
+ dtrace_close(g_dtp);
+ return (g_status);
+
+ case DMODE_LIST:
+ if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL)
+ fatal("failed to open output file '%s'", g_ofile);
+
+ installsighands();
+
+ oprintf("%5s %10s %17s %33s %s\n",
+ "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME");
+
+ for (i = 0; i < g_cmdc; i++)
+ list_prog(&g_cmdv[i]);
+
+ if (g_cmdc == 0)
+ (void) dtrace_probe_iter(g_dtp, NULL, list_probe, NULL);
+
+ dtrace_close(g_dtp);
+ return (g_status);
+
+ case DMODE_HEADER:
+ if (g_cmdc == 0) {
+ (void) fprintf(stderr, "%s: -h requires one or more "
+ "scripts or enabling options\n", g_pname);
+ dtrace_close(g_dtp);
+ return (E_USAGE);
+ }
+
+ if (g_ofile == NULL) {
+ char *p;
+
+ if (g_cmdc > 1) {
+ (void) fprintf(stderr, "%s: -h requires an "
+ "output file if multiple scripts are "
+ "specified\n", g_pname);
+ dtrace_close(g_dtp);
+ return (E_USAGE);
+ }
+
+ if ((p = strrchr(g_cmdv[0].dc_arg, '.')) == NULL ||
+ strcmp(p, ".d") != 0) {
+ (void) fprintf(stderr, "%s: -h requires an "
+ "output file if no scripts are "
+ "specified\n", g_pname);
+ dtrace_close(g_dtp);
+ return (E_USAGE);
+ }
+
+ p[0] = '\0'; /* strip .d suffix */
+ g_ofile = p = g_cmdv[0].dc_ofile;
+ (void) snprintf(p, sizeof (g_cmdv[0].dc_ofile),
+ "%s.h", basename(g_cmdv[0].dc_arg));
+ }
+
+ if ((g_ofp = fopen(g_ofile, "w")) == NULL)
+ fatal("failed to open header file '%s'", g_ofile);
+
+ oprintf("/*\n * Generated by dtrace(1M).\n */\n\n");
+
+ if (dtrace_program_header(g_dtp, g_ofp, g_ofile) != 0 ||
+ fclose(g_ofp) == EOF)
+ dfatal("failed to create header file %s", g_ofile);
+
+ dtrace_close(g_dtp);
+ return (g_status);
+ }
+
+ /*
+ * If -a and -Z were not specified and no probes have been matched, no
+ * probe criteria was specified on the command line and we abort.
+ */
+ if (g_total == 0 && !g_grabanon && !(g_cflags & DTRACE_C_ZDEFS))
+ dfatal("no probes %s\n", g_cmdc ? "matched" : "specified");
+
+ /*
+ * Start tracing. Once we dtrace_go(), reload any options that affect
+ * our globals in case consuming anonymous state has changed them.
+ */
+ go();
+
+ (void) dtrace_getopt(g_dtp, "flowindent", &opt);
+ g_flowindent = opt != DTRACEOPT_UNSET;
+
+ (void) dtrace_getopt(g_dtp, "grabanon", &opt);
+ g_grabanon = opt != DTRACEOPT_UNSET;
+
+ (void) dtrace_getopt(g_dtp, "quiet", &opt);
+ g_quiet = opt != DTRACEOPT_UNSET;
+
+ (void) dtrace_getopt(g_dtp, "destructive", &opt);
+ if (opt != DTRACEOPT_UNSET)
+ notice("allowing destructive actions\n");
+
+ installsighands();
+
+ /*
+ * Now that tracing is active and we are ready to consume trace data,
+ * continue any grabbed or created processes, setting them running
+ * using the /proc control mechanism inside of libdtrace.
+ */
+ for (i = 0; i < g_psc; i++)
+ dtrace_proc_continue(g_dtp, g_psv[i]);
+
+ g_pslive = g_psc; /* count for prochandler() */
+
+ do {
+ if (!g_intr && !done)
+ dtrace_sleep(g_dtp);
+
+#ifdef __FreeBSD__
+ if (g_siginfo) {
+ (void)dtrace_aggregate_print(g_dtp, g_ofp, NULL);
+ g_siginfo = 0;
+ }
+#endif
+
+ if (g_newline) {
+ /*
+ * Output a newline just to make the output look
+ * slightly cleaner. Note that we do this even in
+ * "quiet" mode...
+ */
+ oprintf("\n");
+ g_newline = 0;
+ }
+
+ if (done || g_intr || (g_psc != 0 && g_pslive == 0)) {
+ done = 1;
+ if (dtrace_stop(g_dtp) == -1)
+ dfatal("couldn't stop tracing");
+ }
+
+ switch (dtrace_work(g_dtp, g_ofp, chew, chewrec, NULL)) {
+ case DTRACE_WORKSTATUS_DONE:
+ done = 1;
+ break;
+ case DTRACE_WORKSTATUS_OKAY:
+ break;
+ default:
+ if (!g_impatient && dtrace_errno(g_dtp) != EINTR)
+ dfatal("processing aborted");
+ }
+
+ if (g_ofp != NULL && fflush(g_ofp) == EOF)
+ clearerr(g_ofp);
+ } while (!done);
+
+ oprintf("\n");
+
+ if (!g_impatient) {
+ if (dtrace_aggregate_print(g_dtp, g_ofp, NULL) == -1 &&
+ dtrace_errno(g_dtp) != EINTR)
+ dfatal("failed to print aggregations");
+ }
+
+ dtrace_close(g_dtp);
+ return (g_status);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/README b/cddl/contrib/opensolaris/cmd/dtrace/test/README
new file mode 100644
index 000000000000..51ab650fd7d3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/README
@@ -0,0 +1,32 @@
+
+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 2006 Sun Microsystems, Inc. All rights reserved.
+Use is subject to license terms.
+
+ident "%Z%%M% %I% %E% SMI"
+
+DTrace Testing Suite
+
+The SUNWdtrt package delivers a set of test programs and D source
+files into the directory /opt/SUNWdtrt. For more information see
+the following web site:
+
+ http://www.opensolaris.org/os/community/dtrace/dtest
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/baddof/baddof.c b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/baddof/baddof.c
new file mode 100644
index 000000000000..1c14c6592c88
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/baddof/baddof.c
@@ -0,0 +1,207 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/varargs.h>
+#include <errno.h>
+#include <math.h>
+#include <dtrace.h>
+
+void
+fatal(char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ fprintf(stderr, "%s: ", "baddof");
+ vfprintf(stderr, fmt, ap);
+
+ if (fmt[strlen(fmt) - 1] != '\n')
+ fprintf(stderr, ": %s\n", strerror(errno));
+
+ exit(1);
+}
+
+#define LEAP_DISTANCE 20
+
+void
+corrupt(int fd, unsigned char *buf, int len)
+{
+ static int ttl, valid;
+ int bit, i;
+ unsigned char saved;
+ int val[LEAP_DISTANCE], pos[LEAP_DISTANCE];
+ int new, rv;
+
+again:
+ printf("valid DOF #%d\n", valid++);
+
+ /*
+ * We are going iterate through, flipping one bit and attempting
+ * to enable.
+ */
+ for (bit = 0; bit < len * 8; bit++) {
+ saved = buf[bit / 8];
+ buf[bit / 8] ^= (1 << (bit % 8));
+
+ if ((bit % 100) == 0)
+ printf("%d\n", bit);
+
+ if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) == -1) {
+ /*
+ * That failed -- restore the bit and drive on.
+ */
+ buf[bit / 8] = saved;
+ continue;
+ }
+
+ /*
+ * That worked -- and it may have enabled probes. To keep
+ * enabled probes down to a reasonable level, we'll close
+ * and reopen pseudodevice if we have more than 10,000
+ * probes enabled.
+ */
+ ttl += rv;
+
+ if (ttl < 10000) {
+ buf[bit / 8] = saved;
+ continue;
+ }
+
+ printf("enabled %d probes; resetting device.\n", ttl);
+ close(fd);
+
+ new = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR);
+
+ if (new == -1)
+ fatal("couldn't open DTrace pseudo device");
+
+ if (new != fd) {
+ dup2(new, fd);
+ close(new);
+ }
+
+ ttl = 0;
+ buf[bit / 8] = saved;
+ }
+
+ for (;;) {
+ /*
+ * Now we want to get as many bits away as possible. We flip
+ * bits randomly -- getting as far away as we can until we don't
+ * seem to be making any progress.
+ */
+ for (i = 0; i < LEAP_DISTANCE; i++) {
+ /*
+ * Pick a random bit and corrupt it.
+ */
+ bit = lrand48() % (len * 8);
+
+ val[i] = buf[bit / 8];
+ pos[i] = bit / 8;
+ buf[bit / 8] ^= (1 << (bit % 8));
+ }
+
+ /*
+ * Let's see if that managed to get us valid DOF...
+ */
+ if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) > 0) {
+ /*
+ * Success! This will be our new base for valid DOF.
+ */
+ ttl += rv;
+ goto again;
+ }
+
+ /*
+ * No luck -- we'll restore those bits and try flipping a
+ * different set. Note that this must be done in reverse
+ * order...
+ */
+ for (i = LEAP_DISTANCE - 1; i >= 0; i--)
+ buf[pos[i]] = val[i];
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ char *filename = argv[1];
+ dtrace_hdl_t *dtp;
+ dtrace_prog_t *pgp;
+ int err, fd, len;
+ FILE *fp;
+ unsigned char *dof, *copy;
+
+ if (argc < 2)
+ fatal("expected D script as argument\n");
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ fatal("couldn't open %s", filename);
+
+ /*
+ * First, we need to compile our provided D into DOF.
+ */
+ if ((dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
+ fatal("cannot open dtrace library: %s\n",
+ dtrace_errmsg(NULL, err));
+ }
+
+ pgp = dtrace_program_fcompile(dtp, fp, 0, 0, NULL);
+ fclose(fp);
+
+ if (pgp == NULL) {
+ fatal("failed to compile script %s: %s\n", filename,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ dof = dtrace_dof_create(dtp, pgp, 0);
+ len = ((dof_hdr_t *)dof)->dofh_loadsz;
+
+ if ((copy = malloc(len)) == NULL)
+ fatal("could not allocate copy of %d bytes", len);
+
+ for (;;) {
+ bcopy(dof, copy, len);
+ /*
+ * Open another instance of the dtrace device.
+ */
+ fd = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR);
+
+ if (fd == -1)
+ fatal("couldn't open DTrace pseudo device");
+
+ corrupt(fd, copy, len);
+ close(fd);
+ }
+
+ /* NOTREACHED */
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/badioctl/badioctl.c b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/badioctl/badioctl.c
new file mode 100644
index 000000000000..8d6833d52173
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/badioctl/badioctl.c
@@ -0,0 +1,145 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/varargs.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define DTRACEIOC (('d' << 24) | ('t' << 16) | ('r' << 8))
+#define DTRACEIOC_MAX 17
+
+void
+fatal(char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ fprintf(stderr, "%s: ", "badioctl");
+ vfprintf(stderr, fmt, ap);
+
+ if (fmt[strlen(fmt) - 1] != '\n')
+ fprintf(stderr, ": %s\n", strerror(errno));
+
+ exit(1);
+}
+
+void
+badioctl(pid_t parent)
+{
+ int fd = -1, random, ps = sysconf(_SC_PAGESIZE);
+ int i = 0, seconds;
+ caddr_t addr;
+ hrtime_t now, last = 0, end;
+
+ if ((random = open("/dev/random", O_RDONLY)) == -1)
+ fatal("couldn't open /dev/random");
+
+ if ((addr = mmap(0, ps, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0)) == (caddr_t)-1)
+ fatal("mmap");
+
+ for (;;) {
+ unsigned int ioc;
+
+ if ((now = gethrtime()) - last > NANOSEC) {
+ if (kill(parent, 0) == -1 && errno == ESRCH) {
+ /*
+ * Our parent died. We will kill ourselves in
+ * sympathy.
+ */
+ exit(0);
+ }
+
+ /*
+ * Once a second, we'll reopen the device.
+ */
+ if (fd != -1)
+ close(fd);
+
+ fd = open("/devices/pseudo/dtrace@0:dtrace", O_RDONLY);
+
+ if (fd == -1)
+ fatal("couldn't open DTrace pseudo device");
+
+ last = now;
+ }
+
+
+ if ((i++ % 1000) == 0) {
+ /*
+ * Every thousand iterations, change our random gunk.
+ */
+ read(random, addr, ps);
+ }
+
+ read(random, &ioc, sizeof (ioc));
+ ioc %= DTRACEIOC_MAX;
+ ioc++;
+ ioctl(fd, DTRACEIOC | ioc, addr);
+ }
+}
+
+int
+main()
+{
+ pid_t child, parent = getpid();
+ int status;
+
+ for (;;) {
+ if ((child = fork()) == 0)
+ badioctl(parent);
+
+ while (waitpid(child, &status, WEXITED) != child)
+ continue;
+
+ if (WIFEXITED(status)) {
+ /*
+ * Our child exited by design -- we'll exit with
+ * the same status code.
+ */
+ exit(WEXITSTATUS(status));
+ }
+
+ /*
+ * Our child died on a signal. Respawn it.
+ */
+ printf("badioctl: child died on signal %d; respawning.\n",
+ WTERMSIG(status));
+ fflush(stdout);
+ }
+
+ /* NOTREACHED */
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/chkargs/chkargs.c b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/chkargs/chkargs.c
new file mode 100644
index 000000000000..a7e0222fd0ea
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/chkargs/chkargs.c
@@ -0,0 +1,149 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <strings.h>
+#include <unistd.h>
+#include <dtrace.h>
+
+static int g_count;
+static int g_errs;
+static int g_fd;
+static int g_verbose;
+static int g_errexit;
+static char *g_progname;
+
+static int
+probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *data)
+{
+ dtrace_probeinfo_t p;
+ dtrace_argdesc_t arg;
+ char buf[BUFSIZ];
+ int i;
+
+ (void) printf("\r%6d", ++g_count);
+ (void) fflush(stdout);
+
+ if (dtrace_probe_info(dtp, pdp, &p) != 0) {
+ (void) printf(" failed to get probe info for "
+ "%s:%s:%s:%s [%d]\n", pdp->dtpd_provider, pdp->dtpd_mod,
+ pdp->dtpd_func, pdp->dtpd_name, pdp->dtpd_id);
+ g_errs++;
+ return (0);
+ }
+
+ for (i = 0; i < p.dtp_argc; i++) {
+ if (p.dtp_argv[i].dtt_type == CTF_ERR) {
+ bzero(&arg, sizeof (dtrace_argdesc_t));
+ arg.dtargd_id = pdp->dtpd_id;
+ arg.dtargd_ndx = i;
+ (void) ioctl(g_fd, DTRACEIOC_PROBEARG, &arg);
+
+ (void) printf(" failed to get types for args[%d] "
+ "of %s:%s:%s:%s [%d]: <%s> -> <%s>\n", i,
+ pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func,
+ pdp->dtpd_name, pdp->dtpd_id,
+ arg.dtargd_native, arg.dtargd_xlate);
+
+ g_errs++;
+
+ if (g_errexit)
+ return (-1);
+
+ } else if (g_verbose) {
+ (void) printf("%d args[%d] : %s\n", pdp->dtpd_id, i,
+ ctf_type_name(p.dtp_argv[i].dtt_ctfp,
+ p.dtp_argv[i].dtt_type, buf, sizeof (buf)));
+ }
+ }
+
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ dtrace_probedesc_t pd, *pdp = NULL;
+ dtrace_hdl_t *dtp;
+ int err, c;
+ char *p;
+
+ g_progname = argv[0];
+
+ if ((dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
+ (void) fprintf(stderr, "%s: failed to open dtrace: %s\n",
+ g_progname, dtrace_errmsg(dtp, err));
+ return (1);
+ }
+
+ while ((c = getopt(argc, argv, "evx:")) != -1) {
+ switch (c) {
+ case 'e':
+ g_errexit++;
+ break;
+ case 'v':
+ g_verbose++;
+ break;
+ case 'x':
+ if ((p = strchr(optarg, '=')) != NULL)
+ *p++ = '\0';
+
+ if (dtrace_setopt(dtp, optarg, p) != 0) {
+ (void) fprintf(stderr, "%s: failed to set "
+ "option -x %s: %s\n", g_progname, optarg,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ return (2);
+ }
+ break;
+
+ default:
+ (void) fprintf(stderr, "Usage: %s [-ev] "
+ "[-x opt[=arg]] [probedesc]\n", g_progname);
+ return (2);
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc > 0) {
+ if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, argv[0], &pd)) {
+ (void) fprintf(stderr, "%s: invalid probe description "
+ "%s: %s\n", g_progname, argv[0],
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ return (2);
+ }
+ pdp = &pd;
+ }
+
+ g_fd = dtrace_ctlfd(dtp);
+ (void) dtrace_probe_iter(dtp, pdp, probe, NULL);
+ dtrace_close(dtp);
+
+ (void) printf("\nTotal probes: %d\n", g_count);
+ (void) printf("Total errors: %d\n\n", g_errs);
+
+ return (g_errs != 0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/Getopt.java b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/Getopt.java
new file mode 100644
index 000000000000..e06a170d6a88
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/Getopt.java
@@ -0,0 +1,453 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+import java.io.StringWriter;
+import java.io.PrintWriter;
+
+/**
+ * A Java port of Solaris {@code lib/libc/port/gen/getopt.c}, which is a
+ * port of System V UNIX getopt. See <b>getopt(3C)</b> and SUS/XPG
+ * getopt() for function definition and requirements. Unlike that
+ * definition, this implementation moves non-options to the end of the
+ * argv array rather than quitting at the first non-option.
+ */
+public class Getopt {
+ static final int EOF = -1;
+
+ private String progname;
+ private String[] args;
+ private int argc;
+ private String optstring;
+ private int optind = 0; // args index
+ private int optopt = 0;
+ private String optarg = null;
+ private boolean opterr = true;
+
+ /*
+ * _sp is required to keep state between successive calls to
+ * getopt() while extracting aggregated short-options (ie: -abcd).
+ */
+ private int _sp = 1;
+
+ /**
+ * Creates a {Code Getopt} instance to parse the given command-line
+ * arguments. Modifies the given args array by swapping the
+ * positions of non-options and options so that non-options appear
+ * at the end of the array.
+ */
+ public Getopt(String programName, String[] args,
+ String optionString)
+ {
+ progname = programName;
+ // No defensive copy; Getopt is expected to modify the given
+ // args array
+ this.args = args;
+ argc = this.args.length;
+ optstring = optionString;
+ validate();
+ }
+
+ private void
+ validate()
+ {
+ if (progname == null) {
+ throw new NullPointerException("program name is null");
+ }
+ int i = 0;
+ for (String s : args) {
+ if (s == null) {
+ throw new NullPointerException("null arg at index " + i);
+ }
+ ++i;
+ }
+ if (optstring == null) {
+ throw new NullPointerException("option string is null");
+ }
+ }
+
+ private static class StringRef {
+ private String s;
+
+ public String
+ get()
+ {
+ return s;
+ }
+
+ public StringRef
+ set(String value)
+ {
+ s = value;
+ return this;
+ }
+ }
+
+ /*
+ * Generalized error processing method. If the optstr parameter is
+ * null, the character c is converted to a string and displayed
+ * instead.
+ */
+ void
+ err(String format, char c, String optstr)
+ {
+ if (opterr && optstring.charAt(0) != ':') {
+ StringWriter w = new StringWriter();
+ PrintWriter p = new PrintWriter(w);
+ p.printf(format, progname, (optstr == null ?
+ Character.toString(c) : optstr.substring(2)));
+ System.err.println(w.toString());
+ }
+ }
+
+ /*
+ * Determine if the specified character (c) is present in the string
+ * (optstring) as a regular, single character option. If the option
+ * is found, return an index into optstring where the short-option
+ * character is found, otherwise return -1. The characters ':' and
+ * '(' are not allowed.
+ */
+ static int
+ parseshort(String optstring, char c)
+ {
+ if (c == ':' || c == '(') {
+ return -1;
+ }
+
+ int ch;
+ int len = optstring.length();
+ for (int i = 0; i < len; ++i) {
+ ch = optstring.charAt(i);
+ if (ch == c) {
+ return i;
+ }
+
+ while (i < len && ch == '(') {
+ for (++i; i < len && (ch = optstring.charAt(i)) != ')'; ++i);
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Determine if the specified string (opt) is present in the string
+ * (optstring) as a long-option contained within parenthesis. If the
+ * long-option specifies option-argument, return a reference to it
+ * in longoptarg. Otherwise set the longoptarg reference to null.
+ * If the option is found, return an index into optstring at the
+ * position of the short-option character associated with the
+ * long-option; otherwise return -1.
+ *
+ * @param optstring the entire optstring passed to the {@code
+ * Getopt} constructor
+ * @param opt the long option read from the command line
+ * @param longoptarg the value of the option is returned in this
+ * parameter, if an option exists. Possible return values in
+ * longoptarg are:
+ * <ul>
+ * <li><b>NULL:</b> No argument was found</li>
+ * <li><b>empty string (""):</b> Argument was explicitly left empty
+ * by the user (e.g., --option= )</li>
+ * <li><b>valid string:</b> Argument found on the command line</li>
+ * </ul>
+ * @return index to equivalent short-option in optstring, or -1 if
+ * option not found in optstring.
+ */
+ static int
+ parselong(String optstring, String opt, StringRef longoptarg)
+ {
+ int cp; // index into optstring, beginning of one option spec
+ int ip; // index into optstring, traverses every char
+ char ic; // optstring char
+ int il; // optstring length
+ int op; // index into opt
+ char oc; // opt char
+ int ol; // opt length
+ boolean match; // true if opt is matching part of optstring
+
+ longoptarg.set(null);
+ cp = ip = 0;
+ il = optstring.length();
+ ol = opt.length();
+ do {
+ ic = optstring.charAt(ip);
+ if (ic != '(' && ++ip == il)
+ break;
+ ic = optstring.charAt(ip);
+ if (ic == ':' && ++ip == il)
+ break;
+ ic = optstring.charAt(ip);
+ while (ic == '(') {
+ if (++ip == il)
+ break;
+ op = 0;
+ match = true;
+ while (ip < il && (ic = optstring.charAt(ip)) != ')' &&
+ op < ol) {
+ oc = opt.charAt(op++);
+ match = (ic == oc && match);
+ ++ip;
+ }
+
+ if (match && ip < il && ic == ')' && (op >= ol ||
+ opt.charAt(op) == '=')) {
+ if (op < ol && opt.charAt(op) == '=') {
+ /* may be an empty string - OK */
+ longoptarg.set(opt.substring(op + 1));
+ } else {
+ longoptarg.set(null);
+ }
+ return cp;
+ }
+ if (ip < il && ic == ')' && ++ip == il)
+ break;
+ ic = optstring.charAt(ip);
+ }
+ cp = ip;
+ /*
+ * Handle double-colon in optstring ("a::(longa)") The old
+ * getopt() accepts it and treats it as a required argument.
+ */
+ while ((cp > 0) && (cp < il) && (optstring.charAt(cp) == ':')) {
+ --cp;
+ }
+ } while (cp < il);
+ return -1;
+ }
+
+ /**
+ * Get the current option value.
+ */
+ public String
+ getOptarg()
+ {
+ return optarg;
+ }
+
+ /**
+ * Get the index of the next option to be parsed.
+ */
+ public int
+ getOptind()
+ {
+ return optind;
+ }
+
+ /**
+ * Gets the command-line arguments.
+ */
+ public String[]
+ getArgv()
+ {
+ // No defensive copy: Getopt is expected to modify the given
+ // args array.
+ return args;
+ }
+
+ /**
+ * Gets the aggregated short option that just failed. Since long
+ * options can't be aggregated, a failed long option can be obtained
+ * by {@code getArgv()[getOptind() - 1]}.
+ */
+ public int
+ getOptopt()
+ {
+ return optopt;
+ }
+
+ /**
+ * Set to {@code false} to suppress diagnostic messages to stderr.
+ */
+ public void
+ setOpterr(boolean err)
+ {
+ opterr = err;
+ }
+
+ /**
+ * Gets the next option character, or -1 if there are no more
+ * options. If getopt() encounters a short-option character or a
+ * long-option string not described in the {@code optionString}
+ * argument to the constructor, it returns the question-mark (?)
+ * character. If it detects a missing option-argument, it also
+ * returns the question-mark (?) character, unless the first
+ * character of the {@code optionString} argument was a colon (:),
+ * in which case getopt() returns the colon (:) character.
+ * <p>
+ * This implementation swaps the positions of options and
+ * non-options in the given argv array.
+ */
+ public int
+ getopt()
+ {
+ char c;
+ int cp;
+ boolean longopt;
+ StringRef longoptarg = new StringRef();
+
+ /*
+ * Has the end of the options been encountered? The following
+ * implements the SUS requirements:
+ *
+ * If, when getopt() is called:
+ * - the first character of argv[optind] is not '-'
+ * - argv[optind] is the string "-"
+ * getopt() returns -1 without changing optind if
+ * - argv[optind] is the string "--"
+ * getopt() returns -1 after incrementing optind
+ */
+ if (_sp == 1) {
+ boolean nonOption;
+ do {
+ nonOption = false;
+ if (optind >= argc || args[optind].equals("-")) {
+ return EOF;
+ } else if (args[optind].equals("--")) {
+ ++optind;
+ return EOF;
+ } else if (args[optind].charAt(0) != '-') {
+ // non-option: here we deviate from the SUS requirements
+ // by not quitting, and instead move non-options to the
+ // end of the args array
+ nonOption = true;
+ String tmp = args[optind];
+ if (optind + 1 < args.length) {
+ System.arraycopy(args, optind + 1, args, optind,
+ args.length - (optind + 1));
+ args[args.length - 1] = tmp;
+ }
+ --argc;
+ }
+ } while (nonOption);
+ }
+
+ /*
+ * Getting this far indicates that an option has been encountered.
+ * Note that the syntax of optstring applies special meanings to
+ * the characters ':' and '(', so they are not permissible as
+ * option letters. A special meaning is also applied to the ')'
+ * character, but its meaning can be determined from context.
+ * Note that the specification only requires that the alnum
+ * characters be accepted.
+ *
+ * If the second character of the argument is a '-' this must be
+ * a long-option, otherwise it must be a short option. Scan for
+ * the option in optstring by the appropriate algorithm. Either
+ * scan will return an index to the short-option character in
+ * optstring if the option is found and -1 otherwise.
+ *
+ * For an unrecognized long-option, optopt will equal 0, but
+ * since long-options can't aggregate the failing option can be
+ * identified by argv[optind-1].
+ */
+ optopt = c = args[optind].charAt(_sp);
+ optarg = null;
+ longopt = (_sp == 1 && c == '-');
+ if (!(longopt
+ ? ((cp = parselong(optstring, args[optind].substring(2),
+ longoptarg)) != -1)
+ : ((cp = parseshort(optstring, c)) != -1))) {
+ err("%s: illegal option -- %s", c,
+ (longopt ? args[optind] : null));
+ /*
+ * Note: When the long option is unrecognized, optopt will
+ * be '-' here, which matches the specification.
+ */
+ if (args[optind].length() == ++_sp || longopt) {
+ ++optind;
+ _sp = 1;
+ }
+ return '?';
+ }
+ optopt = c = optstring.charAt(cp);
+
+ /*
+ * A valid option has been identified. If it should have an
+ * option-argument, process that now. SUS defines the setting
+ * of optarg as follows:
+ *
+ * 1. If the option was the last character in an element of
+ * argv, then optarg contains the next element of argv, and
+ * optind is incremented by 2. If the resulting value of
+ * optind is not less than argc, this indicates a missing
+ * option-argument, and getopt() returns an error indication.
+ *
+ * 2. Otherwise, optarg points to the string following the
+ * option character in that element of argv, and optind is
+ * incremented by 1.
+ *
+ * The second clause allows -abcd (where b requires an
+ * option-argument) to be interpreted as "-a -b cd".
+ *
+ * Note that the option-argument can legally be an empty string,
+ * such as:
+ * command --option= operand
+ * which explicitly sets the value of --option to nil
+ */
+ if (cp + 1 < optstring.length() && optstring.charAt(cp + 1) == ':') {
+ // The option takes an argument
+ if (!longopt && ((_sp + 1) < args[optind].length())) {
+ optarg = args[optind++].substring(_sp + 1);
+ } else if (longopt && (longoptarg.get() != null)) {
+ /*
+ * The option argument was explicitly set to the empty
+ * string on the command line (--option=)
+ */
+ optind++;
+ optarg = longoptarg.get();
+ } else if (++optind >= argc) {
+ err("%s: option requires an argument -- %s", c,
+ (longopt ? args[optind - 1] : null));
+ _sp = 1;
+ optarg = null;
+ return (optstring.charAt(0) == ':' ? ':' : '?');
+ } else
+ optarg = args[optind++];
+ _sp = 1;
+ } else {
+ // The option does NOT take an argument
+ if (longopt && (longoptarg.get() != null)) {
+ // User supplied an arg to an option that takes none
+ err("%s: option doesn't take an argument -- %s", (char)0,
+ (longopt ? args[optind] : null));
+ optarg = longoptarg.set(null).get();
+ c = '?';
+ }
+
+ if (longopt || args[optind].length() == ++_sp) {
+ _sp = 1;
+ ++optind;
+ }
+ optarg = null;
+ }
+ return (c);
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/JDTrace.java b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/JDTrace.java
new file mode 100644
index 000000000000..3c5654d88df5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/JDTrace.java
@@ -0,0 +1,1042 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+import org.opensolaris.os.dtrace.*;
+import java.io.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * Emulates {@code dtrace(1M)} using the Java DTrace API.
+ */
+public class JDTrace {
+ static Logger logger = Logger.getLogger(JDTrace.class.getName());
+
+ static Consumer dtrace;
+
+ static {
+ Handler handler = new ConsoleHandler();
+ handler.setLevel(Level.ALL);
+ logger.addHandler(handler);
+ }
+
+ static final String CLASSNAME = "JDTrace";
+ static final String OPTSTR =
+ "3:6:b:c:CD:ef:Fi:I:lL:m:n:o:p:P:qs:U:vVwx:X:Z";
+ static boolean heading = false;
+ static boolean quiet = false;
+ static boolean flow = false;
+ static int stackindent = 14;
+ static int exitStatus = 0;
+ static boolean started;
+ static boolean stopped;
+ static PrintStream out = System.out;
+ static final String ATS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
+ static final String SPACES = " ";
+ static final int QUANTIZE_ZERO_BUCKET = 63;
+
+ enum Mode {
+ EXEC,
+ INFO,
+ LIST,
+ VERSION
+ }
+
+ enum ProgramType {
+ STRING,
+ FILE
+ }
+
+ static class CompileRequest {
+ String s;
+ ProgramType type;
+ ProbeDescription.Spec probespec;
+ }
+
+ // Modify program string by expanding an incomplete probe
+ // description according to the requested probespec.
+ static void
+ applyProbespec(CompileRequest req)
+ {
+ ProbeDescription.Spec spec = ((req.probespec == null)
+ ? ProbeDescription.Spec.NAME
+ : req.probespec);
+
+ int colons = 0;
+ switch (req.probespec) {
+ case PROVIDER:
+ colons = 3;
+ break;
+ case MODULE:
+ colons = 2;
+ break;
+ case FUNCTION:
+ colons = 1;
+ break;
+ }
+
+ StringBuffer buf = new StringBuffer();
+ if (colons > 0) {
+ char ch;
+ int len = req.s.length();
+
+ int i = 0;
+ // Find first whitespace character not including leading
+ // whitespace (end of first token). Ignore whitespace
+ // inside a block if the block is concatenated with the
+ // probe description.
+ for (; (i < len) && Character.isWhitespace(req.s.charAt(i)); ++i);
+ int npos = i;
+ boolean inBlock = false;
+ for (; (npos < len) &&
+ (!Character.isWhitespace(ch = req.s.charAt(npos)) ||
+ inBlock); ++npos) {
+ if (ch == '{') {
+ inBlock = true;
+ } else if (ch == '}') {
+ inBlock = false;
+ }
+ }
+
+ // libdtrace lets you concatenate multiple probe
+ // descriptions separated by code blocks in curly braces,
+ // for example genunix::'{printf("FOUND");}'::entry, as long
+ // as the concatenated probe descriptions begin with ':' and
+ // not a specific field such as 'syscall'. So to expand the
+ // possibly multiple probe descriptions, we need to insert
+ // colons before each open curly brace, and again at the end
+ // only if there is at least one non-whitespace (probe
+ // specifying) character after the last closing curly brace.
+
+ int prev_i = 0;
+ while (i < npos) {
+ for (; (i < npos) && (req.s.charAt(i) != '{'); ++i);
+ buf.append(req.s.substring(prev_i, i));
+ if ((i < npos) || ((i > 0) && (req.s.charAt(i - 1) != '}'))) {
+ for (int c = 0; c < colons; ++c) {
+ buf.append(':');
+ }
+ }
+ if (i < npos) {
+ buf.append(req.s.charAt(i++));
+ }
+ prev_i = i;
+ }
+
+ // append remainder of program text
+ buf.append(req.s.substring(i));
+
+ req.s = buf.toString();
+ }
+ }
+
+ static void
+ printValue(Object value, int bytes, String stringFormat)
+ {
+ if (value instanceof Integer) {
+ if (bytes == 1) {
+ out.printf(" %3d", (Integer)value);
+ } else if (bytes == 2) {
+ out.printf(" %5d", (Integer)value);
+ } else {
+ out.printf(" %8d", (Integer)value);
+ }
+ } else if (value instanceof Long) {
+ out.printf(" %16d", (Long)value);
+ } else {
+ out.printf(stringFormat, value.toString());
+ }
+ }
+
+ static void
+ consumeProbeData(ProbeData data)
+ {
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer(data.toString());
+ }
+
+ if (!heading) {
+ if (flow) {
+ out.printf("%3s %-41s\n", "CPU", "FUNCTION");
+ } else {
+ if (!quiet) {
+ out.printf("%3s %6s %32s\n",
+ "CPU", "ID", "FUNCTION:NAME");
+ }
+ }
+ heading = true;
+ }
+ ProbeDescription probe = data.getEnabledProbeDescription();
+ if (flow) {
+ Flow flow = data.getFlow();
+ int indent = (flow.getDepth() * 2);
+ StringBuffer buf = new StringBuffer();
+ // indent
+ buf.append(' ');
+ for (int i = 0; i < indent; ++i) {
+ buf.append(' ');
+ }
+ // prefix
+ switch (flow.getKind()) {
+ case ENTRY:
+ if (indent == 0) {
+ buf.append("=> ");
+ } else {
+ buf.append("-> ");
+ }
+ break;
+ case RETURN:
+ if (indent == 0) {
+ buf.append("<= ");
+ } else {
+ buf.append("<- ");
+ }
+ break;
+ }
+
+ switch (flow.getKind()) {
+ case NONE:
+ buf.append(probe.getFunction());
+ buf.append(':');
+ buf.append(probe.getName());
+ break;
+ default:
+ buf.append(probe.getFunction());
+ }
+
+ out.printf("%3s %-41s ", data.getCPU(),
+ buf.toString());
+ } else {
+ if (!quiet) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(probe.getFunction());
+ buf.append(':');
+ buf.append(probe.getName());
+ out.printf("%3s %6s %32s ",
+ data.getCPU(), probe.getID(),
+ buf.toString());
+ }
+ }
+ Record record = null;
+ Object value;
+ List <Record> records = data.getRecords();
+ Iterator <Record> itr = records.iterator();
+ while (itr.hasNext()) {
+ record = itr.next();
+
+ if (record instanceof ExitRecord) {
+ exitStatus = ((ExitRecord)record).getStatus();
+ } else if (record instanceof ScalarRecord) {
+ ScalarRecord scalar = (ScalarRecord)record;
+ value = scalar.getValue();
+ if (value instanceof byte[]) {
+ out.print(record.toString());
+ } else {
+ if (quiet) {
+ out.print(value);
+ } else {
+ printValue(value, scalar.getNumberOfBytes(),
+ " %-33s");
+ }
+ }
+ } else if (record instanceof PrintfRecord) {
+ out.print(record);
+ } else if (record instanceof PrintaRecord) {
+ PrintaRecord printa = (PrintaRecord)record;
+ List <Tuple> tuples = printa.getTuples();
+ if (tuples.isEmpty()) {
+ out.print(printa.getOutput());
+ } else {
+ for (Tuple t : tuples) {
+ out.print(printa.getFormattedString(t));
+ }
+ }
+
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine(printa.toString());
+ }
+ } else if (record instanceof StackValueRecord) {
+ printStack((StackValueRecord)record);
+ }
+ }
+ if (!quiet) {
+ out.println();
+ }
+ }
+
+ static void
+ printDistribution(Distribution d)
+ {
+ out.printf("\n%16s %41s %-9s\n", "value",
+ "------------- Distribution -------------",
+ "count");
+ long v; // bucket frequency (value)
+ long b; // lower bound of bucket range
+ double total = 0;
+ boolean positives = false;
+ boolean negatives = false;
+
+ Distribution.Bucket bucket;
+ int b1 = 0; // first displayed bucket
+ int b2 = d.size() - 1; // last displayed bucket
+ for (; (b1 <= b2) && (d.get(b1).getFrequency() == 0); ++b1);
+ // If possible, get one bucket before the first non-zero
+ // bucket and one bucket after the last.
+ if (b1 > b2) {
+ // There isn't any data. This is possible if (and only if)
+ // negative increment values have been used. In this case,
+ // print the buckets around the base.
+ if (d instanceof LinearDistribution) {
+ b1 = 0;
+ b2 = 2;
+ } else {
+ b1 = QUANTIZE_ZERO_BUCKET - 1;
+ b2 = QUANTIZE_ZERO_BUCKET + 1;
+ }
+ } else {
+ if (b1 > 0) --b1;
+ for (; (b2 > 0) && (d.get(b2).getFrequency() == 0); --b2);
+ if (b2 < (d.size() - 1)) ++b2;
+ }
+ for (int i = b1; i <= b2; ++i) {
+ v = d.get(i).getFrequency();
+ if (v > 0) {
+ positives = true;
+ }
+ if (v < 0) {
+ negatives = true;
+ }
+ total += Math.abs((double)v);
+ }
+ for (int i = b1; i <= b2; ++i) {
+ bucket = d.get(i);
+ v = bucket.getFrequency();
+ b = bucket.getMin();
+
+ if (d instanceof LinearDistribution) {
+ if (b == Long.MIN_VALUE) {
+ String lt = "< " + ((LinearDistribution)d).getBase();
+ out.printf("%16s ", lt);
+ } else if (bucket.getMax() == Long.MAX_VALUE) {
+ String ge = ">= " + b;
+ out.printf("%16s ", ge);
+ } else {
+ out.printf("%16d ", b);
+ }
+ } else {
+ out.printf("%16d ", b);
+ }
+
+ printDistributionLine(v, total, positives, negatives);
+ }
+ }
+
+ static void
+ printDistributionLine(long val, double total, boolean positives,
+ boolean negatives)
+ {
+ double f;
+ int depth, len = 40;
+
+ assert (ATS.length() == len && SPACES.length() == len);
+ assert (!(total == 0 && (positives || negatives)));
+ assert (!(val < 0 && !negatives));
+ assert (!(val > 0 && !positives));
+ assert (!(val != 0 && total == 0));
+
+ if (!negatives) {
+ if (positives) {
+ f = (Math.abs((double)val) * (double)len) / total;
+ depth = (int)(f + 0.5);
+ } else {
+ depth = 0;
+ }
+
+ out.printf("|%s%s %-9d\n", ATS.substring(len - depth),
+ SPACES.substring(depth), val);
+ return;
+ }
+
+ if (!positives) {
+ f = (Math.abs((double)val) * (double)len) / total;
+ depth = (int)(f + 0.5);
+
+ out.printf("%s%s| %-9d\n", SPACES.substring(depth),
+ ATS.substring(len - depth), val);
+ return;
+ }
+
+ /*
+ * If we're here, we have both positive and negative bucket values.
+ * To express this graphically, we're going to generate both positive
+ * and negative bars separated by a centerline. These bars are half
+ * the size of normal quantize()/lquantize() bars, so we divide the
+ * length in half before calculating the bar length.
+ */
+ len /= 2;
+ String ats = ATS.substring(len);
+ String spaces = SPACES.substring(len);
+
+ f = (Math.abs((double)val) * (double)len) / total;
+ depth = (int)(f + 0.5);
+
+ if (val <= 0) {
+ out.printf("%s%s|%s %-9d\n", spaces.substring(depth),
+ ats.substring(len - depth), repeat(" ", len), val);
+ return;
+ } else {
+ out.printf("%20s|%s%s %-9d\n", "", ats.substring(len - depth),
+ spaces.substring(depth), val);
+ }
+ }
+
+ public static String
+ repeat(String s, int n)
+ {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < n; ++i) {
+ buf.append(s);
+ }
+ return buf.toString();
+ }
+
+ static void
+ printStack(StackValueRecord rec)
+ {
+ StackFrame[] frames = rec.getStackFrames();
+ int i;
+ out.println();
+ String s;
+ for (StackFrame f : frames) {
+ for (i = 0; i < stackindent; ++i) {
+ out.print(' ');
+ }
+ s = f.getFrame();
+ if (s.indexOf('[') == 0) {
+ out.print(" ");
+ }
+ out.println(s);
+ }
+ }
+
+ static void
+ printAggregate(Aggregate aggregate)
+ {
+ printAggregationRecords(aggregate.getOrderedRecords());
+ }
+
+ static void
+ printAggregationRecords(List <AggregationRecord> list)
+ {
+ Tuple tuple;
+ AggregationValue value;
+ ValueRecord tupleRecord;
+ int i;
+ int len;
+ for (AggregationRecord r : list) {
+ tuple = r.getTuple();
+ value = r.getValue();
+ len = tuple.size();
+ for (i = 0; i < len; ++i) {
+ tupleRecord = tuple.get(i);
+ if (tupleRecord instanceof StackValueRecord) {
+ printStack((StackValueRecord)tupleRecord);
+ } else if (tupleRecord instanceof SymbolValueRecord) {
+ printValue(tupleRecord.toString(), -1, " %-50s");
+ } else {
+ printValue(tupleRecord.getValue(),
+ ((ScalarRecord)tupleRecord).getNumberOfBytes(),
+ " %-50s");
+ }
+ }
+ if (value instanceof Distribution) {
+ Distribution d = (Distribution)value;
+ printDistribution(d);
+ } else {
+ Number v = value.getValue();
+ printValue(v, -1, " %-50s");
+ }
+ out.println();
+ }
+ }
+
+ static void
+ exit(int status)
+ {
+ out.flush();
+ System.err.flush();
+ if (status == 0) {
+ status = exitStatus;
+ }
+ System.exit(status);
+ }
+
+ static void
+ usage()
+ {
+ String predact = "[[ predicate ] action ]";
+ System.err.printf("Usage: java %s [-32|-64] [-CeFlqvVwZ] " +
+ "[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] " +
+ "[-o output] [-p pid] [-s script] [-U name]\n\t" +
+ "[-x opt[=val]] [-X a|c|s|t]\n\n" +
+ "\t[-P provider %s]\n" +
+ "\t[-m [ provider: ] module %s]\n" +
+ "\t[-f [[ provider: ] module: ] func %s]\n" +
+ "\t[-n [[[ provider: ] module: ] func: ] name %s]\n" +
+ "\t[-i probe-id %s] [ args ... ]\n\n", CLASSNAME,
+ predact, predact, predact, predact, predact);
+ System.err.printf("\tpredicate -> '/' D-expression '/'\n");
+ System.err.printf("\t action -> '{' D-statements '}'\n");
+ System.err.printf("\n" +
+ "\t-32 generate 32-bit D programs\n" +
+ "\t-64 generate 64-bit D programs\n\n" +
+ "\t-b set trace buffer size\n" +
+ "\t-c run specified command and exit upon its completion\n" +
+ "\t-C run cpp(1) preprocessor on script files\n" +
+ "\t-D define symbol when invoking preprocessor\n" +
+ "\t-e exit after compiling request but prior to enabling " +
+ "probes\n" +
+ "\t-f enable or list probes matching the specified " +
+ "function name\n" +
+ "\t-F coalesce trace output by function\n" +
+ "\t-i enable or list probes matching the specified probe id\n" +
+ "\t-I add include directory to preprocessor search path\n" +
+ "\t-l list probes matching specified criteria\n" +
+ "\t-L add library directory to library search path\n" +
+ "\t-m enable or list probes matching the specified " +
+ "module name\n" +
+ "\t-n enable or list probes matching the specified probe name\n" +
+ "\t-o set output file\n" +
+ "\t-p grab specified process-ID and cache its symbol tables\n" +
+ "\t-P enable or list probes matching the specified " +
+ "provider name\n" +
+ "\t-q set quiet mode (only output explicitly traced data)\n" +
+ "\t-s enable or list probes according to the specified " +
+ "D script\n" +
+ "\t-U undefine symbol when invoking preprocessor\n" +
+ "\t-v set verbose mode (report stability attributes, " +
+ "arguments)\n" +
+ "\t-V report DTrace API version\n" +
+ "\t-w permit destructive actions\n" +
+ "\t-x enable or modify compiler and tracing options\n" +
+ "\t-X specify ISO C conformance settings for preprocessor\n" +
+ "\t-Z permit probe descriptions that match zero probes\n" +
+ "\n" +
+ "\tTo log PrintaRecord, set this environment variable:\n" +
+ "\t\tJDTRACE_LOGGING_LEVEL=FINE\n" +
+ "\tTo log ProbeData, set JDTRACE_LOGGING_LEVEL=FINER\n");
+ exit(2);
+ }
+
+ static void
+ printProgramStability(String programType, String programDescription,
+ ProgramInfo info)
+ {
+ out.println();
+ out.printf("Stability data for %s %s:\n\n",
+ programType, programDescription);
+ InterfaceAttributes a;
+ out.println("\tMinimum probe description " +
+ "attributes");
+ a = info.getMinimumProbeAttributes();
+ out.printf("\t\tIdentifier Names: %s\n",
+ a.getNameStability());
+ out.printf("\t\tData Semantics: %s\n",
+ a.getDataStability());
+ out.printf("\t\tDependency Class: %s\n",
+ a.getDependencyClass());
+ out.println("\tMinimum probe statement attributes");
+ a = info.getMinimumStatementAttributes();
+ out.printf("\t\tIdentifier Names: %s\n",
+ a.getNameStability());
+ out.printf("\t\tData Semantics: %s\n",
+ a.getDataStability());
+ out.printf("\t\tDependency Class: %s\n",
+ a.getDependencyClass());
+ }
+
+ static void
+ printProbeDescription(ProbeDescription p)
+ {
+ out.printf("%5d %10s %17s %33s %s\n", p.getID(),
+ p.getProvider(), p.getModule(),
+ p.getFunction(), p.getName());
+ }
+
+ static void
+ printProbeInfo(ProbeInfo p)
+ {
+ InterfaceAttributes a;
+ out.println("\n\tProbe Description Attributes");
+
+ a = p.getProbeAttributes();
+ out.printf("\t\tIdentifier Names: %s\n",
+ a.getNameStability());
+ out.printf("\t\tData Semantics: %s\n",
+ a.getDataStability());
+ out.printf("\t\tDependency Class: %s\n",
+ a.getDependencyClass());
+
+ out.println("\n\tArgument Attributes");
+
+ a = p.getArgumentAttributes();
+ out.printf("\t\tIdentifier Names: %s\n",
+ a.getNameStability());
+ out.printf("\t\tData Semantics: %s\n",
+ a.getDataStability());
+ out.printf("\t\tDependency Class: %s\n",
+ a.getDependencyClass());
+
+ // Argument types unsupported for now.
+
+ out.println();
+ }
+
+ public static void
+ main(String[] args)
+ {
+ String loggingLevel = System.getenv().get("JDTRACE_LOGGING_LEVEL");
+ try {
+ logger.setLevel(Level.parse(loggingLevel));
+ } catch (Exception e) {
+ logger.setLevel(Level.OFF);
+ }
+
+ if (args.length == 0) {
+ usage();
+ }
+
+ List <CompileRequest> compileRequests = new LinkedList
+ <CompileRequest> ();
+ List <Program> programList = new LinkedList <Program> ();
+ boolean verbose = false;
+ Mode mode = Mode.EXEC;
+
+ final ExceptionHandler exceptionHandler = new ExceptionHandler() {
+ public void handleException(Throwable e) {
+ if (e instanceof DTraceException) {
+ DTraceException de = (DTraceException)e;
+ System.err.printf("dtrace: %s\n", de.getMessage());
+ } else if (e instanceof ConsumerException) {
+ ConsumerException ce = (ConsumerException)e;
+ Object msg = ce.getNotificationObject();
+ if ((msg instanceof org.opensolaris.os.dtrace.Error) ||
+ (msg instanceof Drop)) {
+ System.err.printf("dtrace: %s\n", ce.getMessage());
+ } else {
+ ce.printStackTrace();
+ }
+ } else {
+ e.printStackTrace();
+ }
+ exit(1);
+ }
+ };
+
+ Getopt g = new Getopt(CLASSNAME, args, OPTSTR);
+ int c = 0;
+
+ List <Consumer.OpenFlag> openFlags =
+ new ArrayList <Consumer.OpenFlag> ();
+
+ while ((c = g.getopt()) != -1) {
+ switch (c) {
+ case '3': {
+ String s = g.getOptarg();
+ if (!s.equals("2")) {
+ System.err.println("dtrace: illegal option -- 3" + s);
+ usage();
+ }
+ openFlags.add(Consumer.OpenFlag.ILP32);
+ break;
+ }
+ case '6': {
+ String s = g.getOptarg();
+ if (!s.equals("4")) {
+ System.err.println("dtrace: illegal option -- 6" + s);
+ usage();
+ }
+ openFlags.add(Consumer.OpenFlag.LP64);
+ break;
+ }
+ }
+ }
+
+ Consumer.OpenFlag[] oflags = new Consumer.OpenFlag[openFlags.size()];
+ oflags = openFlags.toArray(oflags);
+
+ dtrace = new LocalConsumer() {
+ protected Thread createThread() {
+ Thread t = super.createThread();
+ t.setDaemon(false);
+ t.setPriority(Thread.MIN_PRIORITY);
+ return t;
+ }
+ };
+
+ g = new Getopt(CLASSNAME, args, OPTSTR);
+ c = 0;
+
+ try {
+ dtrace.open(oflags);
+
+ // Set default options that may be overriden by options or #pragma
+ dtrace.setOption(Option.bufsize, Option.mb(4));
+ dtrace.setOption(Option.aggsize, Option.mb(4));
+
+ CompileRequest r;
+ while ((c = g.getopt()) != -1) {
+ switch (c) {
+ case 'b':
+ dtrace.setOption(Option.bufsize, g.getOptarg());
+ break;
+ case 'c':
+ dtrace.createProcess(g.getOptarg());
+ break;
+ case 'C':
+ dtrace.setOption(Option.cpp);
+ break;
+ case 'D':
+ dtrace.setOption(Option.define, g.getOptarg());
+ break;
+ case 'e':
+ mode = Mode.INFO;
+ break;
+ case 'f':
+ r = new CompileRequest();
+ r.s = g.getOptarg();
+ r.type = ProgramType.STRING;
+ r.probespec = ProbeDescription.Spec.FUNCTION;
+ compileRequests.add(r);
+ break;
+ case 'F':
+ dtrace.setOption(Option.flowindent);
+ break;
+ case 'i':
+ r = new CompileRequest();
+ r.s = g.getOptarg();
+ r.type = ProgramType.STRING;
+ r.probespec = ProbeDescription.Spec.NAME;
+ compileRequests.add(r);
+ break;
+ case 'I':
+ dtrace.setOption(Option.incdir, g.getOptarg());
+ break;
+ case 'l':
+ mode = Mode.LIST;
+ dtrace.setOption(Option.zdefs); // -l implies -Z
+ break;
+ case 'L':
+ dtrace.setOption(Option.libdir, g.getOptarg());
+ break;
+ case 'm':
+ r = new CompileRequest();
+ r.s = g.getOptarg();
+ r.type = ProgramType.STRING;
+ r.probespec = ProbeDescription.Spec.MODULE;
+ compileRequests.add(r);
+ break;
+ case 'n':
+ r = new CompileRequest();
+ r.s = g.getOptarg();
+ r.type = ProgramType.STRING;
+ r.probespec = ProbeDescription.Spec.NAME;
+ compileRequests.add(r);
+ break;
+ case 'o':
+ String outFileName = g.getOptarg();
+ File outFile = new File(outFileName);
+ try {
+ FileOutputStream fos = new FileOutputStream(
+ outFile, true);
+ out = new PrintStream(fos);
+ } catch (FileNotFoundException e) {
+ System.err.println("failed to open " +
+ outFileName + " in write mode");
+ exit(1);
+ } catch (SecurityException e) {
+ System.err.println("failed to open " +
+ outFileName);
+ exit(1);
+ }
+ break;
+ case 'p':
+ String pidstr = g.getOptarg();
+ int pid = -1;
+ try {
+ pid = Integer.parseInt(pidstr);
+ } catch (NumberFormatException e) {
+ System.err.println("invalid pid: " + pidstr);
+ exit(1);
+ }
+ dtrace.grabProcess(pid);
+ break;
+ case 'P':
+ r = new CompileRequest();
+ r.s = g.getOptarg();
+ r.type = ProgramType.STRING;
+ r.probespec = ProbeDescription.Spec.PROVIDER;
+ compileRequests.add(r);
+ break;
+ case 'q':
+ dtrace.setOption(Option.quiet);
+ break;
+ case 's':
+ r = new CompileRequest();
+ r.s = g.getOptarg();
+ r.type = ProgramType.FILE;
+ compileRequests.add(r);
+ break;
+ case 'U':
+ dtrace.setOption(Option.undef, g.getOptarg());
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'V':
+ mode = Mode.VERSION;
+ break;
+ case 'w':
+ dtrace.setOption(Option.destructive);
+ break;
+ case 'x':
+ String[] xarg = g.getOptarg().split("=", 2);
+ if (xarg.length > 1) {
+ dtrace.setOption(xarg[0], xarg[1]);
+ } else if (xarg.length == 1) {
+ dtrace.setOption(xarg[0]);
+ }
+ break;
+ case 'X':
+ dtrace.setOption(Option.stdc, g.getOptarg());
+ break;
+ case 'Z':
+ dtrace.setOption(Option.zdefs);
+ break;
+ case '?':
+ usage(); // getopt() already printed an error
+ break;
+ default:
+ System.err.print("getopt() returned " + c + "\n");
+ c = 0;
+ }
+ }
+ c = 0;
+ List <String> argList = new LinkedList <String> ();
+ for (int i = g.getOptind(); i < args.length; ++i) {
+ argList.add(args[i]);
+ }
+
+ if (mode == Mode.VERSION) {
+ out.printf("dtrace: %s\n", dtrace.getVersion());
+ dtrace.close();
+ exit(0);
+ }
+
+ String[] compileArgs = new String[argList.size()];
+ compileArgs = argList.toArray(compileArgs);
+
+ Program program;
+ for (CompileRequest req : compileRequests) {
+ switch (req.type) {
+ case STRING:
+ applyProbespec(req);
+ program = dtrace.compile(req.s, compileArgs);
+ break;
+ case FILE:
+ File file = new File(req.s);
+ program = dtrace.compile(file, compileArgs);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unexpected program type: " + req.type);
+ }
+
+ programList.add(program);
+ }
+
+ // Get options set by #pragmas in compiled program
+ long optval;
+ quiet = (dtrace.getOption(Option.quiet) != Option.UNSET);
+ flow = (dtrace.getOption(Option.flowindent) != Option.UNSET);
+ optval = dtrace.getOption("stackindent");
+ if (optval != Option.UNSET) {
+ stackindent = (int)optval;
+ }
+
+ if (mode == Mode.LIST) {
+ out.printf("%5s %10s %17s %33s %s\n",
+ "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME");
+
+ if (verbose) {
+ List <List <Probe>> lists =
+ new LinkedList <List <Probe>> ();
+ for (Program p : programList) {
+ lists.add(dtrace.listProgramProbeDetail(p));
+ }
+ ProbeDescription p;
+ ProbeInfo pinfo;
+ for (List <Probe> list : lists) {
+ for (Probe probe : list) {
+ p = probe.getDescription();
+ pinfo = probe.getInfo();
+ printProbeDescription(p);
+ printProbeInfo(pinfo);
+ }
+ }
+ } else {
+ List <List <ProbeDescription>> lists =
+ new LinkedList <List <ProbeDescription>> ();
+ for (Program p : programList) {
+ lists.add(dtrace.listProgramProbes(p));
+ }
+ for (List <ProbeDescription> list : lists) {
+ for (ProbeDescription p : list) {
+ printProbeDescription(p);
+ }
+ }
+ }
+ exit(0);
+ }
+
+ String programType;
+ String programDescription;
+ ProgramInfo info;
+ for (Program p : programList) {
+ if (p instanceof Program.File) {
+ Program.File pf = (Program.File)p;
+ programType = "script";
+ programDescription = pf.getFile().getPath();
+ } else {
+ programType = "description";
+ programDescription =
+ p.getContents().split("[/{;]", 2)[0];
+ }
+
+ if (mode == Mode.EXEC) {
+ dtrace.enable(p);
+ } else {
+ dtrace.getProgramInfo(p);
+ }
+ info = p.getInfo();
+ if ((mode == Mode.EXEC) && !quiet) {
+ System.err.printf("dtrace: %s '%s' matched %d probe%s\n",
+ programType, programDescription,
+ info.getMatchingProbeCount(),
+ info.getMatchingProbeCount() == 1 ? "" : "s");
+ }
+ if (verbose) {
+ printProgramStability(programType,
+ programDescription, info);
+ }
+ }
+ if (mode != Mode.EXEC) {
+ exit(0);
+ }
+ dtrace.addConsumerListener(new ConsumerAdapter() {
+ public void consumerStarted(ConsumerEvent e) {
+ started = true;
+ }
+ public void consumerStopped(ConsumerEvent e) {
+ stopped = true;
+ out.println();
+ try {
+ Aggregate aggregate = dtrace.getAggregate();
+ if (aggregate != null) {
+ printAggregate(aggregate);
+ }
+ dtrace.close();
+ } catch (Throwable x) {
+ exceptionHandler.handleException(x);
+ }
+ exit(0);
+ }
+ public void dataDropped(DropEvent e) {
+ System.err.printf("dtrace: %s",
+ e.getDrop().getDefaultMessage());
+ }
+ public void errorEncountered(ErrorEvent e)
+ throws ConsumerException {
+ org.opensolaris.os.dtrace.Error error = e.getError();
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine(error.toString());
+ }
+ System.err.printf("dtrace: %s",
+ error.getDefaultMessage());
+ }
+ public void dataReceived(DataEvent e)
+ throws ConsumerException {
+ consumeProbeData(e.getProbeData());
+ }
+ public void processStateChanged(ProcessEvent e)
+ throws ConsumerException {
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine(e.getProcessState().toString());
+ }
+ }
+ });
+ // Print unprinted aggregations after Ctrl-C
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ public void run() {
+ if (stopped || !started) {
+ return;
+ }
+
+ try {
+ Aggregate aggregate = dtrace.getAggregate();
+ if (aggregate != null) {
+ out.println();
+ out.println();
+ printAggregate(aggregate);
+ }
+ } catch (Throwable x) {
+ exceptionHandler.handleException(x);
+ }
+ }
+ });
+ dtrace.go(exceptionHandler);
+ } catch (DTraceException e) {
+ if (c > 0) {
+ // set option error
+ if (g.getOptarg() == null) {
+ System.err.printf("dtrace: failed to set -%c: %s\n",
+ c, e.getMessage());
+ } else {
+ System.err.printf("dtrace: failed to set -%c %s: %s\n",
+ c, g.getOptarg(), e.getMessage());
+ }
+ } else {
+ // any other error
+ System.err.printf("dtrace: %s\n", e.getMessage());
+ }
+ exit(1);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/exception.lst b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/exception.lst
new file mode 100644
index 000000000000..19fc3aca51c2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/exception.lst
@@ -0,0 +1,79 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# Exception list: names tests that are bypassed when running in Java
+# mode (relative to /opt/SUNWdtrt/tst)
+
+# double precision (64-bit floating point) not same in java
+common/aggs/tst.neglquant.d
+common/aggs/tst.negquant.d
+
+# freopen() (to suppress output) not supported by Java DTrace API
+common/printa/tst.walltimestamp.ksh
+
+# -G option not supported by jdtrace
+common/dtraceUtil/tst.ELFGenerationOut.d.ksh
+common/dtraceUtil/tst.ELFGenerationWithO.d.ksh
+
+# -H option not supported by jdtrace
+common/dtraceUtil/tst.PreprocessorStatement.d.ksh
+
+# -G and -h options not supported by jdtrace
+common/usdt/tst.badguess.ksh
+common/usdt/tst.dlclose1.ksh
+common/usdt/tst.dlclose2.ksh
+common/usdt/tst.dlclose3.ksh
+common/usdt/tst.eliminate.ksh
+common/usdt/tst.enabled.ksh
+common/usdt/tst.enabled2.ksh
+common/usdt/tst.entryreturn.ksh
+common/usdt/tst.fork.ksh
+common/usdt/tst.guess32.ksh
+common/usdt/tst.guess64.ksh
+common/usdt/tst.header.ksh
+common/usdt/tst.linkpriv.ksh
+common/usdt/tst.linkunpriv.ksh
+common/usdt/tst.multiple.ksh
+common/usdt/tst.nodtrace.ksh
+common/usdt/tst.noreap.ksh
+common/usdt/tst.noreapring.ksh
+common/usdt/tst.onlyenabled.ksh
+common/usdt/tst.reap.ksh
+common/usdt/tst.reeval.ksh
+common/usdt/tst.static.ksh
+common/usdt/tst.static2.ksh
+common/usdt/tst.user.ksh
+sparc/usdt/tst.tailcall.ksh
+common/pid/tst.provregex3.ksh
+common/pid/tst.provregex4.ksh
+
+# freopen() and ftruncate() not supported by Java DTrace API
+common/funcs/tst.badfreopen.ksh
+common/funcs/tst.freopen.ksh
+common/funcs/tst.ftruncate.ksh
+
+# jdtrace doesn't pull in library files?
+common/pragma/tst.libdepfullyconnected.ksh
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/jdtrace.c b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/jdtrace.c
new file mode 100644
index 000000000000..095126569cc1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/jdtrace.c
@@ -0,0 +1,60 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <alloca.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/systeminfo.h>
+
+int
+main(int argc, char **argv)
+{
+ int i, ac, has64;
+ char **av, **p;
+
+ ac = argc + 3;
+ av = p = alloca(sizeof (char *) * ac);
+
+ *p++ = "java";
+ *p++ = "-jar";
+ *p++ = "/opt/SUNWdtrt/lib/java/jdtrace.jar";
+
+ argc--;
+ argv++;
+
+ for (i = 0; i < argc; i++) {
+ p[i] = argv[i];
+ }
+ p[i] = NULL;
+
+ (void) execvp(av[0], av);
+
+ perror("exec failed");
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/manifest/jdtrace.jar-manifest b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/manifest/jdtrace.jar-manifest
new file mode 100644
index 000000000000..add47ebf4c8d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/manifest/jdtrace.jar-manifest
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: JDTrace
+Class-Path: /usr/share/lib/java/dtrace.jar
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl
new file mode 100755
index 000000000000..30b54d850733
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl
@@ -0,0 +1,240 @@
+#!/usr/local/bin/perl
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+#
+
+require 5.8.4;
+
+$PNAME = $0;
+$PNAME =~ s:.*/::;
+$USAGE = "Usage: $PNAME [file ...]\n";
+$errs = 0;
+
+sub err
+{
+ my($msg) = @_;
+
+ print "$file: $lineno: $msg\n";
+ $errs++;
+}
+
+sub dstyle
+{
+ open(FILE, "$file");
+ $lineno = 0;
+ $inclause = 0;
+ $skipnext = 0;
+
+ while (<FILE>) {
+ $lineno++;
+
+ chop;
+
+ if ($skipnext) {
+ $skipnext = 0;
+ next;
+ }
+
+ #
+ # Amazingly, some ident strings are longer than 80 characters!
+ #
+ if (/^#pragma ident/) {
+ next;
+ }
+
+ #
+ # The algorithm to calculate line length from cstyle.
+ #
+ $line = $_;
+ if ($line =~ tr/\t/\t/ * 7 + length($line) > 80) {
+ # yes, there is a chance.
+ # replace tabs with spaces and check again.
+ $eline = $line;
+ 1 while $eline =~
+ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
+
+ if (length($eline) > 80) {
+ err "line > 80 characters";
+ }
+ }
+
+ if (/\/\*DSTYLED\*\//) {
+ $skipnext = 1;
+ next;
+ }
+
+ if (/^#pragma/) {
+ next;
+ }
+
+ if (/^#include/) {
+ next;
+ }
+
+ #
+ # Before we do any more analysis, we want to prune out any
+ # quoted strings. This is a bit tricky because we need
+ # to be careful of backslashed quotes within quoted strings.
+ # I'm sure there is a very crafty way to do this with a
+ # single regular expression, but that will have to wait for
+ # somone with better regex juju that I; we do this by first
+ # eliminating the backslashed quotes, and then eliminating
+ # whatever quoted strings are left. Note that we eliminate
+ # the string by replacing it with "quotedstr"; this is to
+ # allow lines to end with a quoted string. (If we simply
+ # eliminated the quoted string, dstyle might complain about
+ # the line ending in a space or tab.)
+ #
+ s/\\\"//g;
+ s/\"[^\"]*\"/quotedstr/g;
+
+ if (/[ \t]$/) {
+ err "space or tab at end of line";
+ }
+
+ if (/^[\t]+[ ]+[\t]+/) {
+ err "spaces between tabs";
+ }
+
+ if (/^[\t]* \*/) {
+ next;
+ }
+
+ if (/^ /) {
+ err "indented by spaces not tabs";
+ }
+
+ if (/^{}$/) {
+ next;
+ }
+
+ if (!/^enum/ && !/^\t*struct/ && !/^\t*union/ && !/^typedef/ &&
+ !/^translator/ && !/^provider/ && !/\tif / &&
+ !/ else /) {
+ if (/[\w\s]+{/) {
+ err "left brace not on its own line";
+ }
+
+ if (/{[\w\s]+/) {
+ err "left brace not on its own line";
+ }
+ }
+
+ if (!/;$/ && !/\t*}$/ && !/ else /) {
+ if (/[\w\s]+}/) {
+ err "right brace not on its own line";
+ }
+
+ if (/}[\w\s]+/) {
+ err "right brace not on its own line";
+ }
+ }
+
+ if (/^}/) {
+ $inclause = 0;
+ }
+
+ if (!$inclause && /^[\w ]+\//) {
+ err "predicate not at beginning of line";
+ }
+
+ if (!$inclause && /^\/[ \t]+\w/) {
+ err "space between '/' and expression in predicate";
+ }
+
+ if (!$inclause && /\w[ \t]+\/$/) {
+ err "space between expression and '/' in predicate";
+ }
+
+ if (!$inclause && /\s,/) {
+ err "space before comma in probe description";
+ }
+
+ if (!$inclause && /\w,[\w\s]/ && !/;$/) {
+ if (!/extern/ && !/\(/ && !/inline/) {
+ err "multiple probe descriptions on same line";
+ }
+ }
+
+ if ($inclause && /sizeof\(/) {
+ err "missing space after sizeof";
+ }
+
+ if ($inclause && /^[\w ]/) {
+ err "line doesn't begin with a tab";
+ }
+
+ if ($inclause && /,[\w]/) {
+ err "comma without trailing space";
+ }
+
+ if (/\w&&/ || /&&\w/ || /\w\|\|/ || /\|\|\w/) {
+ err "logical operator not set off with spaces";
+ }
+
+ #
+ # We want to catch "i<0" variants, but we don't want to
+ # erroneously flag translators.
+ #
+ if (!/\w<\w+>\(/) {
+ if (/\w>/ || / >\w/ || /\w</ || /<\w/) {
+ err "comparison operator not set " .
+ "off with spaces";
+ }
+ }
+
+ if (/\w==/ || /==\w/ || /\w<=/ || />=\w/ || /\w!=/ || /!=\w/) {
+ err "comparison operator not set off with spaces";
+ }
+
+ if (/\w=/ || /=\w/) {
+ err "assignment operator not set off with spaces";
+ }
+
+ if (/^{/) {
+ $inclause = 1;
+ }
+ }
+}
+
+foreach $arg (@ARGV) {
+ if (-f $arg) {
+ push(@files, $arg);
+ } else {
+ die "$PNAME: $arg is not a valid file\n";
+ }
+}
+
+die $USAGE if (scalar(@files) == 0);
+
+foreach $file (@files) {
+ dstyle($file);
+}
+
+exit($errs != 0);
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dtest.pl b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dtest.pl
new file mode 100755
index 000000000000..d5a7244f8ebb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dtest.pl
@@ -0,0 +1,706 @@
+#!/usr/local/bin/perl
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+require 5.8.4;
+
+use File::Find;
+use File::Basename;
+use Getopt::Std;
+use Cwd;
+use Cwd 'abs_path';
+
+$PNAME = $0;
+$PNAME =~ s:.*/::;
+$OPTSTR = 'abd:fghi:jlnqsx:';
+$USAGE = "Usage: $PNAME [-abfghjlnqs] [-d dir] [-i isa] "
+ . "[-x opt[=arg]] [file | dir ...]\n";
+($MACH = `uname -p`) =~ s/\W*\n//;
+($PLATFORM = `uname -i`) =~ s/\W*\n//;
+
+@dtrace_argv = ();
+
+$ksh_path = '/usr/local/bin/ksh';
+
+@files = ();
+%exceptions = ();
+%results = ();
+$errs = 0;
+
+#
+# If no test files are specified on the command-line, execute a find on "."
+# and append any tst.*.d, tst.*.ksh, err.*.d or drp.*.d files found within
+# the directory tree.
+#
+sub wanted
+{
+ push(@files, $File::Find::name)
+ if ($_ =~ /^(tst|err|drp)\..+\.(d|ksh)$/ && -f "$_");
+}
+
+sub dirname {
+ my($s) = @_;
+ my($i);
+
+ $s = substr($s, 0, $i) if (($i = rindex($s, '/')) != -1);
+ return $i == -1 ? '.' : $i == 0 ? '/' : $s;
+}
+
+sub usage
+{
+ print $USAGE;
+ print "\t -a execute test suite using anonymous enablings\n";
+ print "\t -b execute bad ioctl test program\n";
+ print "\t -d specify directory for test results files and cores\n";
+ print "\t -g enable libumem debugging when running tests\n";
+ print "\t -f force bypassed tests to run\n";
+ print "\t -h display verbose usage message\n";
+ print "\t -i specify ISA to test instead of isaexec(3C) default\n";
+ print "\t -j execute test suite using jdtrace (Java API) only\n";
+ print "\t -l save log file of results and PIDs used by tests\n";
+ print "\t -n execute test suite using dtrace(1m) only\n";
+ print "\t -q set quiet mode (only report errors and summary)\n";
+ print "\t -s save results files even for tests that pass\n";
+ print "\t -x pass corresponding -x argument to dtrace(1M)\n";
+ exit(2);
+}
+
+sub errmsg
+{
+ my($msg) = @_;
+
+ print STDERR $msg;
+ print LOG $msg if ($opt_l);
+ $errs++;
+}
+
+sub fail
+{
+ my(@parms) = @_;
+ my($msg) = $parms[0];
+ my($errfile) = $parms[1];
+ my($n) = 0;
+ my($dest) = basename($file);
+
+ while (-d "$opt_d/failure.$n") {
+ $n++;
+ }
+
+ unless (mkdir "$opt_d/failure.$n") {
+ warn "ERROR: failed to make directory $opt_d/failure.$n: $!\n";
+ exit(125);
+ }
+
+ open(README, ">$opt_d/failure.$n/README");
+ print README "ERROR: " . $file . " " . $msg;
+
+ if (scalar @parms > 1) {
+ print README "; see $errfile\n";
+ } else {
+ if (-f "$opt_d/$pid.core") {
+ print README "; see $pid.core\n";
+ } else {
+ print README "\n";
+ }
+ }
+
+ close(README);
+
+ if (-f "$opt_d/$pid.out") {
+ rename("$opt_d/$pid.out", "$opt_d/failure.$n/$pid.out");
+ link("$file.out", "$opt_d/failure.$n/$dest.out");
+ }
+
+ if (-f "$opt_d/$pid.err") {
+ rename("$opt_d/$pid.err", "$opt_d/failure.$n/$pid.err");
+ link("$file.err", "$opt_d/failure.$n/$dest.err");
+ }
+
+ if (-f "$opt_d/$pid.core") {
+ rename("$opt_d/$pid.core", "$opt_d/failure.$n/$pid.core");
+ }
+
+ link("$file", "$opt_d/failure.$n/$dest");
+
+ $msg = "ERROR: " . $dest . " " . $msg;
+
+ if (scalar @parms > 1) {
+ $msg = $msg . "; see $errfile in failure.$n\n";
+ } else {
+ $msg = $msg . "; details in failure.$n\n";
+ }
+
+ errmsg($msg);
+}
+
+sub logmsg
+{
+ my($msg) = @_;
+
+ print STDOUT $msg unless ($opt_q);
+ print LOG $msg if ($opt_l);
+}
+
+# Trim leading and trailing whitespace
+sub trim {
+ my($s) = @_;
+
+ $s =~ s/^\s*//;
+ $s =~ s/\s*$//;
+ return $s;
+}
+
+# Load exception set of skipped tests from the file at the given
+# pathname. The test names are assumed to be paths relative to $dt_tst,
+# for example: common/aggs/tst.neglquant.d, and specify tests to be
+# skipped.
+sub load_exceptions {
+ my($listfile) = @_;
+ my($line) = "";
+
+ %exceptions = ();
+ if (length($listfile) > 0) {
+ exit(123) unless open(STDIN, "<$listfile");
+ while (<STDIN>) {
+ chomp;
+ $line = $_;
+ # line is non-empty and not a comment
+ if ((length($line) > 0) && ($line =~ /^\s*[^\s#]/ )) {
+ $exceptions{trim($line)} = 1;
+ }
+ }
+ }
+}
+
+# Return 1 if the test is found in the exception set, 0 otherwise.
+sub is_exception {
+ my($file) = @_;
+ my($i) = -1;
+
+ if (scalar(keys(%exceptions)) == 0) {
+ return 0;
+ }
+
+ # hash absolute pathname after $dt_tst/
+ $file = abs_path($file);
+ $i = index($file, $dt_tst);
+ if ($i == 0) {
+ $file = substr($file, length($dt_tst) + 1);
+ return $exceptions{$file};
+ }
+ return 0;
+}
+
+#
+# Iterate over the set of test files specified on the command-line or by a find
+# on "$defdir/common", "$defdir/$MACH" and "$defdir/$PLATFORM" and execute each
+# one. If the test file is executable, we fork and exec it. If the test is a
+# .ksh file, we run it with $ksh_path. Otherwise we run dtrace -s on it. If
+# the file is named tst.* we assume it should return exit status 0. If the
+# file is named err.* we assume it should return exit status 1. If the file is
+# named err.D_[A-Z0-9]+[.*].d we use dtrace -xerrtags and examine stderr to
+# ensure that a matching error tag was produced. If the file is named
+# drp.[A-Z0-9]+[.*].d we use dtrace -xdroptags and examine stderr to ensure
+# that a matching drop tag was produced. If any *.out or *.err files are found
+# we perform output comparisons.
+#
+# run_tests takes two arguments: The first is the pathname of the dtrace
+# command to invoke when running the tests. The second is the pathname
+# of a file (may be the empty string) listing tests that ought to be
+# skipped (skipped tests are listed as paths relative to $dt_tst, for
+# example: common/aggs/tst.neglquant.d).
+#
+sub run_tests {
+ my($dtrace, $exceptions_path) = @_;
+ my($passed) = 0;
+ my($bypassed) = 0;
+ my($failed) = $errs;
+ my($total) = 0;
+
+ die "$PNAME: $dtrace not found\n" unless (-x "$dtrace");
+ logmsg($dtrace . "\n");
+
+ load_exceptions($exceptions_path);
+
+ foreach $file (sort @files) {
+ $file =~ m:.*/((.*)\.(\w+)):;
+ $name = $1;
+ $base = $2;
+ $ext = $3;
+
+ $dir = dirname($file);
+ $isksh = 0;
+ $tag = 0;
+ $droptag = 0;
+
+ if ($name =~ /^tst\./) {
+ $isksh = ($ext eq 'ksh');
+ $status = 0;
+ } elsif ($name =~ /^err\.(D_[A-Z0-9_]+)\./) {
+ $status = 1;
+ $tag = $1;
+ } elsif ($name =~ /^err\./) {
+ $status = 1;
+ } elsif ($name =~ /^drp\.([A-Z0-9_]+)\./) {
+ $status = 0;
+ $droptag = $1;
+ } else {
+ errmsg("ERROR: $file is not a valid test file name\n");
+ next;
+ }
+
+ $fullname = "$dir/$name";
+ $exe = "$dir/$base.exe";
+ $exe_pid = -1;
+
+ if ($opt_a && ($status != 0 || $tag != 0 || $droptag != 0 ||
+ -x $exe || $isksh || -x $fullname)) {
+ $bypassed++;
+ next;
+ }
+
+ if (!$opt_f && is_exception("$dir/$name")) {
+ $bypassed++;
+ next;
+ }
+
+ if (!$isksh && -x $exe) {
+ if (($exe_pid = fork()) == -1) {
+ errmsg(
+ "ERROR: failed to fork to run $exe: $!\n");
+ next;
+ }
+
+ if ($exe_pid == 0) {
+ open(STDIN, '</dev/null');
+
+ exec($exe);
+
+ warn "ERROR: failed to exec $exe: $!\n";
+ }
+ }
+
+ logmsg("testing $file ... ");
+
+ if (($pid = fork()) == -1) {
+ errmsg("ERROR: failed to fork to run test $file: $!\n");
+ next;
+ }
+
+ if ($pid == 0) {
+ open(STDIN, '</dev/null');
+ exit(125) unless open(STDOUT, ">$opt_d/$$.out");
+ exit(125) unless open(STDERR, ">$opt_d/$$.err");
+
+ unless (chdir($dir)) {
+ warn "ERROR: failed to chdir for $file: $!\n";
+ exit(126);
+ }
+
+ push(@dtrace_argv, '-xerrtags') if ($tag);
+ push(@dtrace_argv, '-xdroptags') if ($droptag);
+ push(@dtrace_argv, $exe_pid) if ($exe_pid != -1);
+
+ if ($isksh) {
+ exit(123) unless open(STDIN, "<$name");
+ exec("$ksh_path /dev/stdin $dtrace");
+ } elsif (-x $name) {
+ warn "ERROR: $name is executable\n";
+ exit(1);
+ } else {
+ if ($tag == 0 && $status == $0 && $opt_a) {
+ push(@dtrace_argv, '-A');
+ }
+
+ push(@dtrace_argv, '-C');
+ push(@dtrace_argv, '-s');
+ push(@dtrace_argv, $name);
+ exec($dtrace, @dtrace_argv);
+ }
+
+ warn "ERROR: failed to exec for $file: $!\n";
+ exit(127);
+ }
+
+ if (waitpid($pid, 0) == -1) {
+ errmsg("ERROR: timed out waiting for $file\n");
+ kill(9, $exe_pid) if ($exe_pid != -1);
+ kill(9, $pid);
+ next;
+ }
+
+ kill(9, $exe_pid) if ($exe_pid != -1);
+
+ if ($tag == 0 && $status == $0 && $opt_a) {
+ #
+ # We can chuck the earler output.
+ #
+ unlink($pid . '.out');
+ unlink($pid . '.err');
+
+ #
+ # This is an anonymous enabling. We need to get
+ # the module unloaded.
+ #
+ system("dtrace -ae 1> /dev/null 2> /dev/null");
+ system("svcadm disable -s " .
+ "svc:/network/nfs/mapid:default");
+ system("modunload -i 0 ; modunload -i 0 ; " .
+ "modunload -i 0");
+ if (!system("modinfo | grep dtrace")) {
+ warn "ERROR: couldn't unload dtrace\n";
+ system("svcadm enable " .
+ "-s svc:/network/nfs/mapid:default");
+ exit(124);
+ }
+
+ #
+ # DTrace is gone. Now update_drv(1M), and rip
+ # everything out again.
+ #
+ system("update_drv dtrace");
+ system("dtrace -ae 1> /dev/null 2> /dev/null");
+ system("modunload -i 0 ; modunload -i 0 ; " .
+ "modunload -i 0");
+ if (!system("modinfo | grep dtrace")) {
+ warn "ERROR: couldn't unload dtrace\n";
+ system("svcadm enable " .
+ "-s svc:/network/nfs/mapid:default");
+ exit(124);
+ }
+
+ #
+ # Now bring DTrace back in.
+ #
+ system("sync ; sync");
+ system("dtrace -l -n bogusprobe 1> /dev/null " .
+ "2> /dev/null");
+ system("svcadm enable -s " .
+ "svc:/network/nfs/mapid:default");
+
+ #
+ # That should have caused DTrace to reload with
+ # the new configuration file. Now we can try to
+ # snag our anonymous state.
+ #
+ if (($pid = fork()) == -1) {
+ errmsg("ERROR: failed to fork to run " .
+ "test $file: $!\n");
+ next;
+ }
+
+ if ($pid == 0) {
+ open(STDIN, '</dev/null');
+ exit(125) unless open(STDOUT, ">$opt_d/$$.out");
+ exit(125) unless open(STDERR, ">$opt_d/$$.err");
+
+ push(@dtrace_argv, '-a');
+
+ unless (chdir($dir)) {
+ warn "ERROR: failed to chdir " .
+ "for $file: $!\n";
+ exit(126);
+ }
+
+ exec($dtrace, @dtrace_argv);
+ warn "ERROR: failed to exec for $file: $!\n";
+ exit(127);
+ }
+
+ if (waitpid($pid, 0) == -1) {
+ errmsg("ERROR: timed out waiting for $file\n");
+ kill(9, $pid);
+ next;
+ }
+ }
+
+ logmsg("[$pid]\n");
+ $wstat = $?;
+ $wifexited = ($wstat & 0xFF) == 0;
+ $wexitstat = ($wstat >> 8) & 0xFF;
+ $wtermsig = ($wstat & 0x7F);
+
+ if (!$wifexited) {
+ fail("died from signal $wtermsig");
+ next;
+ }
+
+ if ($wexitstat == 125) {
+ die "$PNAME: failed to create output file in $opt_d " .
+ "(cd elsewhere or use -d)\n";
+ }
+
+ if ($wexitstat != $status) {
+ fail("returned $wexitstat instead of $status");
+ next;
+ }
+
+ if (-f "$file.out" &&
+ system("cmp -s $file.out $opt_d/$pid.out") != 0) {
+ fail("stdout mismatch", "$pid.out");
+ next;
+ }
+
+ if (-f "$file.err" &&
+ system("cmp -s $file.err $opt_d/$pid.err") != 0) {
+ fail("stderr mismatch: see $pid.err");
+ next;
+ }
+
+ if ($tag) {
+ open(TSTERR, "<$opt_d/$pid.err");
+ $tsterr = <TSTERR>;
+ close(TSTERR);
+
+ unless ($tsterr =~ /: \[$tag\] line \d+:/) {
+ fail("errtag mismatch: see $pid.err");
+ next;
+ }
+ }
+
+ if ($droptag) {
+ $found = 0;
+ open(TSTERR, "<$opt_d/$pid.err");
+
+ while (<TSTERR>) {
+ if (/\[$droptag\] /) {
+ $found = 1;
+ last;
+ }
+ }
+
+ close (TSTERR);
+
+ unless ($found) {
+ fail("droptag mismatch: see $pid.err");
+ next;
+ }
+ }
+
+ unless ($opt_s) {
+ unlink($pid . '.out');
+ unlink($pid . '.err');
+ }
+ }
+
+ if ($opt_a) {
+ #
+ # If we're running with anonymous enablings, we need to
+ # restore the .conf file.
+ #
+ system("dtrace -A 1> /dev/null 2> /dev/null");
+ system("dtrace -ae 1> /dev/null 2> /dev/null");
+ system("modunload -i 0 ; modunload -i 0 ; modunload -i 0");
+ system("update_drv dtrace");
+ }
+
+ $total = scalar(@files);
+ $failed = $errs - $failed;
+ $passed = ($total - $failed - $bypassed);
+ $results{$dtrace} = {
+ "passed" => $passed,
+ "bypassed" => $bypassed,
+ "failed" => $failed,
+ "total" => $total
+ };
+}
+
+die $USAGE unless (getopts($OPTSTR));
+usage() if ($opt_h);
+
+foreach $arg (@ARGV) {
+ if (-f $arg) {
+ push(@files, $arg);
+ } elsif (-d $arg) {
+ find(\&wanted, $arg);
+ } else {
+ die "$PNAME: $arg is not a valid file or directory\n";
+ }
+}
+
+$dt_tst = '/opt/SUNWdtrt/tst';
+$dt_bin = '/opt/SUNWdtrt/bin';
+$defdir = -d $dt_tst ? $dt_tst : '.';
+$bindir = -d $dt_bin ? $dt_bin : '.';
+
+find(\&wanted, "$defdir/common") if (scalar(@ARGV) == 0);
+find(\&wanted, "$defdir/$MACH") if (scalar(@ARGV) == 0);
+find(\&wanted, "$defdir/$PLATFORM") if (scalar(@ARGV) == 0);
+die $USAGE if (scalar(@files) == 0);
+
+$dtrace_path = '/usr/sbin/dtrace';
+$jdtrace_path = "$bindir/jdtrace";
+
+%exception_lists = ("$jdtrace_path" => "$bindir/exception.lst");
+
+if ($opt_j || $opt_n || $opt_i) {
+ @dtrace_cmds = ();
+ push(@dtrace_cmds, $dtrace_path) if ($opt_n);
+ push(@dtrace_cmds, $jdtrace_path) if ($opt_j);
+ push(@dtrace_cmds, "/usr/sbin/$opt_i/dtrace") if ($opt_i);
+} else {
+ @dtrace_cmds = ($dtrace_path, $jdtrace_path);
+}
+
+if ($opt_d) {
+ die "$PNAME: -d arg must be absolute path\n" unless ($opt_d =~ /^\//);
+ die "$PNAME: -d arg $opt_d is not a directory\n" unless (-d "$opt_d");
+ system("coreadm -p $opt_d/%p.core");
+} else {
+ my $dir = getcwd;
+ system("coreadm -p $dir/%p.core");
+ $opt_d = '.';
+}
+
+if ($opt_x) {
+ push(@dtrace_argv, '-x');
+ push(@dtrace_argv, $opt_x);
+}
+
+die "$PNAME: failed to open $PNAME.$$.log: $!\n"
+ unless (!$opt_l || open(LOG, ">$PNAME.$$.log"));
+
+$ENV{'DTRACE_DEBUG_REGSET'} = 'true';
+
+if ($opt_g) {
+ $ENV{'UMEM_DEBUG'} = 'default,verbose';
+ $ENV{'UMEM_LOGGING'} = 'fail,contents';
+ $ENV{'LD_PRELOAD'} = 'libumem.so';
+}
+
+#
+# Ensure that $PATH contains a cc(1) so that we can execute the
+# test programs that require compilation of C code.
+#
+#$ENV{'PATH'} = $ENV{'PATH'} . ':/ws/onnv-tools/SUNWspro/SS11/bin';
+
+if ($opt_b) {
+ logmsg("badioctl'ing ... ");
+
+ if (($badioctl = fork()) == -1) {
+ errmsg("ERROR: failed to fork to run badioctl: $!\n");
+ next;
+ }
+
+ if ($badioctl == 0) {
+ open(STDIN, '</dev/null');
+ exit(125) unless open(STDOUT, ">$opt_d/$$.out");
+ exit(125) unless open(STDERR, ">$opt_d/$$.err");
+
+ exec($bindir . "/badioctl");
+ warn "ERROR: failed to exec badioctl: $!\n";
+ exit(127);
+ }
+
+
+ logmsg("[$badioctl]\n");
+
+ #
+ # If we're going to be bad, we're just going to iterate over each
+ # test file.
+ #
+ foreach $file (sort @files) {
+ ($name = $file) =~ s:.*/::;
+ $dir = dirname($file);
+
+ if (!($name =~ /^tst\./ && $name =~ /\.d$/)) {
+ next;
+ }
+
+ logmsg("baddof'ing $file ... ");
+
+ if (($pid = fork()) == -1) {
+ errmsg("ERROR: failed to fork to run baddof: $!\n");
+ next;
+ }
+
+ if ($pid == 0) {
+ open(STDIN, '</dev/null');
+ exit(125) unless open(STDOUT, ">$opt_d/$$.out");
+ exit(125) unless open(STDERR, ">$opt_d/$$.err");
+
+ unless (chdir($dir)) {
+ warn "ERROR: failed to chdir for $file: $!\n";
+ exit(126);
+ }
+
+ exec($bindir . "/baddof", $name);
+
+ warn "ERROR: failed to exec for $file: $!\n";
+ exit(127);
+ }
+
+ sleep 60;
+ kill(9, $pid);
+ waitpid($pid, 0);
+
+ logmsg("[$pid]\n");
+
+ unless ($opt_s) {
+ unlink($pid . '.out');
+ unlink($pid . '.err');
+ }
+ }
+
+ kill(9, $badioctl);
+ waitpid($badioctl, 0);
+
+ unless ($opt_s) {
+ unlink($badioctl . '.out');
+ unlink($badioctl . '.err');
+ }
+
+ exit(0);
+}
+
+#
+# Run all the tests specified on the command-line (the entire test suite
+# by default) once for each dtrace command tested, skipping any tests
+# not valid for that command.
+#
+foreach $dtrace_cmd (@dtrace_cmds) {
+ run_tests($dtrace_cmd, $exception_lists{$dtrace_cmd});
+}
+
+$opt_q = 0; # force final summary to appear regardless of -q option
+
+logmsg("\n==== TEST RESULTS ====\n");
+foreach $key (keys %results) {
+ my $passed = $results{$key}{"passed"};
+ my $bypassed = $results{$key}{"bypassed"};
+ my $failed = $results{$key}{"failed"};
+ my $total = $results{$key}{"total"};
+
+ logmsg("\n mode: " . $key . "\n");
+ logmsg(" passed: " . $passed . "\n");
+ if ($bypassed) {
+ logmsg(" bypassed: " . $bypassed . "\n");
+ }
+ logmsg(" failed: " . $failed . "\n");
+ logmsg(" total: " . $total . "\n");
+}
+
+exit($errs != 0);
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.rax.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.rax.c
new file mode 100644
index 000000000000..87f74786a9f5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.rax.c
@@ -0,0 +1,43 @@
+/*
+ * 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 (c) 2019 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * Use is subject to license terms.
+ */
+
+__attribute__((optnone)) void
+frax(void)
+{
+ asm volatile("mov $0x41414141, %%rax"
+ : : : "rax"
+ );
+}
+
+int
+main(void)
+{
+
+ while (1) {
+ frax();
+ }
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.rax.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.rax.d
new file mode 100644
index 000000000000..d271bea83dcf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.rax.d
@@ -0,0 +1,36 @@
+/*
+ * 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 (c) 2019 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * Use is subject to license terms.
+ */
+
+#pragma D option quiet
+
+pid$1::frax:return / uregs[R_RAX] == 0x41414141 / {
+ exit(0);
+}
+
+pid$1::frax:return / uregs[R_RAX] != 0x41414141 / {
+ printf("wrong rax value: %d\n", uregs[R_RAX]);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.uregsarray.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.uregsarray.d
new file mode 100644
index 000000000000..3872883bdc9f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/amd64/arrays/tst.uregsarray.d
@@ -0,0 +1,82 @@
+/*
+ * 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 (c) 2019 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Positive test to make sure that we can invoke amd64
+ * ureg[] aliases.
+ *
+ * SECTION: User Process Tracing/uregs Array
+ *
+ * NOTES: This test does no verification - the value of the output
+ * is not deterministic.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("R_GS = 0x%x\n", uregs[R_GS]);
+ printf("R_ES = 0x%x\n", uregs[R_ES]);
+ printf("R_DS = 0x%x\n", uregs[R_DS]);
+ printf("R_CS = 0x%x\n", uregs[R_CS]);
+ printf("R_RFL = 0x%x\n", uregs[R_RFL]);
+ printf("R_SS = 0x%x\n", uregs[R_SS]);
+ printf("R_TRAPNO = 0x%x\n", uregs[R_TRAPNO]);
+
+ printf("R_URSP = 0x%x\n", uregs[R_RSP]);
+ printf("R_RDI = 0x%x\n", uregs[R_RDI]);
+ printf("R_RSI = 0x%x\n", uregs[R_RSI]);
+ printf("R_RBP = 0x%x\n", uregs[R_RBP]);
+ printf("R_RBX = 0x%x\n", uregs[R_RBX]);
+ printf("R_RDX = 0x%x\n", uregs[R_RDX]);
+ printf("R_RCX = 0x%x\n", uregs[R_RCX]);
+ printf("R_RAX = 0x%x\n", uregs[R_RAX]);
+ printf("R_RIP = 0x%x\n", uregs[R_RIP]);
+ printf("R_RDI = 0x%x\n", uregs[R_RDI]);
+ printf("R_R9 = 0x%x\n", uregs[R_R9]);
+ printf("R_R10 = 0x%x\n", uregs[R_R10]);
+ printf("R_R11 = 0x%x\n", uregs[R_R11]);
+ printf("R_R12 = 0x%x\n", uregs[R_R12]);
+ printf("R_R13 = 0x%x\n", uregs[R_R13]);
+ printf("R_R14 = 0x%x\n", uregs[R_R14]);
+ printf("R_R15 = 0x%x\n", uregs[R_R15]);
+
+ /* 32 bits */
+ printf("R_EFL = 0x%x\n", uregs[R_EFL]);
+ printf("R_UESP = 0x%x\n", uregs[R_UESP]);
+ printf("R_ERR = 0x%x\n", uregs[R_ERR]);
+ printf("R_EIP = 0x%x\n", uregs[R_EIP]);
+ printf("R_EDI = 0x%x\n", uregs[R_EDI]);
+ printf("R_ESI = 0x%x\n", uregs[R_ESI]);
+ printf("R_EBP = 0x%x\n", uregs[R_EBP]);
+ printf("R_EBX = 0x%x\n", uregs[R_EBX]);
+ printf("R_EDX = 0x%x\n", uregs[R_EDX]);
+ printf("R_ECX = 0x%x\n", uregs[R_ECX]);
+ printf("R_EAX = 0x%x\n", uregs[R_EAX]);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_FUNC.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_FUNC.bad.d
new file mode 100644
index 000000000000..d12454be4eb5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_FUNC.bad.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * An aggregation must call an aggregating function.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+
+ @counts["xyz"] = breakpoint();
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_MDIM.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_MDIM.bad.d
new file mode 100644
index 000000000000..2c47289b54b5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_MDIM.bad.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * An aggregation may not be used as a multi-dimensional array
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+
+ @counts[0][2] = count();
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_NULL.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_NULL.bad.d
new file mode 100644
index 000000000000..87d18187c3f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_NULL.bad.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * An aggregation must have an aggregating function applied.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+
+ @a[1];
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_REDEF.redef.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_REDEF.redef.d
new file mode 100644
index 000000000000..9b4b425e4929
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_REDEF.redef.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test redefining the aggregation
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a = count();
+}
+
+END
+{
+ @a = max(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.avgtoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.avgtoofew.d
new file mode 100644
index 000000000000..106f4cdebc41
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.avgtoofew.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * avg() should not accept a non-scalar value
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a[pid] = avg(probefunc);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.maxnoarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.maxnoarg.d
new file mode 100644
index 000000000000..181e1962febd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.maxnoarg.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * max() should not accept a non-scalar value
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+BEGIN
+{
+ @a[pid] = max(probefunc);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.mintoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.mintoofew.d
new file mode 100644
index 000000000000..3ca34ffbc1c0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.mintoofew.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * min() should not accept a non-scalar value
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[pid] = min(probefunc);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.quantizetoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.quantizetoofew.d
new file mode 100644
index 000000000000..b7464552eb13
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.quantizetoofew.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * quantize() should not accept a non-scalar value
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[pid] = quantize(probefunc);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.stddevtoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.stddevtoofew.d
new file mode 100644
index 000000000000..262040f1b820
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.stddevtoofew.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * stddev() should not accept a non-scalar value
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a[pid] = stddev(probefunc);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.sumtoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.sumtoofew.d
new file mode 100644
index 000000000000..a77a2d5d2e08
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_AGG_SCALAR.sumtoofew.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * sum() should not accept a non-scalar value
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[pid] = sum(probefunc);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_CLEAR_AGGARG.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_CLEAR_AGGARG.bad.d
new file mode 100644
index 000000000000..0e6060ae95c4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_CLEAR_AGGARG.bad.d
@@ -0,0 +1,77 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * The argument to clear() must be an aggregation.
+ *
+ * SECTION: Aggregations/Clearing aggregations
+ *
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggrate=10ms
+#pragma D option switchrate=10ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func[i%5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 10/
+{
+ printf("Aggregation data before clear():\n");
+ printa(@func);
+
+ clear(count());
+
+ printf("Aggregation data after clear():\n");
+ printa(@func);
+ i++;
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("Final aggregation data:\n");
+ printa(@func);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_CLEAR_PROTO.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_CLEAR_PROTO.bad.d
new file mode 100644
index 000000000000..57fa8841389c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_CLEAR_PROTO.bad.d
@@ -0,0 +1,77 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * clear() should handle no args as an error.
+ *
+ * SECTION: Aggregations/Clearing aggregations
+ *
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggrate=10ms
+#pragma D option switchrate=10ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func[i%5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 10/
+{
+ printf("Aggregation data before clear():\n");
+ printa(@func);
+
+ clear();
+
+ printf("Aggregation data after clear():\n");
+ printa(@func);
+ i++;
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("Final aggregation data:\n");
+ printa(@func);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_FUNC_IDENT.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_FUNC_IDENT.bad.d
new file mode 100644
index 000000000000..866a7acf3b0e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_FUNC_IDENT.bad.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * An aggregation must call an aggregating function, not a probe
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+
+ @counts[0][2] = tick-1();
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_FUNC_UNDEF.badaggfunc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_FUNC_UNDEF.badaggfunc.d
new file mode 100644
index 000000000000..65c12da4990a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_FUNC_UNDEF.badaggfunc.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the use of a non-supported aggregate function.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+
+
+BEGIN
+{
+ @counts["badtest"] = foo();
+
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.badexpr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.badexpr.d
new file mode 100644
index 000000000000..83e6ab796c59
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.badexpr.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test using an aggregation in an expression context.
+ * This should result in a compile-time error.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ trace(@a + 3);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.badkey3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.badkey3.d
new file mode 100644
index 000000000000..67c5b64e4bd5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.badkey3.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the use of a dynamic expression as an aggregation key.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+
+BEGIN
+{
+ @t[i] = count();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.noeffect.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.noeffect.d
new file mode 100644
index 000000000000..9bdff78921df
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_IDENT_UNDEF.noeffect.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test compiling an aggregation statement that has no effect.
+ * This should result in a compile-time error.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey1.d
new file mode 100644
index 000000000000..abf3dd8c552d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey1.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the use of a void expression as an aggregation key.
+ * This should result in a compile-time error.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1, (void)0] = count();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey2.d
new file mode 100644
index 000000000000..9490b821f6ee
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey2.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the use of a dynamic expression as an aggregation key.
+ * This should result in a compile-time error.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[0] = count();
+ @b[@a] = count();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey4.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey4.d
new file mode 100644
index 000000000000..057746eb9da1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_KEY_TYPE.badkey4.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Test the use of a dynamic expression as an aggregation key.
+ * This should result in a compile-time error.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+
+BEGIN
+{
+ @a[curpsinfo] = count();
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASETYPE.lqbad1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASETYPE.lqbad1.d
new file mode 100644
index 000000000000..6bb6765a7f4e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASETYPE.lqbad1.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * lquantize() lower bound around must be an integer constant
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+
+BEGIN
+{
+ x = 'a';
+ @a[1] = lquantize(timestamp, x, 1000, 1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASETYPE.lqshort.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASETYPE.lqshort.d
new file mode 100644
index 000000000000..6bb6765a7f4e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASETYPE.lqshort.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * lquantize() lower bound around must be an integer constant
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+
+BEGIN
+{
+ x = 'a';
+ @a[1] = lquantize(timestamp, x, 1000, 1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASEVAL.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASEVAL.bad.d
new file mode 100644
index 000000000000..23d318e75a22
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_BASEVAL.bad.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * lquantize() lower bound must be a 32-bit quantity
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1] = lquantize(timestamp, 2147483657, 1000, 1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_LIMTYPE.lqbad1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_LIMTYPE.lqbad1.d
new file mode 100644
index 000000000000..894f064a4a6b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_LIMTYPE.lqbad1.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * lquantize() upper bound around must be an integer constant
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+
+BEGIN
+{
+ x = 'a';
+ @a[1] = lquantize(timestamp, 100, rand(), 1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_LIMVAL.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_LIMVAL.bad.d
new file mode 100644
index 000000000000..0a2f5e7f0796
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_LIMVAL.bad.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * lquantize() upper bound around must be an integer constant
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ x = 'a';
+ @a[1] = lquantize(timestamp, 100, 2147483657, 1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHBASE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHBASE.d
new file mode 100644
index 000000000000..b93ffabf88c1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHBASE.d
@@ -0,0 +1,33 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @ = lquantize(0, 10, 20, 1);
+ @ = lquantize(0, 15, 20, 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHBASE.order.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHBASE.order.d
new file mode 100644
index 000000000000..763c1e0b793f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHBASE.order.d
@@ -0,0 +1,33 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @ = lquantize(0, 10, 20, 1);
+ @ = lquantize(0, 15, 30, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHLIM.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHLIM.d
new file mode 100644
index 000000000000..d9ba023e4fa9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHLIM.d
@@ -0,0 +1,33 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @ = lquantize(0, 10, 20, 1);
+ @ = lquantize(0, 10, 2000, 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHLIM.order.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHLIM.order.d
new file mode 100644
index 000000000000..62be0c5b27b0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHLIM.order.d
@@ -0,0 +1,33 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @ = lquantize(0, 10, 20, 1);
+ @ = lquantize(0, 10, 2000, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHSTEP.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHSTEP.d
new file mode 100644
index 000000000000..086f4392f3d3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MATCHSTEP.d
@@ -0,0 +1,33 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @ = lquantize(0, 10, 20, 1);
+ @ = lquantize(0, 10, 20, 2);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MISMATCH.lqbadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MISMATCH.lqbadarg.d
new file mode 100644
index 000000000000..a4444ad11b8d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_MISMATCH.lqbadarg.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Upper bound must be greater than lower bound argument
+ *
+ * SECTION: Aggregations/Aggregations
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-1
+/i < 1000/
+{
+ @a[i] = lquantize(i, 1100, -100, -100 );
+ i += 100;
+}
+
+tick-1
+/i == 1000/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPLARGE.lqtoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPLARGE.lqtoofew.d
new file mode 100644
index 000000000000..664f70f29341
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPLARGE.lqtoofew.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * lquantize() should not accept more than 4 arguments.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1] = lquantize(1, 2, 3, 4, 5);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPSMALL.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPSMALL.bad.d
new file mode 100644
index 000000000000..634e8c06a81d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPSMALL.bad.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Number of quantization levels must be a 16-bit quantity
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a[i] = lquantize(i, 0, 1000000, 10);
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPTYPE.lqbadinc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPTYPE.lqbadinc.d
new file mode 100644
index 000000000000..87c51273a7c5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPTYPE.lqbadinc.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Upper bound must be greater than lower bound argument
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-1
+/i < 1000/
+{
+ @a[i] = lquantize(i, 0, 1100, -100);
+ i += 100;
+}
+
+tick-1
+/i == 1000/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPVAL.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPVAL.bad.d
new file mode 100644
index 000000000000..a90d7571ac6a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_LQUANT_STEPVAL.bad.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * lquantize() step value should be a 16-bit quantity
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a[i] = lquantize(i, 100, 1100, 200000 );
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_AGGARG.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_AGGARG.bad.d
new file mode 100644
index 000000000000..7e5974c5b7ca
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_AGGARG.bad.d
@@ -0,0 +1,65 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * The first argument to normalize() should be an aggregation.
+ *
+ * SECTION: Aggregations/Clearing aggregations
+ *
+ *
+ */
+
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=1ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func[i % 5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 20/
+{
+
+ printf("normalized data:\n");
+ normalize(count(), 4);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_PROTO.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_PROTO.bad.d
new file mode 100644
index 000000000000..82d819d4c02a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_PROTO.bad.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * normalize() accepts 2 args - passing fewer is an error.
+ *
+ * SECTION: Aggregations/Clearing aggregations
+ *
+ *
+ */
+
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=1ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func[i % 5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("normalized data:\n");
+ normalize(@func);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_SCALAR.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_SCALAR.bad.d
new file mode 100644
index 000000000000..14a258648e5a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_NORMALIZE_SCALAR.bad.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * The second argument to normalize() should be a scalar.
+ *
+ * SECTION: Aggregations/Clearing aggregations
+ *
+ *
+ */
+
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=1ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func[i % 5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("normalized data:\n");
+ normalize(@func, "hello");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_ARG.lquantizetoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_ARG.lquantizetoofew.d
new file mode 100644
index 000000000000..db4567f8e851
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_ARG.lquantizetoofew.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * lquantize() should not accept a non-scalar value
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[pid] = lquantize(probefunc, probefunc, probefunc, probefunc);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.avgnoarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.avgnoarg.d
new file mode 100644
index 000000000000..628eeabaccf0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.avgnoarg.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * avg() should not accept a call with no arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a[1] = avg();
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.avgtoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.avgtoomany.d
new file mode 100644
index 000000000000..42e5c1cc91ca
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.avgtoomany.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * avg() should not more than one argument
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a[1] = avg(1, 2);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.counttoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.counttoomany.d
new file mode 100644
index 000000000000..5dc5b800bf2c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.counttoomany.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * count() should not accept any arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a["badtest"] = count(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.lquantizenoarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.lquantizenoarg.d
new file mode 100644
index 000000000000..ae4b67247216
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.lquantizenoarg.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * lquantize() should not accept a call with no arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1] = lquantize();
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.lquantizetoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.lquantizetoomany.d
new file mode 100644
index 000000000000..bf87a4688c1c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.lquantizetoomany.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * lquantize() should not have more than five (!) arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @[1] = lquantize(10, 0, 100, 1, 10, 20);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.maxnoarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.maxnoarg.d
new file mode 100644
index 000000000000..aad2c2498daf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.maxnoarg.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * max() should not accept a call with no arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1] = max();
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.maxtoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.maxtoomany.d
new file mode 100644
index 000000000000..d0fb0918c346
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.maxtoomany.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * max() should not more than one argument
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1] = max(1, 2);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.minnoarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.minnoarg.d
new file mode 100644
index 000000000000..09db51f2265a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.minnoarg.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * min() should not accept a call with no arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1] = min();
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.mintoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.mintoomany.d
new file mode 100644
index 000000000000..2647402cb87c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.mintoomany.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * min() should not more than one argument
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1] = min(1, 2);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.quantizenoarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.quantizenoarg.d
new file mode 100644
index 000000000000..b33957a232eb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.quantizenoarg.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * quantize() should not accept a call with no arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1] = quantize();
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.quantizetoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.quantizetoomany.d
new file mode 100644
index 000000000000..9b162bd252f5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.quantizetoomany.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * quantize() should not have more than two arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[1] = quantize(1, 2, 3);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.stddevnoarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.stddevnoarg.d
new file mode 100644
index 000000000000..2952cf50c6d2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.stddevnoarg.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * stddev() should not accept a call with no arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a[1] = stddev();
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.stddevtoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.stddevtoomany.d
new file mode 100644
index 000000000000..c42e9628ce48
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.stddevtoomany.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * stddev() should not have more than one argument
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a[1] = stddev(1, 2);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.sumnoarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.sumnoarg.d
new file mode 100644
index 000000000000..4f279017bd4d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.sumnoarg.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * sum() should not accept a call with no arguments
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[pid] = sum();
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.sumtoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.sumtoomany.d
new file mode 100644
index 000000000000..5e899be64395
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_PROTO_LEN.sumtoomany.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * sum() should not more than one argument
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+BEGIN
+{
+ @a[pid] = sum(1, 2);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_AGGARG.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_AGGARG.bad.d
new file mode 100644
index 000000000000..69cb729184a4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_AGGARG.bad.d
@@ -0,0 +1,35 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+int i;
+
+BEGIN
+{
+ trunc(i);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_PROTO.badmany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_PROTO.badmany.d
new file mode 100644
index 000000000000..61271a74562e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_PROTO.badmany.d
@@ -0,0 +1,34 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @[0] = count();
+ trunc(@, 10, 20);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_PROTO.badnone.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_PROTO.badnone.d
new file mode 100644
index 000000000000..e141e6c97880
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_PROTO.badnone.d
@@ -0,0 +1,33 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ trunc();
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_SCALAR.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_SCALAR.bad.d
new file mode 100644
index 000000000000..e5485766d14d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/err.D_TRUNC_SCALAR.bad.d
@@ -0,0 +1,34 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @[0] = count();
+ trunc(@, @);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggencoding.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggencoding.d
new file mode 100644
index 000000000000..a594afc7d603
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggencoding.d
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+#pragma D option encoding=utf8
+#pragma D option aggzoom
+
+tick-1ms
+/i++ < 320/
+{
+ @ = lquantize(i, 0, 640, 1, i);
+ @ = lquantize(641 - i, 0, 640, 1, i);
+}
+
+tick-1ms
+/i == 320/
+{
+ printa(@);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggencoding.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggencoding.d.out
new file mode 100644
index 000000000000..68482ffbe14f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggencoding.d.out
@@ -0,0 +1,646 @@
+
+
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 | 1
+ 2 |▏ 2
+ 3 |▎ 3
+ 4 |▍ 4
+ 5 |▌ 5
+ 6 |▋ 6
+ 7 |▊ 7
+ 8 |▉ 8
+ 9 |█ 9
+ 10 |█▏ 10
+ 11 |█▎ 11
+ 12 |█▍ 12
+ 13 |█▌ 13
+ 14 |█▋ 14
+ 15 |█▊ 15
+ 16 |█▉ 16
+ 17 |██ 17
+ 18 |██▏ 18
+ 19 |██▎ 19
+ 20 |██▍ 20
+ 21 |██▍ 21
+ 22 |██▌ 22
+ 23 |██▋ 23
+ 24 |██▊ 24
+ 25 |██▉ 25
+ 26 |███ 26
+ 27 |███▏ 27
+ 28 |███▎ 28
+ 29 |███▍ 29
+ 30 |███▌ 30
+ 31 |███▋ 31
+ 32 |███▊ 32
+ 33 |███▉ 33
+ 34 |████ 34
+ 35 |████▏ 35
+ 36 |████▎ 36
+ 37 |████▍ 37
+ 38 |████▌ 38
+ 39 |████▋ 39
+ 40 |████▊ 40
+ 41 |████▊ 41
+ 42 |████▉ 42
+ 43 |█████ 43
+ 44 |█████▏ 44
+ 45 |█████▎ 45
+ 46 |█████▍ 46
+ 47 |█████▌ 47
+ 48 |█████▋ 48
+ 49 |█████▊ 49
+ 50 |█████▉ 50
+ 51 |██████ 51
+ 52 |██████▏ 52
+ 53 |██████▎ 53
+ 54 |██████▍ 54
+ 55 |██████▌ 55
+ 56 |██████▋ 56
+ 57 |██████▊ 57
+ 58 |██████▉ 58
+ 59 |███████ 59
+ 60 |███████▏ 60
+ 61 |███████▏ 61
+ 62 |███████▎ 62
+ 63 |███████▍ 63
+ 64 |███████▌ 64
+ 65 |███████▋ 65
+ 66 |███████▊ 66
+ 67 |███████▉ 67
+ 68 |████████ 68
+ 69 |████████▏ 69
+ 70 |████████▎ 70
+ 71 |████████▍ 71
+ 72 |████████▌ 72
+ 73 |████████▋ 73
+ 74 |████████▊ 74
+ 75 |████████▉ 75
+ 76 |█████████ 76
+ 77 |█████████▏ 77
+ 78 |█████████▎ 78
+ 79 |█████████▍ 79
+ 80 |█████████▌ 80
+ 81 |█████████▌ 81
+ 82 |█████████▋ 82
+ 83 |█████████▊ 83
+ 84 |█████████▉ 84
+ 85 |██████████ 85
+ 86 |██████████▏ 86
+ 87 |██████████▎ 87
+ 88 |██████████▍ 88
+ 89 |██████████▌ 89
+ 90 |██████████▋ 90
+ 91 |██████████▊ 91
+ 92 |██████████▉ 92
+ 93 |███████████ 93
+ 94 |███████████▏ 94
+ 95 |███████████▎ 95
+ 96 |███████████▍ 96
+ 97 |███████████▌ 97
+ 98 |███████████▋ 98
+ 99 |███████████▊ 99
+ 100 |███████████▉ 100
+ 101 |███████████▉ 101
+ 102 |████████████ 102
+ 103 |████████████▏ 103
+ 104 |████████████▎ 104
+ 105 |████████████▍ 105
+ 106 |████████████▌ 106
+ 107 |████████████▋ 107
+ 108 |████████████▊ 108
+ 109 |████████████▉ 109
+ 110 |█████████████ 110
+ 111 |█████████████▏ 111
+ 112 |█████████████▎ 112
+ 113 |█████████████▍ 113
+ 114 |█████████████▌ 114
+ 115 |█████████████▋ 115
+ 116 |█████████████▊ 116
+ 117 |█████████████▉ 117
+ 118 |██████████████ 118
+ 119 |██████████████▏ 119
+ 120 |██████████████▎ 120
+ 121 |██████████████▎ 121
+ 122 |██████████████▍ 122
+ 123 |██████████████▌ 123
+ 124 |██████████████▋ 124
+ 125 |██████████████▊ 125
+ 126 |██████████████▉ 126
+ 127 |███████████████ 127
+ 128 |███████████████▏ 128
+ 129 |███████████████▎ 129
+ 130 |███████████████▍ 130
+ 131 |███████████████▌ 131
+ 132 |███████████████▋ 132
+ 133 |███████████████▊ 133
+ 134 |███████████████▉ 134
+ 135 |████████████████ 135
+ 136 |████████████████▏ 136
+ 137 |████████████████▎ 137
+ 138 |████████████████▍ 138
+ 139 |████████████████▌ 139
+ 140 |████████████████▋ 140
+ 141 |████████████████▋ 141
+ 142 |████████████████▊ 142
+ 143 |████████████████▉ 143
+ 144 |█████████████████ 144
+ 145 |█████████████████▏ 145
+ 146 |█████████████████▎ 146
+ 147 |█████████████████▍ 147
+ 148 |█████████████████▌ 148
+ 149 |█████████████████▋ 149
+ 150 |█████████████████▊ 150
+ 151 |█████████████████▉ 151
+ 152 |██████████████████ 152
+ 153 |██████████████████▏ 153
+ 154 |██████████████████▎ 154
+ 155 |██████████████████▍ 155
+ 156 |██████████████████▌ 156
+ 157 |██████████████████▋ 157
+ 158 |██████████████████▊ 158
+ 159 |██████████████████▉ 159
+ 160 |███████████████████ 160
+ 161 |███████████████████ 161
+ 162 |███████████████████▏ 162
+ 163 |███████████████████▎ 163
+ 164 |███████████████████▍ 164
+ 165 |███████████████████▌ 165
+ 166 |███████████████████▋ 166
+ 167 |███████████████████▊ 167
+ 168 |███████████████████▉ 168
+ 169 |████████████████████ 169
+ 170 |████████████████████▏ 170
+ 171 |████████████████████▎ 171
+ 172 |████████████████████▍ 172
+ 173 |████████████████████▌ 173
+ 174 |████████████████████▋ 174
+ 175 |████████████████████▊ 175
+ 176 |████████████████████▉ 176
+ 177 |█████████████████████ 177
+ 178 |█████████████████████▏ 178
+ 179 |█████████████████████▎ 179
+ 180 |█████████████████████▍ 180
+ 181 |█████████████████████▍ 181
+ 182 |█████████████████████▌ 182
+ 183 |█████████████████████▋ 183
+ 184 |█████████████████████▊ 184
+ 185 |█████████████████████▉ 185
+ 186 |██████████████████████ 186
+ 187 |██████████████████████▏ 187
+ 188 |██████████████████████▎ 188
+ 189 |██████████████████████▍ 189
+ 190 |██████████████████████▌ 190
+ 191 |██████████████████████▋ 191
+ 192 |██████████████████████▊ 192
+ 193 |██████████████████████▉ 193
+ 194 |███████████████████████ 194
+ 195 |███████████████████████▏ 195
+ 196 |███████████████████████▎ 196
+ 197 |███████████████████████▍ 197
+ 198 |███████████████████████▌ 198
+ 199 |███████████████████████▋ 199
+ 200 |███████████████████████▊ 200
+ 201 |███████████████████████▊ 201
+ 202 |███████████████████████▉ 202
+ 203 |████████████████████████ 203
+ 204 |████████████████████████▏ 204
+ 205 |████████████████████████▎ 205
+ 206 |████████████████████████▍ 206
+ 207 |████████████████████████▌ 207
+ 208 |████████████████████████▋ 208
+ 209 |████████████████████████▊ 209
+ 210 |████████████████████████▉ 210
+ 211 |█████████████████████████ 211
+ 212 |█████████████████████████▏ 212
+ 213 |█████████████████████████▎ 213
+ 214 |█████████████████████████▍ 214
+ 215 |█████████████████████████▌ 215
+ 216 |█████████████████████████▋ 216
+ 217 |█████████████████████████▊ 217
+ 218 |█████████████████████████▉ 218
+ 219 |██████████████████████████ 219
+ 220 |██████████████████████████▏ 220
+ 221 |██████████████████████████▏ 221
+ 222 |██████████████████████████▎ 222
+ 223 |██████████████████████████▍ 223
+ 224 |██████████████████████████▌ 224
+ 225 |██████████████████████████▋ 225
+ 226 |██████████████████████████▊ 226
+ 227 |██████████████████████████▉ 227
+ 228 |███████████████████████████ 228
+ 229 |███████████████████████████▏ 229
+ 230 |███████████████████████████▎ 230
+ 231 |███████████████████████████▍ 231
+ 232 |███████████████████████████▌ 232
+ 233 |███████████████████████████▋ 233
+ 234 |███████████████████████████▊ 234
+ 235 |███████████████████████████▉ 235
+ 236 |████████████████████████████ 236
+ 237 |████████████████████████████▏ 237
+ 238 |████████████████████████████▎ 238
+ 239 |████████████████████████████▍ 239
+ 240 |████████████████████████████▌ 240
+ 241 |████████████████████████████▌ 241
+ 242 |████████████████████████████▋ 242
+ 243 |████████████████████████████▊ 243
+ 244 |████████████████████████████▉ 244
+ 245 |█████████████████████████████ 245
+ 246 |█████████████████████████████▏ 246
+ 247 |█████████████████████████████▎ 247
+ 248 |█████████████████████████████▍ 248
+ 249 |█████████████████████████████▌ 249
+ 250 |█████████████████████████████▋ 250
+ 251 |█████████████████████████████▊ 251
+ 252 |█████████████████████████████▉ 252
+ 253 |██████████████████████████████ 253
+ 254 |██████████████████████████████▏ 254
+ 255 |██████████████████████████████▎ 255
+ 256 |██████████████████████████████▍ 256
+ 257 |██████████████████████████████▌ 257
+ 258 |██████████████████████████████▋ 258
+ 259 |██████████████████████████████▊ 259
+ 260 |██████████████████████████████▉ 260
+ 261 |██████████████████████████████▉ 261
+ 262 |███████████████████████████████ 262
+ 263 |███████████████████████████████▏ 263
+ 264 |███████████████████████████████▎ 264
+ 265 |███████████████████████████████▍ 265
+ 266 |███████████████████████████████▌ 266
+ 267 |███████████████████████████████▋ 267
+ 268 |███████████████████████████████▊ 268
+ 269 |███████████████████████████████▉ 269
+ 270 |████████████████████████████████ 270
+ 271 |████████████████████████████████▏ 271
+ 272 |████████████████████████████████▎ 272
+ 273 |████████████████████████████████▍ 273
+ 274 |████████████████████████████████▌ 274
+ 275 |████████████████████████████████▋ 275
+ 276 |████████████████████████████████▊ 276
+ 277 |████████████████████████████████▉ 277
+ 278 |█████████████████████████████████ 278
+ 279 |█████████████████████████████████▏ 279
+ 280 |█████████████████████████████████▎ 280
+ 281 |█████████████████████████████████▎ 281
+ 282 |█████████████████████████████████▍ 282
+ 283 |█████████████████████████████████▌ 283
+ 284 |█████████████████████████████████▋ 284
+ 285 |█████████████████████████████████▊ 285
+ 286 |█████████████████████████████████▉ 286
+ 287 |██████████████████████████████████ 287
+ 288 |██████████████████████████████████▏ 288
+ 289 |██████████████████████████████████▎ 289
+ 290 |██████████████████████████████████▍ 290
+ 291 |██████████████████████████████████▌ 291
+ 292 |██████████████████████████████████▋ 292
+ 293 |██████████████████████████████████▊ 293
+ 294 |██████████████████████████████████▉ 294
+ 295 |███████████████████████████████████ 295
+ 296 |███████████████████████████████████▏ 296
+ 297 |███████████████████████████████████▎ 297
+ 298 |███████████████████████████████████▍ 298
+ 299 |███████████████████████████████████▌ 299
+ 300 |███████████████████████████████████▋ 300
+ 301 |███████████████████████████████████▋ 301
+ 302 |███████████████████████████████████▊ 302
+ 303 |███████████████████████████████████▉ 303
+ 304 |████████████████████████████████████ 304
+ 305 |████████████████████████████████████▏ 305
+ 306 |████████████████████████████████████▎ 306
+ 307 |████████████████████████████████████▍ 307
+ 308 |████████████████████████████████████▌ 308
+ 309 |████████████████████████████████████▋ 309
+ 310 |████████████████████████████████████▊ 310
+ 311 |████████████████████████████████████▉ 311
+ 312 |█████████████████████████████████████ 312
+ 313 |█████████████████████████████████████▏ 313
+ 314 |█████████████████████████████████████▎ 314
+ 315 |█████████████████████████████████████▍ 315
+ 316 |█████████████████████████████████████▌ 316
+ 317 |█████████████████████████████████████▋ 317
+ 318 |█████████████████████████████████████▊ 318
+ 319 |█████████████████████████████████████▉ 319
+ 320 |██████████████████████████████████████ 320
+ 321 |██████████████████████████████████████ 320
+ 322 |█████████████████████████████████████▉ 319
+ 323 |█████████████████████████████████████▊ 318
+ 324 |█████████████████████████████████████▋ 317
+ 325 |█████████████████████████████████████▌ 316
+ 326 |█████████████████████████████████████▍ 315
+ 327 |█████████████████████████████████████▎ 314
+ 328 |█████████████████████████████████████▏ 313
+ 329 |█████████████████████████████████████ 312
+ 330 |████████████████████████████████████▉ 311
+ 331 |████████████████████████████████████▊ 310
+ 332 |████████████████████████████████████▋ 309
+ 333 |████████████████████████████████████▌ 308
+ 334 |████████████████████████████████████▍ 307
+ 335 |████████████████████████████████████▎ 306
+ 336 |████████████████████████████████████▏ 305
+ 337 |████████████████████████████████████ 304
+ 338 |███████████████████████████████████▉ 303
+ 339 |███████████████████████████████████▊ 302
+ 340 |███████████████████████████████████▋ 301
+ 341 |███████████████████████████████████▋ 300
+ 342 |███████████████████████████████████▌ 299
+ 343 |███████████████████████████████████▍ 298
+ 344 |███████████████████████████████████▎ 297
+ 345 |███████████████████████████████████▏ 296
+ 346 |███████████████████████████████████ 295
+ 347 |██████████████████████████████████▉ 294
+ 348 |██████████████████████████████████▊ 293
+ 349 |██████████████████████████████████▋ 292
+ 350 |██████████████████████████████████▌ 291
+ 351 |██████████████████████████████████▍ 290
+ 352 |██████████████████████████████████▎ 289
+ 353 |██████████████████████████████████▏ 288
+ 354 |██████████████████████████████████ 287
+ 355 |█████████████████████████████████▉ 286
+ 356 |█████████████████████████████████▊ 285
+ 357 |█████████████████████████████████▋ 284
+ 358 |█████████████████████████████████▌ 283
+ 359 |█████████████████████████████████▍ 282
+ 360 |█████████████████████████████████▎ 281
+ 361 |█████████████████████████████████▎ 280
+ 362 |█████████████████████████████████▏ 279
+ 363 |█████████████████████████████████ 278
+ 364 |████████████████████████████████▉ 277
+ 365 |████████████████████████████████▊ 276
+ 366 |████████████████████████████████▋ 275
+ 367 |████████████████████████████████▌ 274
+ 368 |████████████████████████████████▍ 273
+ 369 |████████████████████████████████▎ 272
+ 370 |████████████████████████████████▏ 271
+ 371 |████████████████████████████████ 270
+ 372 |███████████████████████████████▉ 269
+ 373 |███████████████████████████████▊ 268
+ 374 |███████████████████████████████▋ 267
+ 375 |███████████████████████████████▌ 266
+ 376 |███████████████████████████████▍ 265
+ 377 |███████████████████████████████▎ 264
+ 378 |███████████████████████████████▏ 263
+ 379 |███████████████████████████████ 262
+ 380 |██████████████████████████████▉ 261
+ 381 |██████████████████████████████▉ 260
+ 382 |██████████████████████████████▊ 259
+ 383 |██████████████████████████████▋ 258
+ 384 |██████████████████████████████▌ 257
+ 385 |██████████████████████████████▍ 256
+ 386 |██████████████████████████████▎ 255
+ 387 |██████████████████████████████▏ 254
+ 388 |██████████████████████████████ 253
+ 389 |█████████████████████████████▉ 252
+ 390 |█████████████████████████████▊ 251
+ 391 |█████████████████████████████▋ 250
+ 392 |█████████████████████████████▌ 249
+ 393 |█████████████████████████████▍ 248
+ 394 |█████████████████████████████▎ 247
+ 395 |█████████████████████████████▏ 246
+ 396 |█████████████████████████████ 245
+ 397 |████████████████████████████▉ 244
+ 398 |████████████████████████████▊ 243
+ 399 |████████████████████████████▋ 242
+ 400 |████████████████████████████▌ 241
+ 401 |████████████████████████████▌ 240
+ 402 |████████████████████████████▍ 239
+ 403 |████████████████████████████▎ 238
+ 404 |████████████████████████████▏ 237
+ 405 |████████████████████████████ 236
+ 406 |███████████████████████████▉ 235
+ 407 |███████████████████████████▊ 234
+ 408 |███████████████████████████▋ 233
+ 409 |███████████████████████████▌ 232
+ 410 |███████████████████████████▍ 231
+ 411 |███████████████████████████▎ 230
+ 412 |███████████████████████████▏ 229
+ 413 |███████████████████████████ 228
+ 414 |██████████████████████████▉ 227
+ 415 |██████████████████████████▊ 226
+ 416 |██████████████████████████▋ 225
+ 417 |██████████████████████████▌ 224
+ 418 |██████████████████████████▍ 223
+ 419 |██████████████████████████▎ 222
+ 420 |██████████████████████████▏ 221
+ 421 |██████████████████████████▏ 220
+ 422 |██████████████████████████ 219
+ 423 |█████████████████████████▉ 218
+ 424 |█████████████████████████▊ 217
+ 425 |█████████████████████████▋ 216
+ 426 |█████████████████████████▌ 215
+ 427 |█████████████████████████▍ 214
+ 428 |█████████████████████████▎ 213
+ 429 |█████████████████████████▏ 212
+ 430 |█████████████████████████ 211
+ 431 |████████████████████████▉ 210
+ 432 |████████████████████████▊ 209
+ 433 |████████████████████████▋ 208
+ 434 |████████████████████████▌ 207
+ 435 |████████████████████████▍ 206
+ 436 |████████████████████████▎ 205
+ 437 |████████████████████████▏ 204
+ 438 |████████████████████████ 203
+ 439 |███████████████████████▉ 202
+ 440 |███████████████████████▊ 201
+ 441 |███████████████████████▊ 200
+ 442 |███████████████████████▋ 199
+ 443 |███████████████████████▌ 198
+ 444 |███████████████████████▍ 197
+ 445 |███████████████████████▎ 196
+ 446 |███████████████████████▏ 195
+ 447 |███████████████████████ 194
+ 448 |██████████████████████▉ 193
+ 449 |██████████████████████▊ 192
+ 450 |██████████████████████▋ 191
+ 451 |██████████████████████▌ 190
+ 452 |██████████████████████▍ 189
+ 453 |██████████████████████▎ 188
+ 454 |██████████████████████▏ 187
+ 455 |██████████████████████ 186
+ 456 |█████████████████████▉ 185
+ 457 |█████████████████████▊ 184
+ 458 |█████████████████████▋ 183
+ 459 |█████████████████████▌ 182
+ 460 |█████████████████████▍ 181
+ 461 |█████████████████████▍ 180
+ 462 |█████████████████████▎ 179
+ 463 |█████████████████████▏ 178
+ 464 |█████████████████████ 177
+ 465 |████████████████████▉ 176
+ 466 |████████████████████▊ 175
+ 467 |████████████████████▋ 174
+ 468 |████████████████████▌ 173
+ 469 |████████████████████▍ 172
+ 470 |████████████████████▎ 171
+ 471 |████████████████████▏ 170
+ 472 |████████████████████ 169
+ 473 |███████████████████▉ 168
+ 474 |███████████████████▊ 167
+ 475 |███████████████████▋ 166
+ 476 |███████████████████▌ 165
+ 477 |███████████████████▍ 164
+ 478 |███████████████████▎ 163
+ 479 |███████████████████▏ 162
+ 480 |███████████████████ 161
+ 481 |███████████████████ 160
+ 482 |██████████████████▉ 159
+ 483 |██████████████████▊ 158
+ 484 |██████████████████▋ 157
+ 485 |██████████████████▌ 156
+ 486 |██████████████████▍ 155
+ 487 |██████████████████▎ 154
+ 488 |██████████████████▏ 153
+ 489 |██████████████████ 152
+ 490 |█████████████████▉ 151
+ 491 |█████████████████▊ 150
+ 492 |█████████████████▋ 149
+ 493 |█████████████████▌ 148
+ 494 |█████████████████▍ 147
+ 495 |█████████████████▎ 146
+ 496 |█████████████████▏ 145
+ 497 |█████████████████ 144
+ 498 |████████████████▉ 143
+ 499 |████████████████▊ 142
+ 500 |████████████████▋ 141
+ 501 |████████████████▋ 140
+ 502 |████████████████▌ 139
+ 503 |████████████████▍ 138
+ 504 |████████████████▎ 137
+ 505 |████████████████▏ 136
+ 506 |████████████████ 135
+ 507 |███████████████▉ 134
+ 508 |███████████████▊ 133
+ 509 |███████████████▋ 132
+ 510 |███████████████▌ 131
+ 511 |███████████████▍ 130
+ 512 |███████████████▎ 129
+ 513 |███████████████▏ 128
+ 514 |███████████████ 127
+ 515 |██████████████▉ 126
+ 516 |██████████████▊ 125
+ 517 |██████████████▋ 124
+ 518 |██████████████▌ 123
+ 519 |██████████████▍ 122
+ 520 |██████████████▎ 121
+ 521 |██████████████▎ 120
+ 522 |██████████████▏ 119
+ 523 |██████████████ 118
+ 524 |█████████████▉ 117
+ 525 |█████████████▊ 116
+ 526 |█████████████▋ 115
+ 527 |█████████████▌ 114
+ 528 |█████████████▍ 113
+ 529 |█████████████▎ 112
+ 530 |█████████████▏ 111
+ 531 |█████████████ 110
+ 532 |████████████▉ 109
+ 533 |████████████▊ 108
+ 534 |████████████▋ 107
+ 535 |████████████▌ 106
+ 536 |████████████▍ 105
+ 537 |████████████▎ 104
+ 538 |████████████▏ 103
+ 539 |████████████ 102
+ 540 |███████████▉ 101
+ 541 |███████████▉ 100
+ 542 |███████████▊ 99
+ 543 |███████████▋ 98
+ 544 |███████████▌ 97
+ 545 |███████████▍ 96
+ 546 |███████████▎ 95
+ 547 |███████████▏ 94
+ 548 |███████████ 93
+ 549 |██████████▉ 92
+ 550 |██████████▊ 91
+ 551 |██████████▋ 90
+ 552 |██████████▌ 89
+ 553 |██████████▍ 88
+ 554 |██████████▎ 87
+ 555 |██████████▏ 86
+ 556 |██████████ 85
+ 557 |█████████▉ 84
+ 558 |█████████▊ 83
+ 559 |█████████▋ 82
+ 560 |█████████▌ 81
+ 561 |█████████▌ 80
+ 562 |█████████▍ 79
+ 563 |█████████▎ 78
+ 564 |█████████▏ 77
+ 565 |█████████ 76
+ 566 |████████▉ 75
+ 567 |████████▊ 74
+ 568 |████████▋ 73
+ 569 |████████▌ 72
+ 570 |████████▍ 71
+ 571 |████████▎ 70
+ 572 |████████▏ 69
+ 573 |████████ 68
+ 574 |███████▉ 67
+ 575 |███████▊ 66
+ 576 |███████▋ 65
+ 577 |███████▌ 64
+ 578 |███████▍ 63
+ 579 |███████▎ 62
+ 580 |███████▏ 61
+ 581 |███████▏ 60
+ 582 |███████ 59
+ 583 |██████▉ 58
+ 584 |██████▊ 57
+ 585 |██████▋ 56
+ 586 |██████▌ 55
+ 587 |██████▍ 54
+ 588 |██████▎ 53
+ 589 |██████▏ 52
+ 590 |██████ 51
+ 591 |█████▉ 50
+ 592 |█████▊ 49
+ 593 |█████▋ 48
+ 594 |█████▌ 47
+ 595 |█████▍ 46
+ 596 |█████▎ 45
+ 597 |█████▏ 44
+ 598 |█████ 43
+ 599 |████▉ 42
+ 600 |████▊ 41
+ 601 |████▊ 40
+ 602 |████▋ 39
+ 603 |████▌ 38
+ 604 |████▍ 37
+ 605 |████▎ 36
+ 606 |████▏ 35
+ 607 |████ 34
+ 608 |███▉ 33
+ 609 |███▊ 32
+ 610 |███▋ 31
+ 611 |███▌ 30
+ 612 |███▍ 29
+ 613 |███▎ 28
+ 614 |███▏ 27
+ 615 |███ 26
+ 616 |██▉ 25
+ 617 |██▊ 24
+ 618 |██▋ 23
+ 619 |██▌ 22
+ 620 |██▍ 21
+ 621 |██▍ 20
+ 622 |██▎ 19
+ 623 |██▏ 18
+ 624 |██ 17
+ 625 |█▉ 16
+ 626 |█▊ 15
+ 627 |█▋ 14
+ 628 |█▌ 13
+ 629 |█▍ 12
+ 630 |█▎ 11
+ 631 |█▏ 10
+ 632 |█ 9
+ 633 |▉ 8
+ 634 |▊ 7
+ 635 |▋ 6
+ 636 |▌ 5
+ 637 |▍ 4
+ 638 |▎ 3
+ 639 |▏ 2
+ >= 640 | 1
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.agghist.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.agghist.d
new file mode 100644
index 000000000000..317aecefddfe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.agghist.d
@@ -0,0 +1,46 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option agghist
+#pragma D option quiet
+
+BEGIN
+{
+ @["demerit"] = sum(-10);
+ @["wtf"] = sum(10);
+ @["bot"] = sum(20);
+
+ @bagnoogle["SOAP/XML"] = sum(1);
+ @bagnoogle["XACML store"] = sum(5);
+ @bagnoogle["SAML token"] = sum(6);
+
+ @stalloogle["breakfast"] = sum(-5);
+ @stalloogle["non-diet pepsi"] = sum(-20);
+ @stalloogle["parrot"] = sum(-100);
+
+ printa(@);
+ printa(@bagnoogle);
+ printa(@stalloogle);
+
+ printf("\nzoomed:");
+
+ setopt("aggzoom");
+ printa(@);
+ printa(@bagnoogle);
+ printa(@stalloogle);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.agghist.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.agghist.d.out
new file mode 100644
index 000000000000..d76e4da4b82d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.agghist.d.out
@@ -0,0 +1,38 @@
+
+
+ key ------------- Distribution ------------- count
+ demerit @@@@@| -10
+ wtf |@@@@@ 10
+ bot |@@@@@@@@@@ 20
+
+
+ key ------------- Distribution ------------- count
+ SOAP/XML |@@@ 1
+ XACML store |@@@@@@@@@@@@@@@@@ 5
+ SAML token |@@@@@@@@@@@@@@@@@@@@ 6
+
+
+ key ------------- Distribution ------------- count
+ parrot @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -100
+ non-diet pepsi @@@@@@| -20
+ breakfast @@| -5
+
+zoomed:
+
+ key ------------- Distribution ------------- count
+ demerit @@@@@@@@@@| -10
+ wtf |@@@@@@@@@@ 10
+ bot |@@@@@@@@@@@@@@@@@@@ 20
+
+
+ key ------------- Distribution ------------- count
+ SOAP/XML |@@@@@@@ 1
+ XACML store |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ SAML token |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+
+
+ key ------------- Distribution ------------- count
+ parrot @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -100
+ non-diet pepsi @@@@@@@@| -20
+ breakfast @@| -5
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpack.d
new file mode 100644
index 000000000000..c9fdba76c4be
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpack.d
@@ -0,0 +1,53 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option aggpack
+#pragma D option encoding=ascii
+#pragma D option quiet
+
+BEGIN
+{
+ @x = quantize(1 << 32);
+ @y[1] = quantize(1);
+ @z["mumble"] = quantize(1);
+ @xx["foo", (char)1, (short)2, (long)3] = quantize(1);
+
+ @neg = lquantize(-10, -10, 20, 1, -1);
+ @neg = lquantize(-5, -10, 20, 1, 1);
+ @neg = lquantize(0, -10, 20, 1, 1);
+
+ i = 0;
+}
+
+tick-1ms
+{
+ @a[i] = quantize(0, i);
+ @a[i] = quantize(1, 100 - i);
+ i++;
+}
+
+tick-1ms
+/i > 100/
+{
+ exit(0);
+}
+
+END
+{
+ setopt("aggzoom", "true");
+ printa(@neg);
+ setopt("aggzoom", "false");
+ printa(@neg);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpack.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpack.d.out
new file mode 100644
index 000000000000..5300ebdbe934
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpack.d.out
@@ -0,0 +1,124 @@
+
+
+ min .--------------------------------. max | count
+ < -10 : V X X : >= 20 | 1
+
+
+ min .--------------------------------. max | count
+ < -10 : v x x : >= 20 | 1
+
+
+ min .---. max | count
+ 2147483648 : X : 8589934592 | 1
+
+ key min .---. max | count
+ 1 0 : X : 2 | 1
+
+ key min .---. max | count
+ mumble 0 : X : 2 | 1
+
+ key min .---. max | count
+ foo 1 2 3 0 : X : 2 | 1
+
+ key min .---. max | count
+ 100 0 :X : 2 | 100
+ 99 0 :X_ : 2 | 100
+ 98 0 :X_ : 2 | 100
+ 97 0 :X_ : 2 | 100
+ 96 0 :X_ : 2 | 100
+ 95 0 :X_ : 2 | 100
+ 94 0 :X_ : 2 | 100
+ 93 0 :X_ : 2 | 100
+ 92 0 :X_ : 2 | 100
+ 91 0 :X_ : 2 | 100
+ 90 0 :X_ : 2 | 100
+ 89 0 :X_ : 2 | 100
+ 88 0 :X_ : 2 | 100
+ 87 0 :X_ : 2 | 100
+ 86 0 :X_ : 2 | 100
+ 85 0 :X_ : 2 | 100
+ 84 0 :X_ : 2 | 100
+ 83 0 :X_ : 2 | 100
+ 82 0 :X_ : 2 | 100
+ 81 0 :X_ : 2 | 100
+ 80 0 :X_ : 2 | 100
+ 79 0 :X_ : 2 | 100
+ 78 0 :xx : 2 | 100
+ 77 0 :xx : 2 | 100
+ 76 0 :xx : 2 | 100
+ 75 0 :xx : 2 | 100
+ 74 0 :xx : 2 | 100
+ 73 0 :xx : 2 | 100
+ 72 0 :xx : 2 | 100
+ 71 0 :xx : 2 | 100
+ 70 0 :xx : 2 | 100
+ 69 0 :xx : 2 | 100
+ 68 0 :xx : 2 | 100
+ 67 0 :xx : 2 | 100
+ 66 0 :xx : 2 | 100
+ 65 0 :xx : 2 | 100
+ 64 0 :xx : 2 | 100
+ 63 0 :xx : 2 | 100
+ 62 0 :xx : 2 | 100
+ 61 0 :xx : 2 | 100
+ 60 0 :xx : 2 | 100
+ 59 0 :xx : 2 | 100
+ 58 0 :xx : 2 | 100
+ 57 0 :xx : 2 | 100
+ 56 0 :xx : 2 | 100
+ 55 0 :xx : 2 | 100
+ 54 0 :xx : 2 | 100
+ 53 0 :xx : 2 | 100
+ 52 0 :xx : 2 | 100
+ 51 0 :xx : 2 | 100
+ 50 0 :xx : 2 | 100
+ 49 0 :xx : 2 | 100
+ 48 0 :xx : 2 | 100
+ 47 0 :xx : 2 | 100
+ 46 0 :xx : 2 | 100
+ 45 0 :xx : 2 | 100
+ 44 0 :xx : 2 | 100
+ 43 0 :xx : 2 | 100
+ 42 0 :xx : 2 | 100
+ 41 0 :xx : 2 | 100
+ 40 0 :xx : 2 | 100
+ 39 0 :xx : 2 | 100
+ 38 0 :xx : 2 | 100
+ 37 0 :xx : 2 | 100
+ 36 0 :xx : 2 | 100
+ 35 0 :xx : 2 | 100
+ 34 0 :xx : 2 | 100
+ 33 0 :xx : 2 | 100
+ 32 0 :xx : 2 | 100
+ 31 0 :xx : 2 | 100
+ 30 0 :xx : 2 | 100
+ 29 0 :xx : 2 | 100
+ 28 0 :xx : 2 | 100
+ 27 0 :xx : 2 | 100
+ 26 0 :xx : 2 | 100
+ 25 0 :xx : 2 | 100
+ 24 0 :xx : 2 | 100
+ 23 0 :xx : 2 | 100
+ 22 0 :xx : 2 | 100
+ 21 0 :_X : 2 | 100
+ 20 0 :_X : 2 | 100
+ 19 0 :_X : 2 | 100
+ 18 0 :_X : 2 | 100
+ 17 0 :_X : 2 | 100
+ 16 0 :_X : 2 | 100
+ 15 0 :_X : 2 | 100
+ 14 0 :_X : 2 | 100
+ 13 0 :_X : 2 | 100
+ 12 0 :_X : 2 | 100
+ 11 0 :_X : 2 | 100
+ 10 0 :_X : 2 | 100
+ 9 0 :_X : 2 | 100
+ 8 0 :_X : 2 | 100
+ 7 0 :_X : 2 | 100
+ 6 0 :_X : 2 | 100
+ 5 0 :_X : 2 | 100
+ 4 0 :_X : 2 | 100
+ 3 0 :_X : 2 | 100
+ 2 0 :_X : 2 | 100
+ 1 0 :_X : 2 | 100
+ 0 0 : X : 2 | 100
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackbanner.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackbanner.ksh
new file mode 100644
index 000000000000..f055a08c13e6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackbanner.ksh
@@ -0,0 +1,75 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+let width=8
+
+function outputchar
+{
+ banner $3 | /bin/nawk -v line=$1 -v pos=$2 -v width=$width '{ \
+ for (i = 1; i <= length($0); i++) { \
+ if (substr($0, i, 1) == " ") \
+ continue; \
+ printf("\t@letter%d[%d] = lquantize(%d, 0, 40, 1);\n", \
+ line, NR, i + (pos * width));
+ } \
+ }'
+}
+
+function outputstr
+{
+ let pos=0;
+ let line=0
+
+ printf "#pragma D option aggpack\n#pragma D option aggsortkey\n"
+
+ printf "BEGIN\n{\n"
+ for c in `echo "$1" | /bin/nawk '{ \
+ for (i = 1; i <= length($0); i++) { \
+ c = substr($0, i, 1); \
+ printf("%s\n", c == " " ? "space" : \
+ c == "\n" ? "newline" : c); \
+ } \
+ }'`; do
+ if [[ "$c" == "space" ]]; then
+ let line=line+1
+ let pos=0
+ continue
+ fi
+
+ outputchar $line $pos $c
+ let pos=pos+1
+ done
+
+ let i=0
+
+ while [[ $i -le $line ]]; do
+ printf "\tprinta(@letter%d);\n" $i
+ let i=i+1
+ done
+ printf "\texit(0);\n}\n"
+}
+
+dtrace -qs /dev/stdin -x encoding=utf8 <<EOF
+`outputstr "why must i do this"`
+EOF
+
+dtrace -qs /dev/stdin -x encoding=ascii -x aggzoom <<EOF
+`outputstr "i am not well"`
+EOF
+
+dtrace -qs /dev/stdin -x encoding=utf8 -x aggzoom <<EOF
+`outputstr "send help"`
+EOF
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackbanner.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackbanner.ksh.out
new file mode 100644
index 000000000000..a7eba38785bc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackbanner.ksh.out
@@ -0,0 +1,102 @@
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : ▂ ▂ ▂ ▂ ▂ ▂ : >= 40 | 6
+ 3 < 0 : ▂ ▂ ▂ ▂ ▂ ▂ : >= 40 | 6
+ 4 < 0 : ▂ ▂ ▂▂▂▂▂▂ ▂ : >= 40 | 9
+ 5 < 0 : ▂ ▂▂ ▂ ▂ ▂ ▂ : >= 40 | 7
+ 6 < 0 : ▂▂ ▂▂ ▂ ▂ ▂ : >= 40 | 7
+ 7 < 0 : ▂ ▂ ▂ ▂ ▂ : >= 40 | 5
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : ▂ ▂ ▂ ▂ ▂▂▂▂ ▂▂▂▂▂ : >= 40 | 13
+ 3 < 0 : ▂▂ ▂▂ ▂ ▂ ▂ ▂ : >= 40 | 8
+ 4 < 0 : ▂ ▂▂ ▂ ▂ ▂ ▂▂▂▂ ▂ : >= 40 | 11
+ 5 < 0 : ▂ ▂ ▂ ▂ ▂ ▂ : >= 40 | 6
+ 6 < 0 : ▂ ▂ ▂ ▂ ▂ ▂ ▂ : >= 40 | 7
+ 7 < 0 : ▂ ▂ ▂▂▂▂ ▂▂▂▂ ▂ : >= 40 | 11
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : █ : >= 40 | 1
+ 3 < 0 : █ : >= 40 | 1
+ 4 < 0 : █ : >= 40 | 1
+ 5 < 0 : █ : >= 40 | 1
+ 6 < 0 : █ : >= 40 | 1
+ 7 < 0 : █ : >= 40 | 1
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : ▂▂▂▂▂ ▂▂▂▂ : >= 40 | 9
+ 3 < 0 : ▃ ▃ ▃ ▃ : >= 40 | 4
+ 4 < 0 : ▃ ▃ ▃ ▃ : >= 40 | 4
+ 5 < 0 : ▃ ▃ ▃ ▃ : >= 40 | 4
+ 6 < 0 : ▃ ▃ ▃ ▃ : >= 40 | 4
+ 7 < 0 : ▂▂▂▂▂ ▂▂▂▂ : >= 40 | 9
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : ▂▂▂▂▂ ▂ ▂ ▂ ▂▂▂▂ : >= 40 | 12
+ 3 < 0 : ▂ ▂ ▂ ▂ ▂ : >= 40 | 5
+ 4 < 0 : ▂ ▂▂▂▂▂▂ ▂ ▂▂▂▂ : >= 40 | 12
+ 5 < 0 : ▂ ▂ ▂ ▂ ▂ : >= 40 | 5
+ 6 < 0 : ▂ ▂ ▂ ▂ ▂ ▂ : >= 40 | 6
+ 7 < 0 : ▂ ▂ ▂ ▂ ▂▂▂▂ : >= 40 | 8
+
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : X : >= 40 | 1
+ 3 < 0 : X : >= 40 | 1
+ 4 < 0 : X : >= 40 | 1
+ 5 < 0 : X : >= 40 | 1
+ 6 < 0 : X : >= 40 | 1
+ 7 < 0 : X : >= 40 | 1
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : XX X X : >= 40 | 4
+ 3 < 0 : X X XX XX : >= 40 | 6
+ 4 < 0 : X X X XX X : >= 40 | 6
+ 5 < 0 : XXXXXX X X : >= 40 | 8
+ 6 < 0 : X X X X : >= 40 | 4
+ 7 < 0 : X X X X : >= 40 | 4
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : X X XXXX XXXXX : >= 40 | 11
+ 3 < 0 : XX X X X X : >= 40 | 6
+ 4 < 0 : X X X X X X : >= 40 | 6
+ 5 < 0 : X X X X X X : >= 40 | 6
+ 6 < 0 : X XX X X X : >= 40 | 6
+ 7 < 0 : X X XXXX X : >= 40 | 7
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : X X XXXXXX X X : >= 40 | 10
+ 3 < 0 : X X X X X : >= 40 | 5
+ 4 < 0 : X X XXXXX X X : >= 40 | 9
+ 5 < 0 : X XX X X X X : >= 40 | 7
+ 6 < 0 : XX XX X X X : >= 40 | 7
+ 7 < 0 : X X XXXXXX XXXXXX XXXXXX : >= 40 | 20
+
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : ████ ██████ █ █ █████ : >= 40 | 17
+ 3 < 0 : █ █ ██ █ █ █ : >= 40 | 7
+ 4 < 0 : ████ █████ █ █ █ █ █ : >= 40 | 14
+ 5 < 0 : █ █ █ █ █ █ █ : >= 40 | 7
+ 6 < 0 : █ █ █ █ ██ █ █ : >= 40 | 8
+ 7 < 0 : ████ ██████ █ █ █████ : >= 40 | 17
+
+
+ key min .------------------------------------------. max | count
+ 2 < 0 : █ █ ██████ █ █████ : >= 40 | 14
+ 3 < 0 : █ █ █ █ █ █ : >= 40 | 6
+ 4 < 0 : ██████ █████ █ █ █ : >= 40 | 14
+ 5 < 0 : █ █ █ █ █████ : >= 40 | 9
+ 6 < 0 : █ █ █ █ █ : >= 40 | 5
+ 7 < 0 : █ █ ██████ ██████ █ : >= 40 | 15
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackzoom.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackzoom.d
new file mode 100644
index 000000000000..2f297e25939c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackzoom.d
@@ -0,0 +1,43 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option encoding=ascii
+#pragma D option quiet
+
+tick-1ms
+/i++ < 30/
+{
+ @[1] = lquantize(i, 0, 40, 1, 1000);
+ @[2] = lquantize(i, 0, 40, 1, 1000);
+ @[3] = lquantize(i, 0, 40, 1, 1000);
+}
+
+tick-1ms
+/i == 40/
+{
+ @[1] = lquantize(0, 0, 40, 1, 1);
+ @[1] = lquantize(i, 0, 40, 1, 2000);
+ @[2] = lquantize(0, 0, 40, 1, 1);
+ @[2] = lquantize(i, 0, 40, 1, 2000);
+ @[3] = lquantize(0, 0, 40, 1, 1);
+ @[3] = lquantize(i, 0, 40, 1, 2000);
+
+ printa(@);
+ setopt("aggpack");
+ printa(@);
+ setopt("aggzoom");
+ printa(@);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackzoom.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackzoom.d.out
new file mode 100644
index 000000000000..a22a2a4a173e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggpackzoom.d.out
@@ -0,0 +1,149 @@
+
+ 1
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 | 1
+ 1 |@ 1000
+ 2 |@ 1000
+ 3 |@ 1000
+ 4 |@ 1000
+ 5 |@ 1000
+ 6 |@ 1000
+ 7 |@ 1000
+ 8 |@ 1000
+ 9 |@ 1000
+ 10 |@ 1000
+ 11 |@ 1000
+ 12 |@ 1000
+ 13 |@ 1000
+ 14 |@ 1000
+ 15 |@ 1000
+ 16 |@ 1000
+ 17 |@ 1000
+ 18 |@ 1000
+ 19 |@ 1000
+ 20 |@ 1000
+ 21 |@ 1000
+ 22 |@ 1000
+ 23 |@ 1000
+ 24 |@ 1000
+ 25 |@ 1000
+ 26 |@ 1000
+ 27 |@ 1000
+ 28 |@ 1000
+ 29 |@ 1000
+ 30 |@ 1000
+ 31 | 0
+ 32 | 0
+ 33 | 0
+ 34 | 0
+ 35 | 0
+ 36 | 0
+ 37 | 0
+ 38 | 0
+ 39 | 0
+ >= 40 |@@ 2000
+
+ 2
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 | 1
+ 1 |@ 1000
+ 2 |@ 1000
+ 3 |@ 1000
+ 4 |@ 1000
+ 5 |@ 1000
+ 6 |@ 1000
+ 7 |@ 1000
+ 8 |@ 1000
+ 9 |@ 1000
+ 10 |@ 1000
+ 11 |@ 1000
+ 12 |@ 1000
+ 13 |@ 1000
+ 14 |@ 1000
+ 15 |@ 1000
+ 16 |@ 1000
+ 17 |@ 1000
+ 18 |@ 1000
+ 19 |@ 1000
+ 20 |@ 1000
+ 21 |@ 1000
+ 22 |@ 1000
+ 23 |@ 1000
+ 24 |@ 1000
+ 25 |@ 1000
+ 26 |@ 1000
+ 27 |@ 1000
+ 28 |@ 1000
+ 29 |@ 1000
+ 30 |@ 1000
+ 31 | 0
+ 32 | 0
+ 33 | 0
+ 34 | 0
+ 35 | 0
+ 36 | 0
+ 37 | 0
+ 38 | 0
+ 39 | 0
+ >= 40 |@@ 2000
+
+ 3
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 | 1
+ 1 |@ 1000
+ 2 |@ 1000
+ 3 |@ 1000
+ 4 |@ 1000
+ 5 |@ 1000
+ 6 |@ 1000
+ 7 |@ 1000
+ 8 |@ 1000
+ 9 |@ 1000
+ 10 |@ 1000
+ 11 |@ 1000
+ 12 |@ 1000
+ 13 |@ 1000
+ 14 |@ 1000
+ 15 |@ 1000
+ 16 |@ 1000
+ 17 |@ 1000
+ 18 |@ 1000
+ 19 |@ 1000
+ 20 |@ 1000
+ 21 |@ 1000
+ 22 |@ 1000
+ 23 |@ 1000
+ 24 |@ 1000
+ 25 |@ 1000
+ 26 |@ 1000
+ 27 |@ 1000
+ 28 |@ 1000
+ 29 |@ 1000
+ 30 |@ 1000
+ 31 | 0
+ 32 | 0
+ 33 | 0
+ 34 | 0
+ 35 | 0
+ 36 | 0
+ 37 | 0
+ 38 | 0
+ 39 | 0
+ >= 40 |@@ 2000
+
+
+
+ key min .------------------------------------------. max | count
+ 1 < 0 : _______________________________ _: >= 40 | 32001
+ 2 < 0 : _______________________________ _: >= 40 | 32001
+ 3 < 0 : _______________________________ _: >= 40 | 32001
+
+
+ key min .------------------------------------------. max | count
+ 1 < 0 : _xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx X: >= 40 | 32001
+ 2 < 0 : _xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx X: >= 40 | 32001
+ 3 < 0 : _xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx X: >= 40 | 32001
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggzoom.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggzoom.d
new file mode 100644
index 000000000000..f237d26272f4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggzoom.d
@@ -0,0 +1,35 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option encoding=ascii
+#pragma D option quiet
+
+tick-1ms
+/i++ < 90/
+{
+ @ = lquantize(i, 0, 100, 1, 1000);
+}
+
+tick-1ms
+/i == 100/
+{
+ @ = lquantize(i++, 0, 100, 1, 2000);
+ @ = lquantize(i++, 0, 100, 1, 3000);
+
+ printa(@);
+ setopt("aggzoom");
+ printa(@);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggzoom.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggzoom.d.out
new file mode 100644
index 000000000000..acddf7f731ad
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.aggzoom.d.out
@@ -0,0 +1,211 @@
+
+
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 | 1000
+ 2 | 1000
+ 3 | 1000
+ 4 | 1000
+ 5 | 1000
+ 6 | 1000
+ 7 | 1000
+ 8 | 1000
+ 9 | 1000
+ 10 | 1000
+ 11 | 1000
+ 12 | 1000
+ 13 | 1000
+ 14 | 1000
+ 15 | 1000
+ 16 | 1000
+ 17 | 1000
+ 18 | 1000
+ 19 | 1000
+ 20 | 1000
+ 21 | 1000
+ 22 | 1000
+ 23 | 1000
+ 24 | 1000
+ 25 | 1000
+ 26 | 1000
+ 27 | 1000
+ 28 | 1000
+ 29 | 1000
+ 30 | 1000
+ 31 | 1000
+ 32 | 1000
+ 33 | 1000
+ 34 | 1000
+ 35 | 1000
+ 36 | 1000
+ 37 | 1000
+ 38 | 1000
+ 39 | 1000
+ 40 | 1000
+ 41 | 1000
+ 42 | 1000
+ 43 | 1000
+ 44 | 1000
+ 45 | 1000
+ 46 | 1000
+ 47 | 1000
+ 48 | 1000
+ 49 | 1000
+ 50 | 1000
+ 51 | 1000
+ 52 | 1000
+ 53 | 1000
+ 54 | 1000
+ 55 | 1000
+ 56 | 1000
+ 57 | 1000
+ 58 | 1000
+ 59 | 1000
+ 60 | 1000
+ 61 | 1000
+ 62 | 1000
+ 63 | 1000
+ 64 | 1000
+ 65 | 1000
+ 66 | 1000
+ 67 | 1000
+ 68 | 1000
+ 69 | 1000
+ 70 | 1000
+ 71 | 1000
+ 72 | 1000
+ 73 | 1000
+ 74 | 1000
+ 75 | 1000
+ 76 | 1000
+ 77 | 1000
+ 78 | 1000
+ 79 | 1000
+ 80 | 1000
+ 81 | 1000
+ 82 | 1000
+ 83 | 1000
+ 84 | 1000
+ 85 | 1000
+ 86 | 1000
+ 87 | 1000
+ 88 | 1000
+ 89 | 1000
+ 90 | 1000
+ 91 | 0
+ 92 | 0
+ 93 | 0
+ 94 | 0
+ 95 | 0
+ 96 | 0
+ 97 | 0
+ 98 | 0
+ 99 | 0
+ >= 100 |@@ 5000
+
+
+
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@ 1000
+ 2 |@@@@@@@@ 1000
+ 3 |@@@@@@@@ 1000
+ 4 |@@@@@@@@ 1000
+ 5 |@@@@@@@@ 1000
+ 6 |@@@@@@@@ 1000
+ 7 |@@@@@@@@ 1000
+ 8 |@@@@@@@@ 1000
+ 9 |@@@@@@@@ 1000
+ 10 |@@@@@@@@ 1000
+ 11 |@@@@@@@@ 1000
+ 12 |@@@@@@@@ 1000
+ 13 |@@@@@@@@ 1000
+ 14 |@@@@@@@@ 1000
+ 15 |@@@@@@@@ 1000
+ 16 |@@@@@@@@ 1000
+ 17 |@@@@@@@@ 1000
+ 18 |@@@@@@@@ 1000
+ 19 |@@@@@@@@ 1000
+ 20 |@@@@@@@@ 1000
+ 21 |@@@@@@@@ 1000
+ 22 |@@@@@@@@ 1000
+ 23 |@@@@@@@@ 1000
+ 24 |@@@@@@@@ 1000
+ 25 |@@@@@@@@ 1000
+ 26 |@@@@@@@@ 1000
+ 27 |@@@@@@@@ 1000
+ 28 |@@@@@@@@ 1000
+ 29 |@@@@@@@@ 1000
+ 30 |@@@@@@@@ 1000
+ 31 |@@@@@@@@ 1000
+ 32 |@@@@@@@@ 1000
+ 33 |@@@@@@@@ 1000
+ 34 |@@@@@@@@ 1000
+ 35 |@@@@@@@@ 1000
+ 36 |@@@@@@@@ 1000
+ 37 |@@@@@@@@ 1000
+ 38 |@@@@@@@@ 1000
+ 39 |@@@@@@@@ 1000
+ 40 |@@@@@@@@ 1000
+ 41 |@@@@@@@@ 1000
+ 42 |@@@@@@@@ 1000
+ 43 |@@@@@@@@ 1000
+ 44 |@@@@@@@@ 1000
+ 45 |@@@@@@@@ 1000
+ 46 |@@@@@@@@ 1000
+ 47 |@@@@@@@@ 1000
+ 48 |@@@@@@@@ 1000
+ 49 |@@@@@@@@ 1000
+ 50 |@@@@@@@@ 1000
+ 51 |@@@@@@@@ 1000
+ 52 |@@@@@@@@ 1000
+ 53 |@@@@@@@@ 1000
+ 54 |@@@@@@@@ 1000
+ 55 |@@@@@@@@ 1000
+ 56 |@@@@@@@@ 1000
+ 57 |@@@@@@@@ 1000
+ 58 |@@@@@@@@ 1000
+ 59 |@@@@@@@@ 1000
+ 60 |@@@@@@@@ 1000
+ 61 |@@@@@@@@ 1000
+ 62 |@@@@@@@@ 1000
+ 63 |@@@@@@@@ 1000
+ 64 |@@@@@@@@ 1000
+ 65 |@@@@@@@@ 1000
+ 66 |@@@@@@@@ 1000
+ 67 |@@@@@@@@ 1000
+ 68 |@@@@@@@@ 1000
+ 69 |@@@@@@@@ 1000
+ 70 |@@@@@@@@ 1000
+ 71 |@@@@@@@@ 1000
+ 72 |@@@@@@@@ 1000
+ 73 |@@@@@@@@ 1000
+ 74 |@@@@@@@@ 1000
+ 75 |@@@@@@@@ 1000
+ 76 |@@@@@@@@ 1000
+ 77 |@@@@@@@@ 1000
+ 78 |@@@@@@@@ 1000
+ 79 |@@@@@@@@ 1000
+ 80 |@@@@@@@@ 1000
+ 81 |@@@@@@@@ 1000
+ 82 |@@@@@@@@ 1000
+ 83 |@@@@@@@@ 1000
+ 84 |@@@@@@@@ 1000
+ 85 |@@@@@@@@ 1000
+ 86 |@@@@@@@@ 1000
+ 87 |@@@@@@@@ 1000
+ 88 |@@@@@@@@ 1000
+ 89 |@@@@@@@@ 1000
+ 90 |@@@@@@@@ 1000
+ 91 | 0
+ 92 | 0
+ 93 | 0
+ 94 | 0
+ 95 | 0
+ 96 | 0
+ 97 | 0
+ 98 | 0
+ 99 | 0
+ >= 100 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5000
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.allquant.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.allquant.d
new file mode 100644
index 000000000000..26241b31ea4f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.allquant.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+int i;
+
+tick-10ms
+{
+ @ = quantize(1LL << i);
+ @ = quantize((1LL << i) + 1);
+ @ = quantize(-(1LL << i));
+ @ = quantize(-(1LL << i) - 1);
+ i++;
+}
+
+tick-10ms
+/i == 64/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.allquant.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.allquant.d.out
new file mode 100644
index 000000000000..356d6b46080e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.allquant.d.out
@@ -0,0 +1,131 @@
+
+
+ value ------------- Distribution ------------- count
+-4611686018427387904 |@ 5
+-2305843009213693952 | 2
+-1152921504606846976 | 2
+-576460752303423488 | 2
+-288230376151711744 | 2
+-144115188075855872 | 2
+-72057594037927936 | 2
+-36028797018963968 | 2
+-18014398509481984 | 2
+-9007199254740992 | 2
+-4503599627370496 | 2
+-2251799813685248 | 2
+-1125899906842624 | 2
+-562949953421312 | 2
+-281474976710656 | 2
+-140737488355328 | 2
+ -70368744177664 | 2
+ -35184372088832 | 2
+ -17592186044416 | 2
+ -8796093022208 | 2
+ -4398046511104 | 2
+ -2199023255552 | 2
+ -1099511627776 | 2
+ -549755813888 | 2
+ -274877906944 | 2
+ -137438953472 | 2
+ -68719476736 | 2
+ -34359738368 | 2
+ -17179869184 | 2
+ -8589934592 | 2
+ -4294967296 | 2
+ -2147483648 | 2
+ -1073741824 | 2
+ -536870912 | 2
+ -268435456 | 2
+ -134217728 | 2
+ -67108864 | 2
+ -33554432 | 2
+ -16777216 | 2
+ -8388608 | 2
+ -4194304 | 2
+ -2097152 | 2
+ -1048576 | 2
+ -524288 | 2
+ -262144 | 2
+ -131072 | 2
+ -65536 | 2
+ -32768 | 2
+ -16384 | 2
+ -8192 | 2
+ -4096 | 2
+ -2048 | 2
+ -1024 | 2
+ -512 | 2
+ -256 | 2
+ -128 | 2
+ -64 | 2
+ -32 | 2
+ -16 | 2
+ -8 | 2
+ -4 | 2
+ -2 | 3
+ -1 | 1
+ 0 | 0
+ 1 | 1
+ 2 | 3
+ 4 | 2
+ 8 | 2
+ 16 | 2
+ 32 | 2
+ 64 | 2
+ 128 | 2
+ 256 | 2
+ 512 | 2
+ 1024 | 2
+ 2048 | 2
+ 4096 | 2
+ 8192 | 2
+ 16384 | 2
+ 32768 | 2
+ 65536 | 2
+ 131072 | 2
+ 262144 | 2
+ 524288 | 2
+ 1048576 | 2
+ 2097152 | 2
+ 4194304 | 2
+ 8388608 | 2
+ 16777216 | 2
+ 33554432 | 2
+ 67108864 | 2
+ 134217728 | 2
+ 268435456 | 2
+ 536870912 | 2
+ 1073741824 | 2
+ 2147483648 | 2
+ 4294967296 | 2
+ 8589934592 | 2
+ 17179869184 | 2
+ 34359738368 | 2
+ 68719476736 | 2
+ 137438953472 | 2
+ 274877906944 | 2
+ 549755813888 | 2
+ 1099511627776 | 2
+ 2199023255552 | 2
+ 4398046511104 | 2
+ 8796093022208 | 2
+ 17592186044416 | 2
+ 35184372088832 | 2
+ 70368744177664 | 2
+ 140737488355328 | 2
+ 281474976710656 | 2
+ 562949953421312 | 2
+1125899906842624 | 2
+2251799813685248 | 2
+4503599627370496 | 2
+9007199254740992 | 2
+18014398509481984 | 2
+36028797018963968 | 2
+72057594037927936 | 2
+144115188075855872 | 2
+288230376151711744 | 2
+576460752303423488 | 2
+1152921504606846976 | 2
+2305843009213693952 | 2
+4611686018427387904 | 3
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg.d
new file mode 100644
index 000000000000..a4bfd3cd213d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Positive avg() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is a simple verifiable positive test of the avg() function.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a = avg(i);
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg.d.out
new file mode 100644
index 000000000000..e3c0687d05d5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg.d.out
@@ -0,0 +1,2 @@
+
+ 450
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg_neg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg_neg.d
new file mode 100644
index 000000000000..5c1e77d124e7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg_neg.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Positive avg() test using negative values
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is a simple verifiable positive test of the avg() function.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @ = avg(0);
+ @ = avg(-900);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg_neg.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg_neg.d.out
new file mode 100644
index 000000000000..3fafcd452ac7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.avg_neg.d.out
@@ -0,0 +1,2 @@
+
+ -450
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clear.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clear.d
new file mode 100644
index 000000000000..2acd8ee91758
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clear.d
@@ -0,0 +1,75 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for clearing aggregations
+ *
+ * SECTION: Aggregations/Clearing aggregations
+ *
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=50ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func[i%5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 10/
+{
+ printf("Aggregation data before clear():\n");
+ printa(@func);
+
+ clear(@func);
+
+ printf("Aggregation data after clear():\n");
+ printa(@func);
+ i++;
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("Final aggregation data:\n");
+ printa(@func);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clear.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clear.d.out
new file mode 100644
index 000000000000..486e4ac01a2f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clear.d.out
@@ -0,0 +1,22 @@
+Aggregation data before clear():
+
+ 0 500
+ 1 700
+ 2 900
+ 3 1100
+ 4 1300
+Aggregation data after clear():
+
+ 0 0
+ 1 0
+ 2 0
+ 3 0
+ 4 0
+Final aggregation data:
+
+ 0 1500
+ 1 2700
+ 2 2900
+ 3 3100
+ 4 3300
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg.d
new file mode 100644
index 000000000000..135e511b8d6d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Positive avg() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES:
+ * Verifies that printing a clear()'d aggregation with an avg()
+ * aggregation function doesn't cause problems.
+ *
+ */
+
+#pragma D option quiet
+
+tick-10ms
+/i++ < 5/
+{
+ @a = avg(timestamp);
+}
+
+tick-10ms
+/i == 5/
+{
+ exit(2);
+}
+
+END
+{
+ clear(@a);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg.d.out
new file mode 100644
index 000000000000..8d23188fd1f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg.d.out
@@ -0,0 +1,2 @@
+
+ 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg2.d
new file mode 100644
index 000000000000..0f7a9584c0c2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg2.d
@@ -0,0 +1,63 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Positive avg() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES:
+ * Verifies that printing a clear()'d aggregation with an avg()
+ * aggregation function of 0 doesn't cause divide-by-zero problems.
+ *
+ */
+
+#pragma D option quiet
+#pragma D option switchrate=50ms
+#pragma D option aggrate=1ms
+
+tick-100ms
+/(x++ % 5) == 0/
+{
+ @time = avg(0);
+}
+
+tick-100ms
+/x > 5 && x <= 20/
+{
+ printa(" %@d\n", @time);
+ clear(@time);
+}
+
+tick-100ms
+/x > 20/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg2.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg2.d.out
new file mode 100644
index 000000000000..7cceedda7a5f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearavg2.d.out
@@ -0,0 +1,16 @@
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.cleardenormalize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.cleardenormalize.d
new file mode 100644
index 000000000000..7aefed038d11
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.cleardenormalize.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Denormalized aggregations can be cleared
+ *
+ * SECTION: Aggregations/Normalization;
+ * Aggregations/Clearing aggregations
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=50ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i != 10 || i != 20/
+{
+ @func[i%5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 10/
+{
+ printf("Denormalized data before clear:\n");
+ denormalize(@func);
+ printa(@func);
+
+ clear(@func);
+
+ printf("Aggregation data after clear:\n");
+ printa(@func);
+ i++
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("Final (denormalized) aggregation data:\n");
+ denormalize(@func);
+ printa(@func);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.cleardenormalize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.cleardenormalize.d.out
new file mode 100644
index 000000000000..ed7f2f3493a4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.cleardenormalize.d.out
@@ -0,0 +1,22 @@
+Denormalized data before clear:
+
+ 0 500
+ 1 700
+ 2 900
+ 3 1100
+ 4 1300
+Aggregation data after clear:
+
+ 0 0
+ 1 0
+ 2 0
+ 3 0
+ 4 0
+Final (denormalized) aggregation data:
+
+ 0 1500
+ 1 2700
+ 2 2900
+ 3 3100
+ 4 3300
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearlquantize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearlquantize.d
new file mode 100644
index 000000000000..2d0ff83862da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearlquantize.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Positive lquantize()/clear() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES:
+ * Verifies that printing a clear()'d aggregation with an lquantize()
+ * aggregation function doesn't cause problems.
+ *
+ */
+
+
+#pragma D option switchrate=50ms
+#pragma D option aggrate=1ms
+#pragma D option quiet
+
+tick-100ms
+{
+ x++;
+ @a["linear"] = lquantize(x, 0, 100, 1);
+ @b["exp"] = quantize(x);
+}
+
+tick-100ms
+/(x % 5) == 0 && y++ < 5/
+{
+ printa(@a);
+ printa(@b);
+ clear(@a);
+ clear(@b);
+}
+
+tick-100ms
+/(x % 5) == 0 && y == 5/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearlquantize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearlquantize.d.out
new file mode 100644
index 000000000000..e7e2a6006530
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearlquantize.d.out
@@ -0,0 +1,94 @@
+
+ linear
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@ 1
+ 2 |@@@@@@@@ 1
+ 3 |@@@@@@@@ 1
+ 4 |@@@@@@@@ 1
+ 5 |@@@@@@@@ 1
+ 6 | 0
+
+
+ exp
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@ 1
+ 2 |@@@@@@@@@@@@@@@@ 2
+ 4 |@@@@@@@@@@@@@@@@ 2
+ 8 | 0
+
+
+ linear
+ value ------------- Distribution ------------- count
+ 5 | 0
+ 6 |@@@@@@@@ 1
+ 7 |@@@@@@@@ 1
+ 8 |@@@@@@@@ 1
+ 9 |@@@@@@@@ 1
+ 10 |@@@@@@@@ 1
+ 11 | 0
+
+
+ exp
+ value ------------- Distribution ------------- count
+ 2 | 0
+ 4 |@@@@@@@@@@@@@@@@ 2
+ 8 |@@@@@@@@@@@@@@@@@@@@@@@@ 3
+ 16 | 0
+
+
+ linear
+ value ------------- Distribution ------------- count
+ 10 | 0
+ 11 |@@@@@@@@ 1
+ 12 |@@@@@@@@ 1
+ 13 |@@@@@@@@ 1
+ 14 |@@@@@@@@ 1
+ 15 |@@@@@@@@ 1
+ 16 | 0
+
+
+ exp
+ value ------------- Distribution ------------- count
+ 4 | 0
+ 8 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 16 | 0
+
+
+ linear
+ value ------------- Distribution ------------- count
+ 15 | 0
+ 16 |@@@@@@@@ 1
+ 17 |@@@@@@@@ 1
+ 18 |@@@@@@@@ 1
+ 19 |@@@@@@@@ 1
+ 20 |@@@@@@@@ 1
+ 21 | 0
+
+
+ exp
+ value ------------- Distribution ------------- count
+ 8 | 0
+ 16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 32 | 0
+
+
+ linear
+ value ------------- Distribution ------------- count
+ 20 | 0
+ 21 |@@@@@@@@ 1
+ 22 |@@@@@@@@ 1
+ 23 |@@@@@@@@ 1
+ 24 |@@@@@@@@ 1
+ 25 |@@@@@@@@ 1
+ 26 | 0
+
+
+ exp
+ value ------------- Distribution ------------- count
+ 8 | 0
+ 16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 32 | 0
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearnormalize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearnormalize.d
new file mode 100644
index 000000000000..75cfa2d1c606
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearnormalize.d
@@ -0,0 +1,77 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Normalized aggregation data can be cleared
+ *
+ * SECTION: Aggregations/Normalization;
+ * Aggregations/Clearing aggregations
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=50ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func[i % 5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 10/
+{
+ printf("Normalized data before clear:\n");
+ normalize(@func, 5);
+ printa(@func);
+
+ clear(@func);
+
+ printf("Aggregation data after clear:\n");
+ printa(@func);
+ i++
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("Final (normalized) aggregation data:\n");
+ normalize(@func, 5);
+ printa(@func);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearnormalize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearnormalize.d.out
new file mode 100644
index 000000000000..e568427e16c5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearnormalize.d.out
@@ -0,0 +1,22 @@
+Normalized data before clear:
+
+ 0 100
+ 1 140
+ 2 180
+ 3 220
+ 4 260
+Aggregation data after clear:
+
+ 0 0
+ 1 0
+ 2 0
+ 3 0
+ 4 0
+Final (normalized) aggregation data:
+
+ 0 300
+ 1 540
+ 2 580
+ 3 620
+ 4 660
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearstddev.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearstddev.d
new file mode 100644
index 000000000000..af3ecd56a7fd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearstddev.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Positive stddev() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES:
+ * Verifies that printing a clear()'d aggregation with an stddev()
+ * aggregation function doesn't cause problems.
+ *
+ */
+
+#pragma D option quiet
+
+tick-10ms
+/i++ < 5/
+{
+ @a = stddev(timestamp);
+}
+
+tick-10ms
+/i == 5/
+{
+ exit(2);
+}
+
+END
+{
+ clear(@a);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearstddev.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearstddev.d.out
new file mode 100644
index 000000000000..8d23188fd1f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.clearstddev.d.out
@@ -0,0 +1,2 @@
+
+ 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count.d
new file mode 100644
index 000000000000..e81d123d9881
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Postive count() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a = count();
+ @a = count();
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count.d.out
new file mode 100644
index 000000000000..d34fd3b03750
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count.d.out
@@ -0,0 +1,2 @@
+
+ 2
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count2.d
new file mode 100644
index 000000000000..624b1b4eeff9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count2.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive count() test
+ *
+ * SECTION: Aggregations/Aggregations
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i != 10/
+{
+ i++;
+ @counts["tick-count"] = count();
+}
+
+tick-10ms
+/i == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count2.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count2.d.out
new file mode 100644
index 000000000000..4998a339f8e6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count2.d.out
@@ -0,0 +1,2 @@
+
+ tick-count 10
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count3.d
new file mode 100644
index 000000000000..5913ff604c6d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.count3.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test multiple count() calls.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i != 10/
+{
+ i++;
+ @counts1[execname] = count();
+ @counts2[execname, arg0] = count();
+}
+
+tick-10ms
+/i == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalize.d
new file mode 100644
index 000000000000..37269e82d9a0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalize.d
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Simple denormalization test
+ *
+ * SECTION: Aggregations/Normalization
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-10ms
+/i < 20/
+{
+ @func[i % 5] = sum(i * 100);
+ i++;
+}
+
+tick-10ms
+/i == 20/
+{
+ normalize(@func, 5);
+
+ printf("denormalized:");
+ denormalize(@func);
+ printa(@func);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalize.d.out
new file mode 100644
index 000000000000..fa4d0da79e94
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalize.d.out
@@ -0,0 +1,7 @@
+denormalized:
+ 0 3000
+ 1 3400
+ 2 3800
+ 3 4200
+ 4 4600
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalizeonly.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalizeonly.d
new file mode 100644
index 000000000000..d63a83e6f260
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalizeonly.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * denormalize() should work even if normalize() isn't called.
+ *
+ * SECTION: Aggregations/Normalization
+ *
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-10ms
+/i < 20/
+{
+ @func[i%5] = sum(i * 100);
+ i++;
+}
+
+tick-10ms
+/i == 20/
+{
+ printf("denormalized:");
+ denormalize(@func);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalizeonly.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalizeonly.d.out
new file mode 100644
index 000000000000..cc16f277b78c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.denormalizeonly.d.out
@@ -0,0 +1,6 @@
+denormalized:
+ 0 3000
+ 1 3400
+ 2 3800
+ 3 4200
+ 4 4600
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.fmtnormalize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.fmtnormalize.d
new file mode 100644
index 000000000000..8ff3aabf2796
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.fmtnormalize.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for normalization() with printa()
+ *
+ * SECTION: Aggregations/Normalization
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=50ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func[i % 5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("normalized data:\n");
+ normalize(@func, 5);
+ printa("%u %@u\n", @func);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.fmtnormalize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.fmtnormalize.d.out
new file mode 100644
index 000000000000..bbf345be29d7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.fmtnormalize.d.out
@@ -0,0 +1,7 @@
+normalized data:
+0 600
+1 680
+2 760
+3 840
+4 920
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.forms.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.forms.d
new file mode 100644
index 000000000000..2b08a12d5ede
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.forms.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive aggregation test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a = count();
+ @b = max(1);
+ @c[0] = count();
+ @d[0] = max(1);
+
+ printa("\n@a = %@u\n", @a);
+ printa("@b = %@u\n", @b);
+ printa("@c = %@u\n", @c);
+ printa("@d = %@u\n", @d);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.forms.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.forms.d.out
new file mode 100644
index 000000000000..1f31450d34a5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.forms.d.out
@@ -0,0 +1,6 @@
+
+@a = 1
+@b = 1
+@c = 1
+@d = 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.goodkey.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.goodkey.d
new file mode 100644
index 000000000000..46becd56eff6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.goodkey.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive aggregation key test
+ *
+ * SECTION: Aggregations/Aggregations
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i != 5/
+{
+ i++;
+ @counts[execname, pid, id, tid, arg0, vtimestamp ] = count();
+
+}
+
+tick-10ms
+/i == 5/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.keysort.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.keysort.d
new file mode 100644
index 000000000000..dbc8b6d27002
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.keysort.d
@@ -0,0 +1,108 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+ j = 0;
+
+ @tour["Ghent", i++, j] = sum(5 - j);
+ j++;
+
+ @tour["Berlin", i++, j] = sum(5 - j);
+ j++;
+
+ @tour["London", i++, j] = sum(5 - j);
+ @tour["Dublin", i++, j] = sum(5 - j);
+ j++;
+
+ @tour["Shanghai", i++, j] = sum(5 - j);
+ j++;
+
+ @tour["Zurich", i++, j] = sum(5 - j);
+ j++;
+
+ @tour["Regina", i++, j] = sum(5 - j);
+ @tour["Winnipeg", i++, j] = sum(5 - j);
+ @tour["Edmonton", i++, j] = sum(5 - j);
+ @tour["Calgary", i++, j] = sum(5 - j);
+ @tour["Vancouver", i++, j] = sum(5 - j);
+ @tour["Victoria", i++, j] = sum(5 - j);
+ j++;
+
+ @tour["Prague", i++, j] = sum(5 - j);
+ @tour["London", i++, j] = sum(5 - j);
+ j++;
+
+ @tour["Brisbane", i++, j] = sum(5 - j);
+ @tour["Sydney", i++, j] = sum(5 - j);
+ @tour["Melbourne", i++, j] = sum(5 - j);
+ j++;
+
+ setopt("aggsortkey", "false");
+ setopt("aggsortkeypos", "0");
+ @tour["Amsterdam", i++, j] = sum(5 - j);
+
+ printf("By value:\n");
+ printa("%20s %8d %8d %8@d\n", @tour);
+
+ setopt("aggsortkey");
+ printf("\nBy key, position 0:\n");
+ printa("%20s %8d %8d %8@d\n", @tour);
+
+ setopt("aggsortkeypos", "1");
+ printf("\nBy key, position 1:\n");
+ printa("%20s %8d %8d %8@d\n", @tour);
+
+ setopt("aggsortkeypos", "2");
+ printf("\nBy key, position 2:\n");
+ printa("%20s %8d %8d %8@d\n", @tour);
+
+ setopt("aggsortkey", "false");
+ setopt("aggsortkeypos", "0");
+ setopt("aggsortrev");
+
+ printf("\nReversed by value:\n");
+ printa("%20s %8d %8d %8@d\n", @tour);
+
+ setopt("aggsortkey");
+ printf("\nReversed by key, position 0:\n");
+ printa("%20s %8d %8d %8@d\n", @tour);
+
+ setopt("aggsortkeypos", "1");
+ printf("\nReversed by key, position 1:\n");
+ printa("%20s %8d %8d %8@d\n", @tour);
+
+ setopt("aggsortkeypos", "2");
+ printf("\nReversed by key, position 2:\n");
+ printa("%20s %8d %8d %8@d\n", @tour);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.keysort.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.keysort.d.out
new file mode 100644
index 000000000000..250d84b92250
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.keysort.d.out
@@ -0,0 +1,160 @@
+By value:
+ Amsterdam 17 8 -3
+ Brisbane 14 7 -2
+ Melbourne 16 7 -2
+ Sydney 15 7 -2
+ London 13 6 -1
+ Prague 12 6 -1
+ Calgary 9 5 0
+ Edmonton 8 5 0
+ Regina 6 5 0
+ Vancouver 10 5 0
+ Victoria 11 5 0
+ Winnipeg 7 5 0
+ Zurich 5 4 1
+ Shanghai 4 3 2
+ Dublin 3 2 3
+ London 2 2 3
+ Berlin 1 1 4
+ Ghent 0 0 5
+
+By key, position 0:
+ Amsterdam 17 8 -3
+ Berlin 1 1 4
+ Brisbane 14 7 -2
+ Calgary 9 5 0
+ Dublin 3 2 3
+ Edmonton 8 5 0
+ Ghent 0 0 5
+ London 2 2 3
+ London 13 6 -1
+ Melbourne 16 7 -2
+ Prague 12 6 -1
+ Regina 6 5 0
+ Shanghai 4 3 2
+ Sydney 15 7 -2
+ Vancouver 10 5 0
+ Victoria 11 5 0
+ Winnipeg 7 5 0
+ Zurich 5 4 1
+
+By key, position 1:
+ Ghent 0 0 5
+ Berlin 1 1 4
+ London 2 2 3
+ Dublin 3 2 3
+ Shanghai 4 3 2
+ Zurich 5 4 1
+ Regina 6 5 0
+ Winnipeg 7 5 0
+ Edmonton 8 5 0
+ Calgary 9 5 0
+ Vancouver 10 5 0
+ Victoria 11 5 0
+ Prague 12 6 -1
+ London 13 6 -1
+ Brisbane 14 7 -2
+ Sydney 15 7 -2
+ Melbourne 16 7 -2
+ Amsterdam 17 8 -3
+
+By key, position 2:
+ Ghent 0 0 5
+ Berlin 1 1 4
+ Dublin 3 2 3
+ London 2 2 3
+ Shanghai 4 3 2
+ Zurich 5 4 1
+ Calgary 9 5 0
+ Edmonton 8 5 0
+ Regina 6 5 0
+ Vancouver 10 5 0
+ Victoria 11 5 0
+ Winnipeg 7 5 0
+ London 13 6 -1
+ Prague 12 6 -1
+ Brisbane 14 7 -2
+ Melbourne 16 7 -2
+ Sydney 15 7 -2
+ Amsterdam 17 8 -3
+
+Reversed by value:
+ Ghent 0 0 5
+ Berlin 1 1 4
+ London 2 2 3
+ Dublin 3 2 3
+ Shanghai 4 3 2
+ Zurich 5 4 1
+ Winnipeg 7 5 0
+ Victoria 11 5 0
+ Vancouver 10 5 0
+ Regina 6 5 0
+ Edmonton 8 5 0
+ Calgary 9 5 0
+ Prague 12 6 -1
+ London 13 6 -1
+ Sydney 15 7 -2
+ Melbourne 16 7 -2
+ Brisbane 14 7 -2
+ Amsterdam 17 8 -3
+
+Reversed by key, position 0:
+ Zurich 5 4 1
+ Winnipeg 7 5 0
+ Victoria 11 5 0
+ Vancouver 10 5 0
+ Sydney 15 7 -2
+ Shanghai 4 3 2
+ Regina 6 5 0
+ Prague 12 6 -1
+ Melbourne 16 7 -2
+ London 13 6 -1
+ London 2 2 3
+ Ghent 0 0 5
+ Edmonton 8 5 0
+ Dublin 3 2 3
+ Calgary 9 5 0
+ Brisbane 14 7 -2
+ Berlin 1 1 4
+ Amsterdam 17 8 -3
+
+Reversed by key, position 1:
+ Amsterdam 17 8 -3
+ Melbourne 16 7 -2
+ Sydney 15 7 -2
+ Brisbane 14 7 -2
+ London 13 6 -1
+ Prague 12 6 -1
+ Victoria 11 5 0
+ Vancouver 10 5 0
+ Calgary 9 5 0
+ Edmonton 8 5 0
+ Winnipeg 7 5 0
+ Regina 6 5 0
+ Zurich 5 4 1
+ Shanghai 4 3 2
+ Dublin 3 2 3
+ London 2 2 3
+ Berlin 1 1 4
+ Ghent 0 0 5
+
+Reversed by key, position 2:
+ Amsterdam 17 8 -3
+ Sydney 15 7 -2
+ Melbourne 16 7 -2
+ Brisbane 14 7 -2
+ Prague 12 6 -1
+ London 13 6 -1
+ Winnipeg 7 5 0
+ Victoria 11 5 0
+ Vancouver 10 5 0
+ Regina 6 5 0
+ Edmonton 8 5 0
+ Calgary 9 5 0
+ Zurich 5 4 1
+ Shanghai 4 3 2
+ London 2 2 3
+ Dublin 3 2 3
+ Berlin 1 1 4
+ Ghent 0 0 5
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantize.d
new file mode 100644
index 000000000000..dd25f861caf2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantize.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive lquantize() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is verifiable simple positive test of the lquantize() function.
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a[i] = lquantize(i, -100, 1100, 100 );
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantize.d.out
new file mode 100644
index 000000000000..fecb4483c5ac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantize.d.out
@@ -0,0 +1,61 @@
+
+ 0
+ value ------------- Distribution ------------- count
+ -100 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 100 | 0
+
+ 100
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 100 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 200 | 0
+
+ 200
+ value ------------- Distribution ------------- count
+ 100 | 0
+ 200 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 300 | 0
+
+ 300
+ value ------------- Distribution ------------- count
+ 200 | 0
+ 300 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 400 | 0
+
+ 400
+ value ------------- Distribution ------------- count
+ 300 | 0
+ 400 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 500 | 0
+
+ 500
+ value ------------- Distribution ------------- count
+ 400 | 0
+ 500 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 600 | 0
+
+ 600
+ value ------------- Distribution ------------- count
+ 500 | 0
+ 600 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 700 | 0
+
+ 700
+ value ------------- Distribution ------------- count
+ 600 | 0
+ 700 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 800 | 0
+
+ 800
+ value ------------- Distribution ------------- count
+ 700 | 0
+ 800 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 900 | 0
+
+ 900
+ value ------------- Distribution ------------- count
+ 800 | 0
+ 900 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1000 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantnormal.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantnormal.d
new file mode 100644
index 000000000000..003f846f3884
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantnormal.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+tick-10ms
+/i++ < 10/
+{
+ @ = lquantize(i, 0, 10);
+ @ = lquantize(i, 0, 10);
+ @ = lquantize(i, 0, 10);
+ @ = lquantize(i, 0, 10);
+ @ = lquantize(i, 0, 10);
+}
+
+tick-10ms
+/i == 10/
+{
+ exit(0);
+}
+
+END
+{
+ normalize(@, 5);
+ printa(@);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantnormal.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantnormal.d.out
new file mode 100644
index 000000000000..76b55b9c0822
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantnormal.d.out
@@ -0,0 +1,16 @@
+
+
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@ 1
+ 2 |@@@@ 1
+ 3 |@@@@ 1
+ 4 |@@@@ 1
+ 5 |@@@@ 1
+ 6 |@@@@ 1
+ 7 |@@@@ 1
+ 8 |@@@@ 1
+ 9 |@@@@ 1
+ >= 10 |@@@@ 1
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantrange.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantrange.d
new file mode 100644
index 000000000000..e9e671657cb7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantrange.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ @["Nixon"] = lquantize(-20, -10, 10, 1, 25);
+ @["Hoover"] = lquantize(20, -10, 10, 1, -100);
+ @["Harding"] = lquantize(-10, -10, 10, 1, 15);
+ @["Bush"] = lquantize(10, -10, 10, 1, 150);
+
+ printa(@);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantrange.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantrange.d.out
new file mode 100644
index 000000000000..88d3505b495a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantrange.d.out
@@ -0,0 +1,23 @@
+
+ Hoover
+ value ------------- Distribution ------------- count
+ 9 | 0
+ >= 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -100
+
+ Nixon
+ value ------------- Distribution ------------- count
+ < -10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 25
+ -10 | 0
+
+ Harding
+ value ------------- Distribution ------------- count
+ < -10 | 0
+ -10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 15
+ -9 | 0
+
+ Bush
+ value ------------- Distribution ------------- count
+ 9 | 0
+ >= 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 150
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantround.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantround.d
new file mode 100644
index 000000000000..ad609ed207da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantround.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+/*
+ * This test verifies that the height of the ASCII quantization bars is
+ * determined using rounding and not truncated integer arithmetic.
+ */
+tick-10ms
+/i++ >= 27/
+{
+ exit(0);
+}
+
+tick-10ms
+/i > 8/
+{
+ @ = lquantize(2, 0, 4);
+}
+
+tick-10ms
+/i > 2 && i <= 8/
+{
+ @ = lquantize(1, 0, 4);
+}
+
+tick-10ms
+/i <= 2/
+{
+ @ = lquantize(0, 0, 4);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantround.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantround.d.out
new file mode 100644
index 000000000000..1aa94e33a8d4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantround.d.out
@@ -0,0 +1,9 @@
+
+
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@ 2
+ 1 |@@@@@@@@@ 6
+ 2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 19
+ 3 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantzero.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantzero.d
new file mode 100644
index 000000000000..3905f2bde346
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantzero.d
@@ -0,0 +1,96 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ a = 7;
+ b = 13;
+ val = (-a * b) + a;
+}
+
+tick-1ms
+{
+ incr = val % b;
+ val += a;
+}
+
+tick-1ms
+/val == 0/
+{
+ val += a;
+}
+
+tick-1ms
+/incr != 0/
+{
+ i++;
+ @one[i] = lquantize(0, 10, 20, 1, incr);
+ @two[i] = lquantize(0, 1, 20, 5, incr);
+ @three[i] = lquantize(0, 0, 20, 1, incr);
+ @four[i] = lquantize(0, -10, 10, 1, incr);
+ @five[i] = lquantize(0, -10, 0, 1, incr);
+ @six[i] = lquantize(0, -10, -1, 1, incr);
+ @seven[i] = lquantize(0, -10, -2, 1, incr);
+}
+
+tick-1ms
+/incr == 0/
+{
+ printf("Zero below the range:\n");
+ printa(@one);
+ printf("\n");
+
+ printf("Zero just below the range:\n");
+ printa(@two);
+ printf("\n");
+
+ printf("Zero at the bottom of the range:\n");
+ printa(@three);
+ printf("\n");
+
+ printf("Zero within the range:\n");
+ printa(@four);
+ printf("\n");
+
+ printf("Zero at the top of the range:\n");
+ printa(@five);
+ printf("\n");
+
+ printf("Zero just above the range:\n");
+ printa(@six);
+ printf("\n");
+
+ printf("Zero above the range:\n");
+ printa(@seven);
+ printf("\n");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantzero.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantzero.d.out
new file mode 100644
index 000000000000..330de38a7952
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.lquantzero.d.out
@@ -0,0 +1,910 @@
+Zero below the range:
+
+ 2
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+ 10 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+ 10 | 0
+
+ 6
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+ 10 | 0
+
+ 8
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+ 10 | 0
+
+ 10
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+ 10 | 0
+
+ 12
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+ 10 | 0
+
+ 1
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+ 10 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+ 10 | 0
+
+ 5
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+ 10 | 0
+
+ 7
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+ 10 | 0
+
+ 9
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+ 10 | 0
+
+ 11
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+ 10 | 0
+
+ 14
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 10 | 0
+
+ 16
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+ 10 | 0
+
+ 18
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+ 10 | 0
+
+ 20
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 10 | 0
+
+ 22
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 10 | 0
+
+ 24
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+ 10 | 0
+
+ 13
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+ 10 | 0
+
+ 15
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+ 10 | 0
+
+ 17
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+ 10 | 0
+
+ 19
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+ 10 | 0
+
+ 21
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+ 10 | 0
+
+ 23
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+ 10 | 0
+
+
+Zero just below the range:
+
+ 2
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+ 1 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+ 1 | 0
+
+ 6
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+ 1 | 0
+
+ 8
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+ 1 | 0
+
+ 10
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+ 1 | 0
+
+ 12
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+ 1 | 0
+
+ 1
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+ 1 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+ 1 | 0
+
+ 5
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+ 1 | 0
+
+ 7
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+ 1 | 0
+
+ 9
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+ 1 | 0
+
+ 11
+ value ------------- Distribution ------------- count
+ < 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+ 1 | 0
+
+ 14
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1 | 0
+
+ 16
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+ 1 | 0
+
+ 18
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+ 1 | 0
+
+ 20
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 1 | 0
+
+ 22
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 1 | 0
+
+ 24
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+ 1 | 0
+
+ 13
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+ 1 | 0
+
+ 15
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+ 1 | 0
+
+ 17
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+ 1 | 0
+
+ 19
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+ 1 | 0
+
+ 21
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+ 1 | 0
+
+ 23
+ value ------------- Distribution ------------- count
+ < 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+ 1 | 0
+
+
+Zero at the bottom of the range:
+
+ 2
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+ 1 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+ 1 | 0
+
+ 6
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+ 1 | 0
+
+ 8
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+ 1 | 0
+
+ 10
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+ 1 | 0
+
+ 12
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+ 1 | 0
+
+ 1
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+ 1 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+ 1 | 0
+
+ 5
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+ 1 | 0
+
+ 7
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+ 1 | 0
+
+ 9
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+ 1 | 0
+
+ 11
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+ 1 | 0
+
+ 14
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1 | 0
+
+ 16
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+ 1 | 0
+
+ 18
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+ 1 | 0
+
+ 20
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 1 | 0
+
+ 22
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 1 | 0
+
+ 24
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+ 1 | 0
+
+ 13
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+ 1 | 0
+
+ 15
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+ 1 | 0
+
+ 17
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+ 1 | 0
+
+ 19
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+ 1 | 0
+
+ 21
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+ 1 | 0
+
+ 23
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+ 1 | 0
+
+
+Zero within the range:
+
+ 2
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+ 1 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+ 1 | 0
+
+ 6
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+ 1 | 0
+
+ 8
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+ 1 | 0
+
+ 10
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+ 1 | 0
+
+ 12
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+ 1 | 0
+
+ 1
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+ 1 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+ 1 | 0
+
+ 5
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+ 1 | 0
+
+ 7
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+ 1 | 0
+
+ 9
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+ 1 | 0
+
+ 11
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+ 1 | 0
+
+ 14
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1 | 0
+
+ 16
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+ 1 | 0
+
+ 18
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+ 1 | 0
+
+ 20
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 1 | 0
+
+ 22
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 1 | 0
+
+ 24
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+ 1 | 0
+
+ 13
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+ 1 | 0
+
+ 15
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+ 1 | 0
+
+ 17
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+ 1 | 0
+
+ 19
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+ 1 | 0
+
+ 21
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+ 1 | 0
+
+ 23
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+ 1 | 0
+
+
+Zero at the top of the range:
+
+ 2
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+
+ 4
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+
+ 6
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+
+ 8
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+
+ 10
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+
+ 12
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+
+ 1
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+
+ 3
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+
+ 5
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+
+ 7
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+
+ 9
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+
+ 11
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+
+ 14
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+
+ 16
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+
+ 18
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+
+ 20
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+
+ 22
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+
+ 24
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+
+ 13
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+
+ 15
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+
+ 17
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+
+ 19
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+
+ 21
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+
+ 23
+ value ------------- Distribution ------------- count
+ -1 | 0
+ >= 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+
+
+Zero just above the range:
+
+ 2
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+
+ 4
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+
+ 6
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+
+ 8
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+
+ 10
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+
+ 12
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+
+ 1
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+
+ 3
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+
+ 5
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+
+ 7
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+
+ 9
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+
+ 11
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+
+ 14
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+
+ 16
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+
+ 18
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+
+ 20
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+
+ 22
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+
+ 24
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+
+ 13
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+
+ 15
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+
+ 17
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+
+ 19
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+
+ 21
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+
+ 23
+ value ------------- Distribution ------------- count
+ -2 | 0
+ >= -1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+
+
+Zero above the range:
+
+ 23
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+
+ 21
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+
+ 19
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+
+ 17
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+
+ 15
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+
+ 13
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+
+ 24
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+
+ 22
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+
+ 20
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+
+ 18
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+
+ 16
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+
+ 14
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+
+ 11
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+
+ 9
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+
+ 7
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+
+ 5
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+
+ 3
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+
+ 1
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+
+ 12
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+
+ 10
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+
+ 8
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+
+ 6
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+
+ 4
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+
+ 2
+ value ------------- Distribution ------------- count
+ -3 | 0
+ >= -2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max.d
new file mode 100644
index 000000000000..0c973ad56dc6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max.d
@@ -0,0 +1,58 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive max() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is verifiable simple positive test of the max() function.
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a = max(i);
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ printa(@a);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max.d.out
new file mode 100644
index 000000000000..d3957f4ccf12
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max.d.out
@@ -0,0 +1,3 @@
+
+ 900
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max_neg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max_neg.d
new file mode 100644
index 000000000000..63486e5fce21
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max_neg.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive max() test using negative values
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is verifiable simple positive test of the max() function.
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @ = max(0);
+ @ = max(-900);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max_neg.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max_neg.d.out
new file mode 100644
index 000000000000..8d23188fd1f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.max_neg.d.out
@@ -0,0 +1,2 @@
+
+ 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min.d
new file mode 100644
index 000000000000..aff5452e62be
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive min() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is verifiable simple positive test of the min() function.
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a = min(i);
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min.d.out
new file mode 100644
index 000000000000..8d23188fd1f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min.d.out
@@ -0,0 +1,2 @@
+
+ 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min_neg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min_neg.d
new file mode 100644
index 000000000000..20f0a56d8b88
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min_neg.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive min() test using negative values
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is verifiable simple positive test of the min() function.
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @ = min(0);
+ @ = min(-900);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min_neg.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min_neg.d.out
new file mode 100644
index 000000000000..461b29cfd2d3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.min_neg.d.out
@@ -0,0 +1,2 @@
+
+ -900
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs1.d
new file mode 100644
index 000000000000..c65fb529e062
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs1.d
@@ -0,0 +1,66 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Multiple aggregates can be used within the same D script.
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ time_1 = timestamp;
+ i = 0;
+}
+
+tick-10ms
+/i <= 10/
+{
+ time_2 = timestamp;
+ new_time = time_2 - time_1;
+ @a[pid] = max(new_time);
+ @b[pid] = min(new_time);
+ @c[pid] = avg(new_time);
+ @d[pid] = sum(new_time);
+ @e[pid] = quantize(new_time);
+ @f[pid] = stddev(new_time);
+ @g[timestamp] = max(new_time);
+ @h[timestamp] = quantize(new_time);
+ @i[timestamp] = lquantize(new_time, 0, 10000, 1000);
+
+ time_1 = time_2;
+ i++;
+}
+
+tick-10ms
+/i == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs2.d
new file mode 100644
index 000000000000..b34d73fa8b84
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs2.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Test multiple aggregations and the default output order
+ *
+ * SECTION: Aggregations/Aggregations;
+ * Aggregations/Output
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a = avg(i);
+ @b = sum(i);
+ @c = min(i);
+ @d = max(i);
+ @e = quantize(i);
+ @f = lquantize(i, 0, 1000, 100);
+ @g = stddev(i);
+
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs2.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs2.d.out
new file mode 100644
index 000000000000..579f78dd9bed
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs2.d.out
@@ -0,0 +1,37 @@
+
+ 450
+ 4500
+ 0
+ 900
+
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@ 1
+ 1 | 0
+ 2 | 0
+ 4 | 0
+ 8 | 0
+ 16 | 0
+ 32 | 0
+ 64 |@@@@ 1
+ 128 |@@@@ 1
+ 256 |@@@@@@@@@@@@ 3
+ 512 |@@@@@@@@@@@@@@@@ 4
+ 1024 | 0
+
+
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@ 1
+ 100 |@@@@ 1
+ 200 |@@@@ 1
+ 300 |@@@@ 1
+ 400 |@@@@ 1
+ 500 |@@@@ 1
+ 600 |@@@@ 1
+ 700 |@@@@ 1
+ 800 |@@@@ 1
+ 900 |@@@@ 1
+ >= 1000 | 0
+
+ 287
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs3.d
new file mode 100644
index 000000000000..21d2fa9e2d69
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs3.d
@@ -0,0 +1,74 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Test multiple aggregations and overriding default order with
+ * printa() statements.
+ *
+ * SECTION: Aggregations/Aggregations;
+ * Aggregations/Output
+ *
+ * NOTES: This is a simple verifiable test.
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a = count();
+ @b = avg(i);
+ @c = sum(i);
+ @d = min(i);
+ @e = max(i);
+ @f = quantize(i);
+ @g = lquantize(i, 0, 1000, 100);
+ @h = stddev(i);
+
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ printa("%@d\n", @h);
+ printa("%@d\n", @g);
+ printa("%@d\n", @f);
+ printa("%@d\n", @e);
+ printa("%@d\n", @d);
+ printa("%@d\n", @c);
+ printa("%@d\n", @b);
+ printa("%@d\n", @a);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs3.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs3.d.out
new file mode 100644
index 000000000000..ab976601b2af
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multiaggs3.d.out
@@ -0,0 +1,38 @@
+287
+
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@ 1
+ 100 |@@@@ 1
+ 200 |@@@@ 1
+ 300 |@@@@ 1
+ 400 |@@@@ 1
+ 500 |@@@@ 1
+ 600 |@@@@ 1
+ 700 |@@@@ 1
+ 800 |@@@@ 1
+ 900 |@@@@ 1
+ >= 1000 | 0
+
+
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@ 1
+ 1 | 0
+ 2 | 0
+ 4 | 0
+ 8 | 0
+ 16 | 0
+ 32 | 0
+ 64 |@@@@ 1
+ 128 |@@@@ 1
+ 256 |@@@@@@@@@@@@ 3
+ 512 |@@@@@@@@@@@@@@@@ 4
+ 1024 | 0
+
+900
+0
+4500
+450
+10
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multinormalize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multinormalize.d
new file mode 100644
index 000000000000..2cfa1848bd3d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multinormalize.d
@@ -0,0 +1,65 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Multiple aggregations are supported
+ *
+ * SECTION: Aggregations/Normalization
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=50ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func1[i % 5] = sum(i * 100);
+ @func2[i % 5 + 1] = sum(i * 200);
+ i++;
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("normalized data #1:\n");
+ normalize(@func1, 5);
+ printa(@func1);
+
+ printf("\nnormalized data #2:\n");
+ normalize(@func2, 5);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multinormalize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multinormalize.d.out
new file mode 100644
index 000000000000..992b31e21fed
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.multinormalize.d.out
@@ -0,0 +1,15 @@
+normalized data #1:
+
+ 0 600
+ 1 680
+ 2 760
+ 3 840
+ 4 920
+
+normalized data #2:
+
+ 1 1200
+ 2 1360
+ 3 1520
+ 4 1680
+ 5 1840
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.neglquant.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.neglquant.d
new file mode 100644
index 000000000000..d24884b5da6d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.neglquant.d
@@ -0,0 +1,150 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ @["j-church"] = lquantize(1, 0, 10, 1, 100);
+ @["j-church"] = lquantize(1, 0, 10, 1, -99);
+ @["j-church"] = lquantize(1, 0, 10, 1, -1);
+ val = 123;
+}
+
+BEGIN
+{
+ @["k-ingleside"] = lquantize(1, 0, 10, 1, -val);
+}
+
+BEGIN
+{
+ @["l-taraval"] = lquantize(0, 0, 10, 1, -val);
+ @["l-taraval"] = lquantize(-1, 0, 10, 1, -val);
+ @["l-taraval"] = lquantize(1, 0, 10, 1, val);
+ @["l-taraval"] = lquantize(1, 0, 10, 1, val);
+}
+
+BEGIN
+{
+ @["m-oceanview"] = lquantize(1, 0, 10, 1, (1 << 63) - 1);
+ @["m-oceanview"] = lquantize(1, 0, 10, 1);
+ @["m-oceanview"] = lquantize(2, 0, 10, 1, (1 << 63) - 1);
+ @["m-oceanview"] = lquantize(8, 0, 10, 1, 400000);
+}
+
+BEGIN
+{
+ @["n-judah"] = lquantize(1, 0, 10, 1, val);
+ @["n-judah"] = lquantize(2, 0, 10, 1, val);
+ @["n-judah"] = lquantize(2, 0, 10, 1, val);
+ @["n-judah"] = lquantize(2, 0, 10, 1);
+}
+
+BEGIN
+{
+ this->i = 1;
+ this->val = (1 << 63) - 1;
+
+ @["f-market"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["f-market"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["f-market"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["f-market"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["f-market"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["f-market"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["f-market"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+}
+
+BEGIN
+{
+ this->i = 1;
+
+ /*
+ * We want to test the ability to sort very large quantizations
+ * that differ by a small amount. Ideally, they would differ only
+ * by 1 -- but that is smaller than the precision of long doubles of
+ * this magnitude on x86. To assure that the same test works on x86
+ * just as it does on SPARC, we pick a value that is just larger than
+ * the precision at this magnitude. It should go without saying that
+ * this robustness on new ISAs very much depends on the precision
+ * of the long double representation.
+ */
+ this->val = (1 << 63) - 7;
+
+ @["s-castro"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["s-castro"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["s-castro"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["s-castro"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["s-castro"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["s-castro"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+
+ @["s-castro"] = lquantize(this->i, 0, 10, 1, this->val);
+ this->i++;
+ this->val = ((1 << 63) - 1) / this->i;
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.neglquant.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.neglquant.d.out
new file mode 100644
index 000000000000..3b7533b17145
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.neglquant.d.out
@@ -0,0 +1,64 @@
+
+ k-ingleside
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -123
+ 2 | 0
+
+ j-church
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 | 0
+ 1 | 0
+
+ l-taraval
+ value ------------- Distribution ------------- count
+ < 0 @@@@@| -123
+ 0 @@@@@| -123
+ 1 |@@@@@@@@@@ 246
+ 2 | 0
+
+ n-judah
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@ 123
+ 2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@ 247
+ 3 | 0
+
+ m-oceanview
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@| -9223372036854775808
+ 2 |@@@@@@@@@@ 9223372036854775807
+ 3 | 0
+ 4 | 0
+ 5 | 0
+ 6 | 0
+ 7 | 0
+ 8 | 400000
+ 9 | 0
+
+ s-castro
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@ 9223372036854775801
+ 2 |@@@@@@@@ 4611686018427387903
+ 3 |@@@@@ 3074457345618258602
+ 4 |@@@@ 2305843009213693951
+ 5 |@@@ 1844674407370955161
+ 6 |@@@ 1537228672809129301
+ 7 |@@ 1317624576693539401
+ 8 | 0
+
+ f-market
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@ 9223372036854775807
+ 2 |@@@@@@@@ 4611686018427387903
+ 3 |@@@@@ 3074457345618258602
+ 4 |@@@@ 2305843009213693951
+ 5 |@@@ 1844674407370955161
+ 6 |@@@ 1537228672809129301
+ 7 |@@ 1317624576693539401
+ 8 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negorder.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negorder.d
new file mode 100644
index 000000000000..440c4839459e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negorder.d
@@ -0,0 +1,85 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = 7;
+ b = 13;
+ val = (-a * b) + a;
+}
+
+tick-1ms
+{
+ incr = val % b;
+ val += a;
+}
+
+tick-1ms
+/val == 0/
+{
+ val += a;
+}
+
+tick-1ms
+/incr != 0/
+{
+ i++;
+ @quanty[i] = quantize(1, incr);
+ @lquanty[i] = lquantize(1, -10, 10, 1, incr);
+ @summy[i] = sum(incr);
+ @maxxy[i] = max(incr);
+ @minny[i] = min(incr);
+}
+
+tick-1ms
+/incr == 0/
+{
+ printf("Ordering of quantize() with some negative weights:\n");
+ printa(@quanty);
+ printf("\n");
+
+ printf("Ordering of lquantize() with some negative weights:\n");
+ printa(@lquanty);
+ printf("\n");
+
+ printf("Ordering of sum() with some negative weights:\n");
+ printa(@summy);
+ printf("\n");
+
+ printf("Ordering of max() with some negative weights:\n");
+ printa(@maxxy);
+ printf("\n");
+
+ printf("Ordering of min() with some negative weights:\n");
+ printa(@minny);
+ printf("\n");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negorder.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negorder.d.out
new file mode 100644
index 000000000000..a03b685044a4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negorder.d.out
@@ -0,0 +1,376 @@
+Ordering of quantize() with some negative weights:
+
+ 2
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+ 2 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+ 2 | 0
+
+ 6
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+ 2 | 0
+
+ 8
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+ 2 | 0
+
+ 10
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+ 2 | 0
+
+ 12
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+ 2 | 0
+
+ 1
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+ 2 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+ 2 | 0
+
+ 5
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+ 2 | 0
+
+ 7
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+ 2 | 0
+
+ 9
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+ 2 | 0
+
+ 11
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+ 2 | 0
+
+ 14
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 2 | 0
+
+ 16
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+ 2 | 0
+
+ 18
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+ 2 | 0
+
+ 20
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 2 | 0
+
+ 22
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 2 | 0
+
+ 24
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+ 2 | 0
+
+ 13
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+ 2 | 0
+
+ 15
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+ 2 | 0
+
+ 17
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+ 2 | 0
+
+ 19
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+ 2 | 0
+
+ 21
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+ 2 | 0
+
+ 23
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+ 2 | 0
+
+
+Ordering of lquantize() with some negative weights:
+
+ 2
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+ 2 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+ 2 | 0
+
+ 6
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+ 2 | 0
+
+ 8
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+ 2 | 0
+
+ 10
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+ 2 | 0
+
+ 12
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+ 2 | 0
+
+ 1
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+ 2 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+ 2 | 0
+
+ 5
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+ 2 | 0
+
+ 7
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+ 2 | 0
+
+ 9
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+ 2 | 0
+
+ 11
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+ 2 | 0
+
+ 14
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 2 | 0
+
+ 16
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+ 2 | 0
+
+ 18
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+ 2 | 0
+
+ 20
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 2 | 0
+
+ 22
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 2 | 0
+
+ 24
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+ 2 | 0
+
+ 13
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+ 2 | 0
+
+ 15
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+ 2 | 0
+
+ 17
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+ 2 | 0
+
+ 19
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+ 2 | 0
+
+ 21
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+ 2 | 0
+
+ 23
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+ 2 | 0
+
+
+Ordering of sum() with some negative weights:
+
+ 2 -12
+ 4 -11
+ 6 -10
+ 8 -9
+ 10 -8
+ 12 -7
+ 1 -6
+ 3 -5
+ 5 -4
+ 7 -3
+ 9 -2
+ 11 -1
+ 14 1
+ 16 2
+ 18 3
+ 20 4
+ 22 5
+ 24 6
+ 13 7
+ 15 8
+ 17 9
+ 19 10
+ 21 11
+ 23 12
+
+Ordering of max() with some negative weights:
+
+ 2 -12
+ 4 -11
+ 6 -10
+ 8 -9
+ 10 -8
+ 12 -7
+ 1 -6
+ 3 -5
+ 5 -4
+ 7 -3
+ 9 -2
+ 11 -1
+ 14 1
+ 16 2
+ 18 3
+ 20 4
+ 22 5
+ 24 6
+ 13 7
+ 15 8
+ 17 9
+ 19 10
+ 21 11
+ 23 12
+
+Ordering of min() with some negative weights:
+
+ 2 -12
+ 4 -11
+ 6 -10
+ 8 -9
+ 10 -8
+ 12 -7
+ 1 -6
+ 3 -5
+ 5 -4
+ 7 -3
+ 9 -2
+ 11 -1
+ 14 1
+ 16 2
+ 18 3
+ 20 4
+ 22 5
+ 24 6
+ 13 7
+ 15 8
+ 17 9
+ 19 10
+ 21 11
+ 23 12
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negquant.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negquant.d
new file mode 100644
index 000000000000..bbc7263dc58c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negquant.d
@@ -0,0 +1,115 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ @["j-church"] = quantize(1, 100);
+ @["j-church"] = quantize(1, -99);
+ @["j-church"] = quantize(1, -1);
+ val = 123;
+}
+
+BEGIN
+{
+ @["k-ingleside"] = quantize(1, -val);
+}
+
+BEGIN
+{
+ @["l-taraval"] = quantize(0, -val);
+ @["l-taraval"] = quantize(-1, -val);
+ @["l-taraval"] = quantize(1, val);
+ @["l-taraval"] = quantize(1, val);
+}
+
+BEGIN
+{
+ @["m-oceanview"] = quantize(1, (1 << 63) - 1);
+ @["m-oceanview"] = quantize(1);
+ @["m-oceanview"] = quantize(2, (1 << 63) - 1);
+ @["m-oceanview"] = quantize(8, 400000);
+}
+
+BEGIN
+{
+ @["n-judah"] = quantize(1, val);
+ @["n-judah"] = quantize(2, val);
+ @["n-judah"] = quantize(2, val);
+ @["n-judah"] = quantize(2);
+}
+
+BEGIN
+{
+ this->i = 1;
+ this->val = (1 << 63) - 1;
+
+ @["f-market"] = quantize(this->i, this->val);
+ this->i <<= 1;
+ this->val >>= 1;
+
+ @["f-market"] = quantize(this->i, this->val);
+ this->i <<= 1;
+ this->val >>= 1;
+
+ @["f-market"] = quantize(this->i, this->val);
+ this->i <<= 1;
+ this->val >>= 1;
+
+ @["f-market"] = quantize(this->i, this->val);
+ this->i <<= 1;
+ this->val >>= 1;
+}
+
+BEGIN
+{
+ this->i = 1;
+ this->val = (1 << 63) - 4;
+
+ @["s-castro"] = quantize(this->i, this->val);
+ this->i <<= 1;
+ this->val >>= 1;
+
+ @["s-castro"] = quantize(this->i, this->val);
+ this->i <<= 1;
+ this->val >>= 1;
+
+ @["s-castro"] = quantize(this->i, this->val);
+ this->i <<= 1;
+ this->val >>= 1;
+
+ @["s-castro"] = quantize(this->i, this->val);
+ this->i <<= 1;
+ this->val >>= 1;
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negquant.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negquant.d.out
new file mode 100644
index 000000000000..f8466b3367ba
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negquant.d.out
@@ -0,0 +1,55 @@
+
+ k-ingleside
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -123
+ 2 | 0
+
+ j-church
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ l-taraval
+ value ------------- Distribution ------------- count
+ -2 | 0
+ -1 @@@@@| -123
+ 0 @@@@@| -123
+ 1 |@@@@@@@@@@ 246
+ 2 | 0
+
+ n-judah
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@ 123
+ 2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@ 247
+ 4 | 0
+
+ m-oceanview
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 @@@@@@@@@@| -9223372036854775808
+ 2 |@@@@@@@@@@ 9223372036854775807
+ 4 | 0
+ 8 | 400000
+ 16 | 0
+
+ s-castro
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@ 9223372036854775804
+ 2 |@@@@@@@@@@@ 4611686018427387902
+ 4 |@@@@@ 2305843009213693951
+ 8 |@@@ 1152921504606846975
+ 16 | 0
+
+ f-market
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@ 9223372036854775807
+ 2 |@@@@@@@@@@@ 4611686018427387903
+ 4 |@@@@@ 2305843009213693951
+ 8 |@@@ 1152921504606846975
+ 16 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtrunc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtrunc.d
new file mode 100644
index 000000000000..f90eae134805
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtrunc.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+int i;
+
+tick-10ms
+/i < 100/
+{
+ @[i] = sum(i);
+ i++;
+}
+
+tick-10ms
+/i == 100/
+{
+ exit(0);
+}
+
+END
+{
+ trunc(@, -10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtrunc.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtrunc.d.out
new file mode 100644
index 000000000000..c1b07a6dae09
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtrunc.d.out
@@ -0,0 +1,11 @@
+
+ 0 0
+ 1 1
+ 2 2
+ 3 3
+ 4 4
+ 5 5
+ 6 6
+ 7 7
+ 8 8
+ 9 9
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtruncquant.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtruncquant.d
new file mode 100644
index 000000000000..2a13d659331c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtruncquant.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+int i;
+
+tick-10ms
+/i < 100/
+{
+ @[i] = lquantize(i, 0, 150);
+ @[i] = lquantize(i + 1, 0, 150);
+ @[i] = lquantize(i + 2, 0, 150);
+ @[i] = lquantize(i + 3, 0, 150);
+ i++;
+}
+
+tick-10ms
+/i == 100/
+{
+ exit(0);
+}
+
+END
+{
+ trunc(@, -5);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtruncquant.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtruncquant.d.out
new file mode 100644
index 000000000000..264aa392e2ab
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.negtruncquant.d.out
@@ -0,0 +1,46 @@
+
+ 0
+ value ------------- Distribution ------------- count
+ < 0 | 0
+ 0 |@@@@@@@@@@ 1
+ 1 |@@@@@@@@@@ 1
+ 2 |@@@@@@@@@@ 1
+ 3 |@@@@@@@@@@ 1
+ 4 | 0
+
+ 1
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@ 1
+ 2 |@@@@@@@@@@ 1
+ 3 |@@@@@@@@@@ 1
+ 4 |@@@@@@@@@@ 1
+ 5 | 0
+
+ 2
+ value ------------- Distribution ------------- count
+ 1 | 0
+ 2 |@@@@@@@@@@ 1
+ 3 |@@@@@@@@@@ 1
+ 4 |@@@@@@@@@@ 1
+ 5 |@@@@@@@@@@ 1
+ 6 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ 2 | 0
+ 3 |@@@@@@@@@@ 1
+ 4 |@@@@@@@@@@ 1
+ 5 |@@@@@@@@@@ 1
+ 6 |@@@@@@@@@@ 1
+ 7 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ 3 | 0
+ 4 |@@@@@@@@@@ 1
+ 5 |@@@@@@@@@@ 1
+ 6 |@@@@@@@@@@ 1
+ 7 |@@@@@@@@@@ 1
+ 8 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.normalize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.normalize.d
new file mode 100644
index 000000000000..0bcc0fe9134e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.normalize.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for normalization()
+ *
+ * SECTION: Aggregations/Normalization
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=50ms
+
+BEGIN
+{
+ i = 0;
+ start = timestamp;
+}
+
+tick-100ms
+/i < 20/
+{
+ @func[i % 5] = sum(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 20/
+{
+ printf("normalized data:\n");
+ normalize(@func, 5);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.normalize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.normalize.d.out
new file mode 100644
index 000000000000..11193e65d810
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.normalize.d.out
@@ -0,0 +1,7 @@
+normalized data:
+
+ 0 600
+ 1 680
+ 2 760
+ 3 840
+ 4 920
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.order.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.order.d
new file mode 100644
index 000000000000..139001164b6a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.order.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ @[8] = sum(1);
+ @[6] = sum(1);
+ @[7] = sum(1);
+ @[5] = sum(1);
+ @[3] = sum(1);
+ @[0] = sum(1);
+ @[9] = sum(1);
+
+ @tour["Ghent"] = sum(1);
+ @tour["Berlin"] = sum(1);
+ @tour["London"] = sum(1);
+ @tour["Dublin"] = sum(1);
+ @tour["Shanghai"] = sum(1);
+ @tour["Zurich"] = sum(1);
+ @tour["Regina"] = sum(1);
+ @tour["Winnipeg"] = sum(1);
+ @tour["Edmonton"] = sum(1);
+ @tour["Calgary"] = sum(1);
+
+ @ate[8, "Rice"] = sum(1);
+ @ate[8, "Oatmeal"] = sum(1);
+ @ate[8, "Barley"] = sum(1);
+ @ate[8, "Carrots"] = sum(1);
+ @ate[8, "Sweet potato"] = sum(1);
+ @ate[8, "Asparagus"] = sum(1);
+ @ate[8, "Squash"] = sum(1);
+
+ @chars['a'] = sum(1);
+ @chars['s'] = sum(1);
+ @chars['d'] = sum(1);
+ @chars['f'] = sum(1);
+
+ printa("%d\n", @);
+ printf("\n");
+
+ printa("%s\n", @tour);
+ printf("\n");
+
+ printa("%d %s\n", @ate);
+ printf("\n");
+
+ printa("%c\n", @chars);
+ printf("\n");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.order.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.order.d.out
new file mode 100644
index 000000000000..505b0f32c9b9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.order.d.out
@@ -0,0 +1,33 @@
+0
+3
+5
+6
+7
+8
+9
+
+Berlin
+Calgary
+Dublin
+Edmonton
+Ghent
+London
+Regina
+Shanghai
+Winnipeg
+Zurich
+
+8 Asparagus
+8 Barley
+8 Carrots
+8 Oatmeal
+8 Rice
+8 Squash
+8 Sweet potato
+
+a
+d
+f
+s
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantize.d
new file mode 100644
index 000000000000..fad472af4b95
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantize.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive quantize() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is verifiable simple positive test of the quantize() function.
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a[i] = quantize(i);
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantize.d.out
new file mode 100644
index 000000000000..f4882ed2bf5d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantize.d.out
@@ -0,0 +1,61 @@
+
+ 0
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1 | 0
+
+ 100
+ value ------------- Distribution ------------- count
+ 32 | 0
+ 64 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 128 | 0
+
+ 200
+ value ------------- Distribution ------------- count
+ 64 | 0
+ 128 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 256 | 0
+
+ 300
+ value ------------- Distribution ------------- count
+ 128 | 0
+ 256 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 512 | 0
+
+ 400
+ value ------------- Distribution ------------- count
+ 128 | 0
+ 256 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 512 | 0
+
+ 500
+ value ------------- Distribution ------------- count
+ 128 | 0
+ 256 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 512 | 0
+
+ 600
+ value ------------- Distribution ------------- count
+ 256 | 0
+ 512 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1024 | 0
+
+ 700
+ value ------------- Distribution ------------- count
+ 256 | 0
+ 512 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1024 | 0
+
+ 800
+ value ------------- Distribution ------------- count
+ 256 | 0
+ 512 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1024 | 0
+
+ 900
+ value ------------- Distribution ------------- count
+ 256 | 0
+ 512 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1024 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantmany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantmany.d
new file mode 100644
index 000000000000..e547b1ec73e4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantmany.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+int64_t val, shift;
+
+tick-1ms
+/val == 0/
+{
+ val = -(1 << shift);
+ shift++;
+}
+
+tick-1ms
+/shift == 32/
+{
+ exit(0);
+}
+
+tick-1ms
+/val == -1/
+{
+ val = (1 << shift);
+}
+
+tick-1ms
+{
+ @[shift] = quantize(val, val);
+ val >>= 1;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantmany.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantmany.d.out
new file mode 100644
index 000000000000..45df24910b84
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantmany.d.out
@@ -0,0 +1,1208 @@
+
+ 1
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@ 1
+ 2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+ 4 | 0
+
+ 2
+ value ------------- Distribution ------------- count
+ -4 | 0
+ -2 @@@@| -2
+ -1 | 0
+ 0 | 0
+ 1 |@@ 1
+ 2 |@@@@ 2
+ 4 |@@@@@@@@@ 4
+ 8 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ -8 | 0
+ -4 @@@@| -4
+ -2 @@| -2
+ -1 | 0
+ 0 | 0
+ 1 |@ 1
+ 2 |@@ 2
+ 4 |@@@@ 4
+ 8 |@@@@@@@@ 8
+ 16 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ -16 | 0
+ -8 @@@@| -8
+ -4 @@| -4
+ -2 @| -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 |@ 2
+ 4 |@@ 4
+ 8 |@@@@ 8
+ 16 |@@@@@@@ 16
+ 32 | 0
+
+ 5
+ value ------------- Distribution ------------- count
+ -32 | 0
+ -16 @@@| -16
+ -8 @@| -8
+ -4 @| -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 |@ 4
+ 8 |@@ 8
+ 16 |@@@ 16
+ 32 |@@@@@@@ 32
+ 64 | 0
+
+ 6
+ value ------------- Distribution ------------- count
+ -64 | 0
+ -32 @@@| -32
+ -16 @@| -16
+ -8 @| -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 |@ 8
+ 16 |@@ 16
+ 32 |@@@ 32
+ 64 |@@@@@@@ 64
+ 128 | 0
+
+ 7
+ value ------------- Distribution ------------- count
+ -128 | 0
+ -64 @@@| -64
+ -32 @@| -32
+ -16 @| -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 |@ 16
+ 32 |@@ 32
+ 64 |@@@ 64
+ 128 |@@@@@@@ 128
+ 256 | 0
+
+ 8
+ value ------------- Distribution ------------- count
+ -256 | 0
+ -128 @@@| -128
+ -64 @@| -64
+ -32 @| -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 |@ 32
+ 64 |@@ 64
+ 128 |@@@ 128
+ 256 |@@@@@@@ 256
+ 512 | 0
+
+ 9
+ value ------------- Distribution ------------- count
+ -512 | 0
+ -256 @@@| -256
+ -128 @@| -128
+ -64 @| -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 |@ 64
+ 128 |@@ 128
+ 256 |@@@ 256
+ 512 |@@@@@@@ 512
+ 1024 | 0
+
+ 10
+ value ------------- Distribution ------------- count
+ -1024 | 0
+ -512 @@@| -512
+ -256 @@| -256
+ -128 @| -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 |@ 128
+ 256 |@@ 256
+ 512 |@@@ 512
+ 1024 |@@@@@@@ 1024
+ 2048 | 0
+
+ 11
+ value ------------- Distribution ------------- count
+ -2048 | 0
+ -1024 @@@| -1024
+ -512 @@| -512
+ -256 @| -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 |@ 256
+ 512 |@@ 512
+ 1024 |@@@ 1024
+ 2048 |@@@@@@@ 2048
+ 4096 | 0
+
+ 12
+ value ------------- Distribution ------------- count
+ -4096 | 0
+ -2048 @@@| -2048
+ -1024 @@| -1024
+ -512 @| -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 |@ 512
+ 1024 |@@ 1024
+ 2048 |@@@ 2048
+ 4096 |@@@@@@@ 4096
+ 8192 | 0
+
+ 13
+ value ------------- Distribution ------------- count
+ -8192 | 0
+ -4096 @@@| -4096
+ -2048 @@| -2048
+ -1024 @| -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 |@ 1024
+ 2048 |@@ 2048
+ 4096 |@@@ 4096
+ 8192 |@@@@@@@ 8192
+ 16384 | 0
+
+ 14
+ value ------------- Distribution ------------- count
+ -16384 | 0
+ -8192 @@@| -8192
+ -4096 @@| -4096
+ -2048 @| -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 |@ 2048
+ 4096 |@@ 4096
+ 8192 |@@@ 8192
+ 16384 |@@@@@@@ 16384
+ 32768 | 0
+
+ 15
+ value ------------- Distribution ------------- count
+ -32768 | 0
+ -16384 @@@| -16384
+ -8192 @@| -8192
+ -4096 @| -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 |@ 4096
+ 8192 |@@ 8192
+ 16384 |@@@ 16384
+ 32768 |@@@@@@@ 32768
+ 65536 | 0
+
+ 16
+ value ------------- Distribution ------------- count
+ -65536 | 0
+ -32768 @@@| -32768
+ -16384 @@| -16384
+ -8192 @| -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 |@ 8192
+ 16384 |@@ 16384
+ 32768 |@@@ 32768
+ 65536 |@@@@@@@ 65536
+ 131072 | 0
+
+ 17
+ value ------------- Distribution ------------- count
+ -131072 | 0
+ -65536 @@@| -65536
+ -32768 @@| -32768
+ -16384 @| -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 |@ 16384
+ 32768 |@@ 32768
+ 65536 |@@@ 65536
+ 131072 |@@@@@@@ 131072
+ 262144 | 0
+
+ 18
+ value ------------- Distribution ------------- count
+ -262144 | 0
+ -131072 @@@| -131072
+ -65536 @@| -65536
+ -32768 @| -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 |@ 32768
+ 65536 |@@ 65536
+ 131072 |@@@ 131072
+ 262144 |@@@@@@@ 262144
+ 524288 | 0
+
+ 19
+ value ------------- Distribution ------------- count
+ -524288 | 0
+ -262144 @@@| -262144
+ -131072 @@| -131072
+ -65536 @| -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 |@ 65536
+ 131072 |@@ 131072
+ 262144 |@@@ 262144
+ 524288 |@@@@@@@ 524288
+ 1048576 | 0
+
+ 20
+ value ------------- Distribution ------------- count
+ -1048576 | 0
+ -524288 @@@| -524288
+ -262144 @@| -262144
+ -131072 @| -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 |@ 131072
+ 262144 |@@ 262144
+ 524288 |@@@ 524288
+ 1048576 |@@@@@@@ 1048576
+ 2097152 | 0
+
+ 21
+ value ------------- Distribution ------------- count
+ -2097152 | 0
+ -1048576 @@@| -1048576
+ -524288 @@| -524288
+ -262144 @| -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 |@ 262144
+ 524288 |@@ 524288
+ 1048576 |@@@ 1048576
+ 2097152 |@@@@@@@ 2097152
+ 4194304 | 0
+
+ 22
+ value ------------- Distribution ------------- count
+ -4194304 | 0
+ -2097152 @@@| -2097152
+ -1048576 @@| -1048576
+ -524288 @| -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 |@ 524288
+ 1048576 |@@ 1048576
+ 2097152 |@@@ 2097152
+ 4194304 |@@@@@@@ 4194304
+ 8388608 | 0
+
+ 23
+ value ------------- Distribution ------------- count
+ -8388608 | 0
+ -4194304 @@@| -4194304
+ -2097152 @@| -2097152
+ -1048576 @| -1048576
+ -524288 | -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 | 524288
+ 1048576 |@ 1048576
+ 2097152 |@@ 2097152
+ 4194304 |@@@ 4194304
+ 8388608 |@@@@@@@ 8388608
+ 16777216 | 0
+
+ 24
+ value ------------- Distribution ------------- count
+ -16777216 | 0
+ -8388608 @@@| -8388608
+ -4194304 @@| -4194304
+ -2097152 @| -2097152
+ -1048576 | -1048576
+ -524288 | -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 | 524288
+ 1048576 | 1048576
+ 2097152 |@ 2097152
+ 4194304 |@@ 4194304
+ 8388608 |@@@ 8388608
+ 16777216 |@@@@@@@ 16777216
+ 33554432 | 0
+
+ 25
+ value ------------- Distribution ------------- count
+ -33554432 | 0
+ -16777216 @@@| -16777216
+ -8388608 @@| -8388608
+ -4194304 @| -4194304
+ -2097152 | -2097152
+ -1048576 | -1048576
+ -524288 | -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 | 524288
+ 1048576 | 1048576
+ 2097152 | 2097152
+ 4194304 |@ 4194304
+ 8388608 |@@ 8388608
+ 16777216 |@@@ 16777216
+ 33554432 |@@@@@@@ 33554432
+ 67108864 | 0
+
+ 26
+ value ------------- Distribution ------------- count
+ -67108864 | 0
+ -33554432 @@@| -33554432
+ -16777216 @@| -16777216
+ -8388608 @| -8388608
+ -4194304 | -4194304
+ -2097152 | -2097152
+ -1048576 | -1048576
+ -524288 | -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 | 524288
+ 1048576 | 1048576
+ 2097152 | 2097152
+ 4194304 | 4194304
+ 8388608 |@ 8388608
+ 16777216 |@@ 16777216
+ 33554432 |@@@ 33554432
+ 67108864 |@@@@@@@ 67108864
+ 134217728 | 0
+
+ 27
+ value ------------- Distribution ------------- count
+ -134217728 | 0
+ -67108864 @@@| -67108864
+ -33554432 @@| -33554432
+ -16777216 @| -16777216
+ -8388608 | -8388608
+ -4194304 | -4194304
+ -2097152 | -2097152
+ -1048576 | -1048576
+ -524288 | -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 | 524288
+ 1048576 | 1048576
+ 2097152 | 2097152
+ 4194304 | 4194304
+ 8388608 | 8388608
+ 16777216 |@ 16777216
+ 33554432 |@@ 33554432
+ 67108864 |@@@ 67108864
+ 134217728 |@@@@@@@ 134217728
+ 268435456 | 0
+
+ 28
+ value ------------- Distribution ------------- count
+ -268435456 | 0
+ -134217728 @@@| -134217728
+ -67108864 @@| -67108864
+ -33554432 @| -33554432
+ -16777216 | -16777216
+ -8388608 | -8388608
+ -4194304 | -4194304
+ -2097152 | -2097152
+ -1048576 | -1048576
+ -524288 | -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 | 524288
+ 1048576 | 1048576
+ 2097152 | 2097152
+ 4194304 | 4194304
+ 8388608 | 8388608
+ 16777216 | 16777216
+ 33554432 |@ 33554432
+ 67108864 |@@ 67108864
+ 134217728 |@@@ 134217728
+ 268435456 |@@@@@@@ 268435456
+ 536870912 | 0
+
+ 29
+ value ------------- Distribution ------------- count
+ -536870912 | 0
+ -268435456 @@@| -268435456
+ -134217728 @@| -134217728
+ -67108864 @| -67108864
+ -33554432 | -33554432
+ -16777216 | -16777216
+ -8388608 | -8388608
+ -4194304 | -4194304
+ -2097152 | -2097152
+ -1048576 | -1048576
+ -524288 | -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 | 524288
+ 1048576 | 1048576
+ 2097152 | 2097152
+ 4194304 | 4194304
+ 8388608 | 8388608
+ 16777216 | 16777216
+ 33554432 | 33554432
+ 67108864 |@ 67108864
+ 134217728 |@@ 134217728
+ 268435456 |@@@ 268435456
+ 536870912 |@@@@@@@ 536870912
+ 1073741824 | 0
+
+ 30
+ value ------------- Distribution ------------- count
+ -1073741824 | 0
+ -536870912 @@@| -536870912
+ -268435456 @@| -268435456
+ -134217728 @| -134217728
+ -67108864 | -67108864
+ -33554432 | -33554432
+ -16777216 | -16777216
+ -8388608 | -8388608
+ -4194304 | -4194304
+ -2097152 | -2097152
+ -1048576 | -1048576
+ -524288 | -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 | 524288
+ 1048576 | 1048576
+ 2097152 | 2097152
+ 4194304 | 4194304
+ 8388608 | 8388608
+ 16777216 | 16777216
+ 33554432 | 33554432
+ 67108864 | 67108864
+ 134217728 |@ 134217728
+ 268435456 |@@ 268435456
+ 536870912 |@@@ 536870912
+ 1073741824 |@@@@@@@ 1073741824
+ 2147483648 | 0
+
+ 31
+ value ------------- Distribution ------------- count
+ -2147483648 | 0
+ -1073741824 @@@| -1073741824
+ -536870912 @@| -536870912
+ -268435456 @| -268435456
+ -134217728 | -134217728
+ -67108864 | -67108864
+ -33554432 | -33554432
+ -16777216 | -16777216
+ -8388608 | -8388608
+ -4194304 | -4194304
+ -2097152 | -2097152
+ -1048576 | -1048576
+ -524288 | -524288
+ -262144 | -262144
+ -131072 | -131072
+ -65536 | -65536
+ -32768 | -32768
+ -16384 | -16384
+ -8192 | -8192
+ -4096 | -4096
+ -2048 | -2048
+ -1024 | -1024
+ -512 | -512
+ -256 | -256
+ -128 | -128
+ -64 | -64
+ -32 | -32
+ -16 | -16
+ -8 | -8
+ -4 | -4
+ -2 | -2
+ -1 | 0
+ 0 | 0
+ 1 | 1
+ 2 | 2
+ 4 | 4
+ 8 | 8
+ 16 | 16
+ 32 | 32
+ 64 | 64
+ 128 | 128
+ 256 | 256
+ 512 | 512
+ 1024 | 1024
+ 2048 | 2048
+ 4096 | 4096
+ 8192 | 8192
+ 16384 | 16384
+ 32768 | 32768
+ 65536 | 65536
+ 131072 | 131072
+ 262144 | 262144
+ 524288 | 524288
+ 1048576 | 1048576
+ 2097152 | 2097152
+ 4194304 | 4194304
+ 8388608 | 8388608
+ 16777216 | 16777216
+ 33554432 | 33554432
+ 67108864 | 67108864
+ 134217728 | 134217728
+ 268435456 |@ 268435456
+ 536870912 |@@ 536870912
+ 1073741824 |@@@ 1073741824
+ 2147483648 |@@@@@@@ 2147483648
+ 4294967296 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantround.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantround.d
new file mode 100644
index 000000000000..c40d69c081df
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantround.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+/*
+ * This test verifies that the height of the ASCII quantization bars is
+ * determined using rounding and not truncated integer arithmetic.
+ */
+tick-10ms
+/i++ >= 27/
+{
+ exit(0);
+}
+
+tick-10ms
+/i > 8/
+{
+ @ = quantize(2);
+}
+
+tick-10ms
+/i > 2 && i <= 8/
+{
+ @ = quantize(1);
+}
+
+tick-10ms
+/i <= 2/
+{
+ @ = quantize(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantround.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantround.d.out
new file mode 100644
index 000000000000..9b89ec144489
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantround.d.out
@@ -0,0 +1,9 @@
+
+
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@ 2
+ 1 |@@@@@@@@@ 6
+ 2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 19
+ 4 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantzero.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantzero.d
new file mode 100644
index 000000000000..bfa633cd03ac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantzero.d
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ a = 7;
+ b = 13;
+ val = (-a * b) + a;
+}
+
+tick-1ms
+{
+ incr = val % b;
+ val += a;
+}
+
+tick-1ms
+/val == 0/
+{
+ val += a;
+}
+
+tick-1ms
+/incr != 0/
+{
+ i++;
+ @[i] = quantize(0, incr);
+}
+
+tick-1ms
+/incr == 0/
+{
+ printa(@);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantzero.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantzero.d.out
new file mode 100644
index 000000000000..c2c1cf02b6d7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.quantzero.d.out
@@ -0,0 +1,146 @@
+
+ 2
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+ 1 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+ 1 | 0
+
+ 6
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+ 1 | 0
+
+ 8
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+ 1 | 0
+
+ 10
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+ 1 | 0
+
+ 12
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+ 1 | 0
+
+ 1
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+ 1 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+ 1 | 0
+
+ 5
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+ 1 | 0
+
+ 7
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+ 1 | 0
+
+ 9
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+ 1 | 0
+
+ 11
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+ 1 | 0
+
+ 14
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 1 | 0
+
+ 16
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+ 1 | 0
+
+ 18
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+ 1 | 0
+
+ 20
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 1 | 0
+
+ 22
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 1 | 0
+
+ 24
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+ 1 | 0
+
+ 13
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+ 1 | 0
+
+ 15
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+ 1 | 0
+
+ 17
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+ 1 | 0
+
+ 19
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+ 1 | 0
+
+ 21
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+ 1 | 0
+
+ 23
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+ 1 | 0
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signature.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signature.d
new file mode 100644
index 000000000000..baa951a4e26c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signature.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is a simple test to make sure that signature checking works properly
+ * for the fake-o types.
+ */
+BEGIN
+{
+ @stk[ustack()] = count();
+ @symmy[sym(0)] = count();
+ @usymmy[usym(0)] = count();
+ @funky[func(0)] = count();
+ @ufunky[ufunc(0)] = count();
+ @moddy[mod(0)] = count();
+ @umoddy[umod(0)] = count();
+}
+
+BEGIN
+{
+ @stk[ustack()] = count();
+ @symmy[sym(0)] = count();
+ @usymmy[usym(0)] = count();
+ @funky[func(0)] = count();
+ @ufunky[ufunc(0)] = count();
+ @moddy[mod(0)] = count();
+ @umoddy[umod(0)] = count();
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeys.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeys.d
new file mode 100644
index 000000000000..ed3d13141af3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeys.d
@@ -0,0 +1,120 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Signed integer keys print and sort as expected.
+ *
+ * SECTION: Aggregations, Printing Aggregations
+ *
+ * NOTES: DTrace sorts integer keys as unsigned values, yet prints 32-
+ * and 64-bit integers as signed values. Since the Java DTrace API is
+ * expected to emulate this behavior, this test was added to ensure that
+ * the behavior is preserved. Consistency with trace() output is also
+ * tested.
+ */
+
+#pragma D option quiet
+#pragma D option aggsortkey
+
+BEGIN
+{
+ trace((char)-2);
+ trace("\n");
+ trace((char)-1);
+ trace("\n");
+ trace((char)0);
+ trace("\n");
+ trace((char)1);
+ trace("\n");
+ trace((char)2);
+ trace("\n");
+ trace("\n");
+
+ trace((short)-2);
+ trace("\n");
+ trace((short)-1);
+ trace("\n");
+ trace((short)0);
+ trace("\n");
+ trace((short)1);
+ trace("\n");
+ trace((short)2);
+ trace("\n");
+ trace("\n");
+
+ trace(-2);
+ trace("\n");
+ trace(-1);
+ trace("\n");
+ trace(0);
+ trace("\n");
+ trace(1);
+ trace("\n");
+ trace(2);
+ trace("\n");
+ trace("\n");
+
+ trace((long long)-2);
+ trace("\n");
+ trace((long long)-1);
+ trace("\n");
+ trace((long long)0);
+ trace("\n");
+ trace((long long)1);
+ trace("\n");
+ trace((long long)2);
+ trace("\n");
+
+ @i8[(char)-2] = sum(-2);
+ @i8[(char)-1] = sum(-1);
+ @i8[(char)0] = sum(0);
+ @i8[(char)1] = sum(1);
+ @i8[(char)2] = sum(2);
+
+ @i16[(short)-2] = sum(-2);
+ @i16[(short)-1] = sum(-1);
+ @i16[(short)0] = sum(0);
+ @i16[(short)1] = sum(1);
+ @i16[(short)2] = sum(2);
+
+ @i32[-2] = sum(-2);
+ @i32[-1] = sum(-1);
+ @i32[0] = sum(0);
+ @i32[1] = sum(1);
+ @i32[2] = sum(2);
+
+ @i64[(long long)-2] = sum(-2);
+ @i64[(long long)-1] = sum(-1);
+ @i64[(long long)0] = sum(0);
+ @i64[(long long)1] = sum(1);
+ @i64[(long long)2] = sum(2);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeys.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeys.d.out
new file mode 100644
index 000000000000..42e619e01200
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeys.d.out
@@ -0,0 +1,44 @@
+254
+255
+0
+1
+2
+
+65534
+65535
+0
+1
+2
+
+-2
+-1
+0
+1
+2
+
+-2
+-1
+0
+1
+2
+
+ 0 0
+ 1 1
+ 2 2
+ 254 -2
+ 255 -1
+ 0 0
+ 1 1
+ 2 2
+ 65534 -2
+ 65535 -1
+ 0 0
+ 1 1
+ 2 2
+ -2 -2
+ -1 -1
+ 0 0
+ 1 1
+ 2 2
+ -2 -2
+ -1 -1
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeyspos.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeyspos.d
new file mode 100644
index 000000000000..5836c6a5ef60
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeyspos.d
@@ -0,0 +1,115 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Signed integer keys print and sort as expected using the
+ * aggsortkeypos and aggsortrev options
+ *
+ * SECTION: Aggregations, Printing Aggregations
+ *
+ * NOTES: DTrace sorts integer keys as unsigned values, yet prints 32-
+ * and 64-bit integers as signed values. Since the Java DTrace API is
+ * expected to emulate this behavior, this test was added to ensure that
+ * the behavior is preserved.
+ */
+
+#pragma D option quiet
+#pragma D option aggsortkey
+#pragma D option aggsortkeypos=1
+#pragma D option aggsortrev
+
+BEGIN
+{
+ @i8["cat", (char)-2] = sum(-2);
+ @i8["dog", (char)-2] = sum(-22);
+ @i8["mouse", (char)-2] = sum(-222);
+ @i8["cat", (char)-1] = sum(-1);
+ @i8["dog", (char)-1] = sum(-11);
+ @i8["mouse", (char)-1] = sum(-111);
+ @i8["cat", (char)0] = sum(0);
+ @i8["dog", (char)0] = sum(10);
+ @i8["mouse", (char)0] = sum(100);
+ @i8["cat", (char)1] = sum(1);
+ @i8["dog", (char)1] = sum(11);
+ @i8["mouse", (char)1] = sum(111);
+ @i8["cat", (char)2] = sum(2);
+ @i8["dog", (char)2] = sum(22);
+ @i8["mouse", (char)2] = sum(222);
+
+ @i16["mouse", (short)-2] = sum(-2);
+ @i16["dog", (short)-2] = sum(-22);
+ @i16["cat", (short)-2] = sum(-222);
+ @i16["mouse", (short)-1] = sum(-1);
+ @i16["dog", (short)-1] = sum(-11);
+ @i16["cat", (short)-1] = sum(-111);
+ @i16["mouse", (short)0] = sum(0);
+ @i16["dog", (short)0] = sum(10);
+ @i16["cat", (short)0] = sum(100);
+ @i16["mouse", (short)1] = sum(1);
+ @i16["dog", (short)1] = sum(11);
+ @i16["cat", (short)1] = sum(111);
+ @i16["mouse", (short)2] = sum(2);
+ @i16["dog", (short)2] = sum(22);
+ @i16["cat", (short)2] = sum(222);
+
+ @i32["mouse", -2] = sum(-2);
+ @i32["bear", -2] = sum(-22);
+ @i32["cat", -2] = sum(-222);
+ @i32["mouse", -1] = sum(-1);
+ @i32["bear", -1] = sum(-11);
+ @i32["cat", -1] = sum(-111);
+ @i32["mouse", 0] = sum(0);
+ @i32["bear", 0] = sum(10);
+ @i32["cat", 0] = sum(100);
+ @i32["mouse", 1] = sum(1);
+ @i32["bear", 1] = sum(11);
+ @i32["cat", 1] = sum(111);
+ @i32["mouse", 2] = sum(2);
+ @i32["bear", 2] = sum(22);
+ @i32["cat", 2] = sum(222);
+
+ @i64["cat", (long long)-2] = sum(-2);
+ @i64["bear", (long long)-2] = sum(-22);
+ @i64["dog", (long long)-2] = sum(-222);
+ @i64["cat", (long long)-1] = sum(-1);
+ @i64["bear", (long long)-1] = sum(-11);
+ @i64["dog", (long long)-1] = sum(-111);
+ @i64["cat", (long long)0] = sum(0);
+ @i64["bear", (long long)0] = sum(10);
+ @i64["dog", (long long)0] = sum(100);
+ @i64["cat", (long long)1] = sum(1);
+ @i64["bear", (long long)1] = sum(11);
+ @i64["dog", (long long)1] = sum(111);
+ @i64["cat", (long long)2] = sum(2);
+ @i64["bear", (long long)2] = sum(22);
+ @i64["dog", (long long)2] = sum(222);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeyspos.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeyspos.d.out
new file mode 100644
index 000000000000..28e95ac3196f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.signedkeyspos.d.out
@@ -0,0 +1,61 @@
+
+ dog -1 -111
+ cat -1 -1
+ bear -1 -11
+ dog -2 -222
+ cat -2 -2
+ bear -2 -22
+ dog 2 222
+ cat 2 2
+ bear 2 22
+ dog 1 111
+ cat 1 1
+ bear 1 11
+ dog 0 100
+ cat 0 0
+ bear 0 10
+ mouse -1 -1
+ cat -1 -111
+ bear -1 -11
+ mouse -2 -2
+ cat -2 -222
+ bear -2 -22
+ mouse 2 2
+ cat 2 222
+ bear 2 22
+ mouse 1 1
+ cat 1 111
+ bear 1 11
+ mouse 0 0
+ cat 0 100
+ bear 0 10
+ mouse 65535 -1
+ dog 65535 -11
+ cat 65535 -111
+ mouse 65534 -2
+ dog 65534 -22
+ cat 65534 -222
+ mouse 2 2
+ dog 2 22
+ cat 2 222
+ mouse 1 1
+ dog 1 11
+ cat 1 111
+ mouse 0 0
+ dog 0 10
+ cat 0 100
+ mouse 255 -111
+ dog 255 -11
+ cat 255 -1
+ mouse 254 -222
+ dog 254 -22
+ cat 254 -2
+ mouse 2 222
+ dog 2 22
+ cat 2 2
+ mouse 1 111
+ dog 1 11
+ cat 1 1
+ mouse 0 100
+ dog 0 10
+ cat 0 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d
new file mode 100644
index 000000000000..bb3ed4789bf5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d
@@ -0,0 +1,35 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#pragma D option quiet
+
+/*
+ * Make sure the sizes of compatible keys doesn't affect the sort order.
+ */
+
+BEGIN
+{
+ @[(int)1, 0] = sum(10);
+ @[(uint64_t)2, 0] = sum(20);
+ @[(int)3, 0] = sum(30);
+ @[(uint64_t)4, 0] = sum(40);
+ printa(@);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d.out
new file mode 100644
index 000000000000..83252ade53ae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d.out
@@ -0,0 +1,6 @@
+
+ 1 0 10
+ 2 0 20
+ 3 0 30
+ 4 0 40
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.d
new file mode 100644
index 000000000000..041b82070f84
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Positive stddev() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is a simple verifiable positive test of the stddev() function.
+ * printa() for one aggregation, default printing behavior for the other
+ * so that we exercise both code paths.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a = stddev(5000000000);
+ @a = stddev(5000000100);
+ @a = stddev(5000000200);
+ @a = stddev(5000000300);
+ @a = stddev(5000000400);
+ @a = stddev(5000000500);
+ @a = stddev(5000000600);
+ @a = stddev(5000000700);
+ @a = stddev(5000000800);
+ @a = stddev(5000000900);
+ @b = stddev(-5000000000);
+ @b = stddev(-5000000100);
+ @b = stddev(-5000000200);
+ @b = stddev(-5000000300);
+ @b = stddev(-5000000400);
+ @b = stddev(-5000000500);
+ @b = stddev(-5000000600);
+ @b = stddev(-5000000700);
+ @b = stddev(-5000000800);
+ @b = stddev(-5000000900);
+ printa("%@d\n", @a);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.d.out
new file mode 100644
index 000000000000..0c02852e452f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.d.out
@@ -0,0 +1,3 @@
+287
+
+ 287
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.normalize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.normalize.d
new file mode 100644
index 000000000000..50c14d3cedb0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.normalize.d
@@ -0,0 +1,46 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Panzura. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * Positive test for normalization() of stddev()
+ *
+ * SECTION: Aggregations/Normalization
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=50ms
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-100ms
+/i < 11/
+{
+ @ = stddev(i * 100);
+ i++;
+}
+
+tick-100ms
+/i == 11/
+{
+ printf("normalized data:\n");
+ normalize(@, 10);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.normalize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.normalize.d.out
new file mode 100644
index 000000000000..a629b1fdb5c2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.stddev.normalize.d.out
@@ -0,0 +1,3 @@
+normalized data:
+
+ 31
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.subr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.subr.d
new file mode 100644
index 000000000000..9b02e982fe0d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.subr.d
@@ -0,0 +1,115 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#define INTFUNC(x) \
+ BEGIN \
+ /*DSTYLED*/ \
+ { \
+ subr++; \
+ @[(long)x] = sum(1); \
+ /*DSTYLED*/ \
+ }
+
+#define STRFUNC(x) \
+ BEGIN \
+ /*DSTYLED*/ \
+ { \
+ subr++; \
+ @str[x] = sum(1); \
+ /*DSTYLED*/ \
+ }
+
+#define VOIDFUNC(x) \
+ BEGIN \
+ /*DSTYLED*/ \
+ { \
+ subr++; \
+ /*DSTYLED*/ \
+ }
+
+INTFUNC(rand())
+INTFUNC(mutex_owned(&`cpu_lock))
+INTFUNC(mutex_owner(&`cpu_lock))
+INTFUNC(mutex_type_adaptive(&`cpu_lock))
+INTFUNC(mutex_type_spin(&`cpu_lock))
+INTFUNC(rw_read_held(&`vfssw_lock))
+INTFUNC(rw_write_held(&`vfssw_lock))
+INTFUNC(rw_iswriter(&`vfssw_lock))
+INTFUNC(copyin(NULL, 1))
+STRFUNC(copyinstr(NULL, 1))
+INTFUNC(speculation())
+INTFUNC(progenyof($pid))
+INTFUNC(strlen("fooey"))
+VOIDFUNC(copyout)
+VOIDFUNC(copyoutstr)
+INTFUNC(alloca(10))
+VOIDFUNC(bcopy)
+VOIDFUNC(copyinto)
+INTFUNC(msgdsize(NULL))
+INTFUNC(msgsize(NULL))
+INTFUNC(getmajor(0))
+INTFUNC(getminor(0))
+STRFUNC(ddi_pathname(NULL, 0))
+STRFUNC(strjoin("foo", "bar"))
+STRFUNC(lltostr(12373))
+STRFUNC(basename("/var/crash/systemtap"))
+STRFUNC(dirname("/var/crash/systemtap"))
+STRFUNC(cleanpath("/var/crash/systemtap"))
+STRFUNC(strchr("The SystemTap, The.", 't'))
+STRFUNC(strrchr("The SystemTap, The.", 't'))
+STRFUNC(strstr("The SystemTap, The.", "The"))
+STRFUNC(strtok("The SystemTap, The.", "T"))
+STRFUNC(substr("The SystemTap, The.", 0))
+INTFUNC(index("The SystemTap, The.", "The"))
+INTFUNC(rindex("The SystemTap, The.", "The"))
+INTFUNC(htons(0x1234))
+INTFUNC(htonl(0x12345678))
+INTFUNC(htonll(0x1234567890abcdefL))
+INTFUNC(ntohs(0x1234))
+INTFUNC(ntohl(0x12345678))
+INTFUNC(ntohll(0x1234567890abcdefL))
+STRFUNC(inet_ntoa((ipaddr_t *)alloca(sizeof (ipaddr_t))))
+STRFUNC(inet_ntoa6((in6_addr_t *)alloca(sizeof (in6_addr_t))))
+STRFUNC(inet_ntop(AF_INET, (void *)alloca(sizeof (ipaddr_t))))
+INTFUNC(getf(0))
+INTFUNC(strtoll("0x12EE5D5", 16))
+STRFUNC(json("{\"systemtap\": false}", "systemtap"))
+
+BEGIN
+/subr == DIF_SUBR_MAX + 1/
+{
+ exit(0);
+}
+
+BEGIN
+{
+ printf("found %d subroutines, expected %d\n", subr, DIF_SUBR_MAX + 1);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sum.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sum.d
new file mode 100644
index 000000000000..1b9025af9715
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sum.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Positive sum() test
+ *
+ * SECTION: Aggregations/Aggregations
+ *
+ * NOTES: This is verifiable simple positive test of the sum() function.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 1000/
+{
+ @a = sum(i);
+ i += 100;
+}
+
+tick-10ms
+/i == 1000/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sum.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sum.d.out
new file mode 100644
index 000000000000..5d8b37b8ac42
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.sum.d.out
@@ -0,0 +1,2 @@
+
+ 4500
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc.d
new file mode 100644
index 000000000000..d1c1b3cc2f87
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+int i;
+
+tick-10ms
+/i < 100/
+{
+ @[i] = sum(i);
+ i++;
+}
+
+tick-10ms
+/i == 100/
+{
+ exit(0);
+}
+
+END
+{
+ trunc(@, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc.d.out
new file mode 100644
index 000000000000..2e18ef8bff29
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc.d.out
@@ -0,0 +1,11 @@
+
+ 90 90
+ 91 91
+ 92 92
+ 93 93
+ 94 94
+ 95 95
+ 96 96
+ 97 97
+ 98 98
+ 99 99
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc0.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc0.d
new file mode 100644
index 000000000000..5c31069d8601
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc0.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+#pragma D option aggrate=1ms
+#pragma D option switchrate=50ms
+
+int i;
+
+tick-100ms
+/i < 10/
+{
+ @[i] = sum(10 - i);
+ i++;
+}
+
+tick-100ms
+/i == 5/
+{
+ trunc(@);
+}
+
+tick-100ms
+/i == 10/
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc0.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc0.d.out
new file mode 100644
index 000000000000..70dc7a026d8c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.trunc0.d.out
@@ -0,0 +1,7 @@
+
+ 9 1
+ 8 2
+ 7 3
+ 6 4
+ 5 5
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.truncquant.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.truncquant.d
new file mode 100644
index 000000000000..8baa56ab9512
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.truncquant.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+int i;
+
+tick-10ms
+/i < 100/
+{
+ @[i] = lquantize(i, 0, 150);
+ @[i] = lquantize(i + 1, 0, 150);
+ @[i] = lquantize(i + 2, 0, 150);
+ @[i] = lquantize(i + 3, 0, 150);
+ i++;
+}
+
+tick-10ms
+/i == 100/
+{
+ exit(0);
+}
+
+END
+{
+ trunc(@, 5);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.truncquant.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.truncquant.d.out
new file mode 100644
index 000000000000..86975af33398
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.truncquant.d.out
@@ -0,0 +1,46 @@
+
+ 95
+ value ------------- Distribution ------------- count
+ 94 | 0
+ 95 |@@@@@@@@@@ 1
+ 96 |@@@@@@@@@@ 1
+ 97 |@@@@@@@@@@ 1
+ 98 |@@@@@@@@@@ 1
+ 99 | 0
+
+ 96
+ value ------------- Distribution ------------- count
+ 95 | 0
+ 96 |@@@@@@@@@@ 1
+ 97 |@@@@@@@@@@ 1
+ 98 |@@@@@@@@@@ 1
+ 99 |@@@@@@@@@@ 1
+ 100 | 0
+
+ 97
+ value ------------- Distribution ------------- count
+ 96 | 0
+ 97 |@@@@@@@@@@ 1
+ 98 |@@@@@@@@@@ 1
+ 99 |@@@@@@@@@@ 1
+ 100 |@@@@@@@@@@ 1
+ 101 | 0
+
+ 98
+ value ------------- Distribution ------------- count
+ 97 | 0
+ 98 |@@@@@@@@@@ 1
+ 99 |@@@@@@@@@@ 1
+ 100 |@@@@@@@@@@ 1
+ 101 |@@@@@@@@@@ 1
+ 102 | 0
+
+ 99
+ value ------------- Distribution ------------- count
+ 98 | 0
+ 99 |@@@@@@@@@@ 1
+ 100 |@@@@@@@@@@ 1
+ 101 |@@@@@@@@@@ 1
+ 102 |@@@@@@@@@@ 1
+ 103 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.valsortkeypos.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.valsortkeypos.d
new file mode 100644
index 000000000000..ec0bee32a25a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.valsortkeypos.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * aggsortkeypos option works when sorting by values, values are
+ * equal, and keys are compared to break the tie
+ *
+ * SECTION: Aggregations, Printing Aggregations
+ *
+ */
+
+#pragma D option quiet
+#pragma D option aggsortkeypos=1
+
+BEGIN
+{
+ @[1, 3] = sum(0);
+ @[2, 2] = sum(0);
+ @[3, 1] = sum(0);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.valsortkeypos.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.valsortkeypos.d.out
new file mode 100644
index 000000000000..9b0acf92e64c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.valsortkeypos.d.out
@@ -0,0 +1,4 @@
+
+ 3 1 0
+ 2 2 0
+ 1 3 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0.d
new file mode 100644
index 000000000000..0b7b6610b377
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify that divide by 0 errors are caught
+ *
+ * SECTION:
+ * Types, Operators, and Expressions/Arithmetic Operators
+ */
+
+
+BEGIN
+{
+ c = 123/0;
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0_1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0_1.d
new file mode 100644
index 000000000000..110179511ef2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0_1.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify that computed divide by 0 errors are caught
+ *
+ * SECTION:
+ * Types, Operators, and Expressions/Arithmetic Operators
+ */
+
+
+
+
+BEGIN
+{
+ c = 123/(7-7);
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0_2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0_2.d
new file mode 100644
index 000000000000..454696144fd9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.divby0_2.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify that computed divide by 0 errors are caught
+ *
+ * SECTION:
+ * Types, Operators, and Expressions/Arithmetic Operators
+ */
+
+
+
+
+
+BEGIN
+{
+ c = 123/((7-7) * 999);
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.modby0.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.modby0.d
new file mode 100644
index 000000000000..b2bf1462fe67
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_DIV_ZERO.modby0.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify that mod by 0 errors are caught
+ *
+ * SECTION:
+ * Types, Operators, and Expressions/Arithmetic Operators
+ */
+
+
+
+BEGIN
+{
+ c = 123%0;
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.addmin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.addmin.d
new file mode 100644
index 000000000000..f20339c169ed
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.addmin.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Call invalid / impossible arithmetic operations and make sure
+ * Test gives compilation error.
+ *
+ * SECTION: Types, Operators, and Expressions/Arithmetic Operators
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+ i+-;
+ printf("The value of i is %d\n", i);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.divmin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.divmin.d
new file mode 100644
index 000000000000..c11e64fde5e9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.divmin.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Call invalid / impossible arithmetic operations and make sure
+ * Test gives compilation error.
+ *
+ * SECTION: Types, Operators, and Expressions/Arithmetic Operators
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 1;
+ i /-= i;
+ printf("The value of i is %d\n", i);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.muladd.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.muladd.d
new file mode 100644
index 000000000000..bb107fb3aebd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.muladd.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Call invalid / impossible arithmetic operations and make sure
+ * Test gives compilation error.
+ *
+ * SECTION: Types, Operators, and Expressions/Arithmetic Operators
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 1;
+ i *+= i;
+ printf("The value of i is %d\n", i);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.muldiv.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.muldiv.d
new file mode 100644
index 000000000000..7d44b6c76e55
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/err.D_SYNTAX.muldiv.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Call invalid / impossible arithmetic operations and make sure
+ * Test gives compilation error.
+ *
+ * SECTION: Types, Operators, and Expressions/Arithmetic Operators
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 1;
+ i */= i;
+ printf("The value of i is %d\n", i);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d
new file mode 100644
index 000000000000..435f09f6d925
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d
@@ -0,0 +1,66 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple Arithmetic expressions.
+ * Call simple expressions and make sure test succeeds.
+ * Match expected output in tst.basics.d.out
+ *
+ * SECTION: Types, Operators, and Expressions/Arithmetic Operators
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+ i = 1 + 2 + 3;
+ printf("The value of i is %d\n", i);
+
+ i = i * 3;
+ printf("The value of i is %d\n", i);
+
+ i = (i * 3) + i;
+ printf("The value of i is %d\n", i);
+
+ i = (i + (i * 3) + i) * i;
+ printf("The value of i is %d\n", i);
+
+ i = i - (i + (i * 3) + i) * i / i * i;
+ printf("The value of i is %d\n", i);
+
+ i = i * (i - 3 + 5 / i * i ) / i * 6;
+ printf("The value of i is %d\n", i);
+
+ i = i ^ 5;
+ printf("The value of i is %d\n", i);
+
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d.out
new file mode 100644
index 000000000000..d3b6af813101
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d.out
@@ -0,0 +1,8 @@
+The value of i is 6
+The value of i is 18
+The value of i is 72
+The value of i is 25920
+The value of i is 935761216
+The value of i is -91738734
+The value of i is -91738729
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d
new file mode 100644
index 000000000000..714fbe373b2c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * Test compile-time casting between integer types of different size.
+ */
+
+#pragma D option quiet
+
+int64_t x;
+
+BEGIN
+{
+ x = (int32_t)(int16_t)0xfff0;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (int32_t)(uint16_t)0xfff0;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (uint32_t)(int16_t)0xfff0;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (uint32_t)(uint16_t)0xfff0;
+ printf("%16x %20d %20u\n", x, x, x);
+ printf("\n");
+
+ x = (int16_t)(int32_t)0xfff0;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (int16_t)(uint32_t)0xfff0;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (uint16_t)(int32_t)0xfff0;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (uint16_t)(uint32_t)0xfff0;
+ printf("%16x %20d %20u\n", x, x, x);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d.out
new file mode 100644
index 000000000000..d43df27d5d5c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d.out
@@ -0,0 +1,10 @@
+fffffffffffffff0 -16 18446744073709551600
+ fff0 65520 65520
+ fffffff0 4294967280 4294967280
+ fff0 65520 65520
+
+fffffffffffffff0 -16 18446744073709551600
+fffffffffffffff0 -16 18446744073709551600
+ fff0 65520 65520
+ fff0 65520 65520
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d
new file mode 100644
index 000000000000..0589b721b421
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d
@@ -0,0 +1,36 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * Test narrowing at assignment.
+ */
+
+#pragma D option quiet
+
+uint16_t x;
+uint32_t y;
+
+BEGIN
+{
+ x = 0xbeefcafe;
+ y = x;
+ printf("%x", y); /* where's the beef? */
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d.out
new file mode 100644
index 000000000000..ea17b160d298
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d.out
@@ -0,0 +1 @@
+cafe
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d
new file mode 100644
index 000000000000..a7017bfee5e7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d
@@ -0,0 +1,52 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * Test execution-time casting between integer types of different size.
+ */
+
+#pragma D option quiet
+
+int64_t x;
+
+BEGIN
+{
+ z = 0xfff0;
+
+ x = (int32_t)(int16_t)z;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (int32_t)(uint16_t)z;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (uint32_t)(int16_t)z;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (uint32_t)(uint16_t)z;
+ printf("%16x %20d %20u\n", x, x, x);
+ printf("\n");
+
+ x = (int16_t)(int32_t)z;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (int16_t)(uint32_t)z;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (uint16_t)(int32_t)z;
+ printf("%16x %20d %20u\n", x, x, x);
+ x = (uint16_t)(uint32_t)z;
+ printf("%16x %20d %20u\n", x, x, x);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d.out
new file mode 100644
index 000000000000..d43df27d5d5c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d.out
@@ -0,0 +1,10 @@
+fffffffffffffff0 -16 18446744073709551600
+ fff0 65520 65520
+ fffffff0 4294967280 4294967280
+ fff0 65520 65520
+
+fffffffffffffff0 -16 18446744073709551600
+fffffffffffffff0 -16 18446744073709551600
+ fff0 65520 65520
+ fff0 65520 65520
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_ARR_BADREF.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_ARR_BADREF.bad.d
new file mode 100644
index 000000000000..d31b1f64c87c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_ARR_BADREF.bad.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Tuples can not be used in non-associative arrays.
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage
+ */
+
+int x[5];
+
+BEGIN
+{
+ x[1, 2] = 1;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRBIG.toobig.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRBIG.toobig.d
new file mode 100644
index 000000000000..80422e884796
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRBIG.toobig.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Array declarations with indexs over INT_MAX return a
+ * D_DECL_ARRBIG errtag.
+ *
+ * SECTION:
+ * Pointers and Arrays/Array Declarations and Storage
+ */
+
+int x[88294967295];
+
+BEGIN
+{
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRNULL.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRNULL.bad.d
new file mode 100644
index 000000000000..6e7a34ff01f3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRNULL.bad.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Arrays must have array dimensions
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage
+ */
+
+int a[];
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRSUB.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRSUB.bad.d
new file mode 100644
index 000000000000..f44036771b88
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_ARRSUB.bad.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Arrays declarations must have a positive constant as a
+ * subscription.
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage
+ */
+
+int a[-7];
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_PROTO_TYPE.badtuple.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_PROTO_TYPE.badtuple.d
new file mode 100644
index 000000000000..7e879dc6120a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_DECL_PROTO_TYPE.badtuple.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invalid tuple types result in a DT_DECL_ARRTYPE error.
+ *
+ * SECTION:
+ * Pointers and Arrays/Array Declarations and Storage
+ */
+
+
+int x[void, char];
+
+BEGIN
+{
+ x[trace(), 'a'] = 456;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_IDENT_UNDEF.badureg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_IDENT_UNDEF.badureg.d
new file mode 100644
index 000000000000..e48541b61670
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/err.D_IDENT_UNDEF.badureg.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Arrays declarations must have a positive constant as a
+ * subscription.
+ *
+ * SECTION: User Process Tracing/uregs Array
+ */
+
+BEGIN
+{
+ printf("FOO = 0x%x\n", uregs[FOO]);
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic1.d
new file mode 100644
index 000000000000..ba5b2cf0d15c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic1.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple array test
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ a[1] = 0;
+}
+
+tick-1
+/a[1] == 0/
+{
+ exit(0);
+}
+
+tick-1
+/a[1] != 0/
+{
+ printf("Expected 0, got %d\n", a[1]);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic2.d
new file mode 100644
index 000000000000..14e1c5cf4503
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic2.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple array test
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ a[1] = 0;
+ a[1]++;
+}
+
+tick-1
+/a[1] == 1/
+{
+ exit(0);
+}
+
+tick-1
+/a[1] != 1/
+{
+ printf("Expected 1, got %d\n", a[1]);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic3.d
new file mode 100644
index 000000000000..897a12f2f23e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic3.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple array test
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ a[1] = 0;
+ ++a[1];
+}
+
+tick-1
+/a[1] == 1/
+{
+ exit(0);
+}
+
+tick-1
+/a[1] != 1/
+{
+ printf("Expected 1, got %d\n", a[1]);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic4.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic4.d
new file mode 100644
index 000000000000..3635a42d5387
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic4.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple array test
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ a["test"] = 0;
+}
+
+tick-1
+/a["test"] == 0/
+{
+ exit(0);
+}
+
+tick-1
+/a["test"] != 0/
+{
+ printf("Expected 0, got %d\n", a["test"]);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic5.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic5.d
new file mode 100644
index 000000000000..866a8c39aeb2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic5.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple array test
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ a["test"] = 0;
+ b = ++a["test"];
+}
+
+tick-1
+/b == 1/
+{
+ exit(0);
+}
+
+tick-1
+/b != 1/
+{
+ printf("Expected b = 1, got %d\n", b);
+ exit(1);
+}
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic6.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic6.d
new file mode 100644
index 000000000000..0371db309331
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.basic6.d
@@ -0,0 +1,58 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple array test
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ a["test", "test"] = 0;
+ b = ++a["test", "test"];
+}
+
+tick-1
+/b == 1/
+{
+ exit(0);
+}
+
+tick-1
+/b != 1/
+{
+ printf("Expected b = 1, got %d\n", b);
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.uregsarray.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.uregsarray.d
new file mode 100644
index 000000000000..b3fba0ca4c82
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/arrays/tst.uregsarray.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Positive test to make sure that we can invoke common
+ * ureg[] aliases.
+ *
+ * SECTION: User Process Tracing/uregs Array
+ *
+ * NOTES: This test does no verification - the value of the output
+ * is not deterministic.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("R_PC = 0x%x\n", uregs[R_PC]);
+ printf("R_SP = 0x%x\n", uregs[R_SP]);
+ printf("R_R0 = 0x%x\n", uregs[R_R0]);
+ printf("R_R1 = 0x%x\n", uregs[R_R1]);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.dupgtype.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.dupgtype.d
new file mode 100644
index 000000000000..267d121274c7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.dupgtype.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test assigning a variable two different incompatible types. This should
+ * result in a compile-time error.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ */
+
+BEGIN
+{
+ x[123] = `kmem_flags;
+ x[456] = *`rootvp;
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.dupttype.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.dupttype.d
new file mode 100644
index 000000000000..ce360cd25d9a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.dupttype.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test assigning a variable two different incompatible types. This should
+ * result in a compile-time error.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ */
+
+BEGIN
+{
+ self->x[123] = `kmem_flags;
+ self->x[456] = *`rootvp;
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.this.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.this.d
new file mode 100644
index 000000000000..2af07ca52ae1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_OP_INCOMPAT.this.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ *
+ * Declare 'this int' variable and assign inappropriate data type.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ *
+ */
+
+#pragma D option quiet
+
+this int x;
+
+BEGIN
+{
+ this->x = "dummy";
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_ARG.badsig.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_ARG.badsig.d
new file mode 100644
index 000000000000..d682fc68883d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_ARG.badsig.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test an associative array reference that is invalid because of a type
+ * signature mismatch -- this should produce a syntax error at compile time.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ */
+
+BEGIN
+{
+ x[123, "foo"] = timestamp;
+}
+
+END
+{
+ x[123, 456] = timestamp;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_LEN.toofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_LEN.toofew.d
new file mode 100644
index 000000000000..b4e82b858880
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_LEN.toofew.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test an associative array reference that is invalid because of too few
+ * arguments -- this should produce a syntax error at compile time.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ */
+
+BEGIN
+{
+ x[123, 456] = timestamp;
+}
+
+END
+{
+ x[123] = timestamp;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_LEN.toomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_LEN.toomany.d
new file mode 100644
index 000000000000..3dc5f7dd7917
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_PROTO_LEN.toomany.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test an associative array reference that is invalid because of too many
+ * arguments -- this should produce a syntax error at compile time.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ */
+
+BEGIN
+{
+ x[123, 456] = timestamp;
+}
+
+END
+{
+ x[123, 456, 789] = timestamp;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_SYNTAX.errassign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_SYNTAX.errassign.d
new file mode 100644
index 000000000000..f31b66f11558
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.D_SYNTAX.errassign.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Assign one to 10 elements; make sure fails to compile.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ */
+
+BEGIN
+{
+ x[10]=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+}
+
+END
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.tupoflow.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.tupoflow.d
new file mode 100644
index 000000000000..810420267523
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/err.tupoflow.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Generates an associative array reference that should overflow the tuple
+ * register stack. We should detect and report this at compile time.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ */
+
+BEGIN
+{
+ a[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] = 0;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.cpyarray.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.cpyarray.d
new file mode 100644
index 000000000000..ca31cc3590d9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.cpyarray.d
@@ -0,0 +1,65 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Copy value from associative arrays to local variables.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ *
+ */
+
+#pragma D option quiet
+
+this int x;
+
+BEGIN
+{
+ a["abc", 123] = 123;
+}
+
+tick-10ms
+{
+ this->x = a["abc", 123]++;
+ printf("The value of x is %d\n", this->x);
+}
+
+tick-10ms
+{
+ this->x = a["abc", 123]++;
+ printf("The value of x is %d\n", this->x);
+}
+
+tick-10ms
+{
+ this->x = a["abc", 123]++;
+ printf("The value of x is %d\n", this->x);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.diffprofile.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.diffprofile.d
new file mode 100644
index 000000000000..ad5fb377e55e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.diffprofile.d
@@ -0,0 +1,62 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * To test Clause Local Variables ' this' across different profiles.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ *
+ */
+
+#pragma D option quiet
+
+this int x;
+this char c;
+
+tick-10ms
+{
+ this->x = 123;
+ this->c = 'D';
+ printf("The value of x is %d\n", this->x);
+}
+
+tick-10ms
+{
+ this->x = 235;
+ printf("The value of x is %d\n", this->x);
+}
+
+tick-10ms
+{
+ this->x = 456;
+ printf("The value of x is %d\n", this->x);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.initialize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.initialize.d
new file mode 100644
index 000000000000..1ab222b151c0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.initialize.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Clause local variables are not initialized to zero.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ *
+ */
+
+#pragma D option quiet
+
+this int x;
+
+BEGIN
+{
+ printf("the value of x is %d\n", this->x);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.invalidref.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.invalidref.d
new file mode 100644
index 000000000000..446acfad4d7f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.invalidref.d
@@ -0,0 +1,75 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Test to ensure that invalid stores to a global associative array
+ * are caught correctly.
+ */
+
+#pragma D option quiet
+
+int last_cmds[int][4];
+
+BEGIN
+{
+ errors = 0;
+ forward = 0;
+ backward = 0;
+}
+
+tick-1s
+/!forward/
+{
+ forward = 1;
+ last_cmds[1][4] = 0xdeadbeef;
+}
+
+tick-1s
+/!backward/
+{
+ backward = 1;
+ last_cmds[1][-5] = 0xdeadbeef;
+}
+
+tick-1s
+/errors > 1/
+{
+ exit(0);
+}
+
+tick-1s
+/n++ > 5/
+{
+ exit(1);
+}
+
+ERROR
+/arg4 == DTRACEFLT_BADADDR/
+{
+ errors++;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.misc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.misc.d
new file mode 100644
index 000000000000..43147dec694d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.misc.d
@@ -0,0 +1,69 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the different kinds of associative scalar references.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ * NOTES:
+ * In particular, we test accessing a DTrace associative array
+ * defined with scalar type (first ref that forces creation as both global
+ * and TLS), and DTrace associative array scalar subsequent references
+ * (both global and TLS).
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i != 5/
+{
+ x[123, "foo"] = 123;
+ self->x[456, "bar"] = 456;
+ i++;
+}
+
+tick-10ms
+/i != 5/
+{
+ printf("x[] = %d\n", x[123, "foo"]);
+ printf("self->x[] = %d\n", self->x[456, "bar"]);
+}
+
+tick-10ms
+/i == 5/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.orthogonality.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.orthogonality.d
new file mode 100644
index 000000000000..3a7d6a2c6413
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.orthogonality.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This test confirms the orthogonality of associative arrays and thread-local
+ * variables by intentionally deriving a matching key signature (based on
+ * t_did).
+ */
+uint64_t b[uint64_t];
+
+BEGIN
+{
+ self->a = 0xbad;
+}
+
+BEGIN
+/b[curthread->td_flags] == 0/
+{
+ exit(0);
+}
+
+BEGIN
+{
+ printf("value should be 0; value is %x!", b[curthread->td_flags]);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.this.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.this.d
new file mode 100644
index 000000000000..c4d01fa35fae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.this.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * To test Clause Local Variables ' this'.
+ *
+ * SECTION: Variables/Associative Arrays
+ *
+ *
+ */
+
+#pragma D option quiet
+
+this int x;
+this char c;
+
+BEGIN
+{
+ this->x = 123;
+ this->c = 'D';
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.valassign.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.valassign.d.out
new file mode 100644
index 000000000000..948d82e9d61d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/assocs/tst.valassign.d.out
@@ -0,0 +1,2 @@
+The value of i is 123
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/err.D_PDESC_ZERO.begin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/err.D_PDESC_ZERO.begin.d
new file mode 100644
index 000000000000..c2a60889218b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/err.D_PDESC_ZERO.begin.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Arguments to BEGIN provider not allowed.
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN::read:entry
+{
+ printf("Begin fired first\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/err.D_PDESC_ZERO.tick.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/err.D_PDESC_ZERO.tick.d
new file mode 100644
index 000000000000..44a363f80401
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/err.D_PDESC_ZERO.tick.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * concat of providers not allowed with BEGIN
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+
+BEGIN:tick-1
+{
+ printf("Begin fired first\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.begin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.begin.d
new file mode 100644
index 000000000000..43e7744e6e76
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.begin.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Order of provider flow, Begin, tick profile, and END.
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+END
+{
+ printf("End fired after exit\n");
+}
+
+BEGIN
+{
+ printf("Begin fired first\n");
+}
+
+tick-1ms
+{
+ printf("tick fired second\n");
+ printf("Call exit\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.begin.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.begin.d.out
new file mode 100644
index 000000000000..a9d8ee1e7c3e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.begin.d.out
@@ -0,0 +1,5 @@
+Begin fired first
+tick fired second
+Call exit
+End fired after exit
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.multibegin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.multibegin.d
new file mode 100644
index 000000000000..3d5fd124f7fa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.multibegin.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Multiple BEGIN providers
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("Begin fired first\n");
+}
+BEGIN
+{
+ printf("Begin fired second\n");
+}
+BEGIN
+{
+ printf("Begin fired third\n");
+}
+BEGIN
+{
+ printf("Begin fired fourth\n");
+}
+BEGIN
+{
+ printf("Begin fired fifth\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.multibegin.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.multibegin.d.out
new file mode 100644
index 000000000000..e5bb99669906
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/begin/tst.multibegin.d.out
@@ -0,0 +1,6 @@
+Begin fired first
+Begin fired second
+Begin fired third
+Begin fired fourth
+Begin fired fifth
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_ADDROF_BITFIELD.BitfieldAddress.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_ADDROF_BITFIELD.BitfieldAddress.d
new file mode 100644
index 000000000000..9c5aca4c1948
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_ADDROF_BITFIELD.BitfieldAddress.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Cannot take the address of a bit-field member using the &
+ * operator.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ */
+
+#pragma D option quiet
+
+struct bitRecord{
+ int a : 1;
+ int b : 3;
+ int c : 12;
+} var;
+
+BEGIN
+{
+ printf("address of a: %d\naddress of b: %d\naddress of c: %dn",
+ &var.a, &var.b, &var.c);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFCONST.NegBitField.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFCONST.NegBitField.d
new file mode 100644
index 000000000000..acb296f4cec0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFCONST.NegBitField.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Bit-field width must be positive.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ */
+
+#pragma D option quiet
+
+struct bitRecord{
+ int a : 1;
+ int b : -3;
+ int c : 12;
+} var;
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFCONST.ZeroBitField.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFCONST.ZeroBitField.d
new file mode 100644
index 000000000000..dfe24c59537c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFCONST.ZeroBitField.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Bit-fields must be positive and non-zero.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ */
+
+#pragma D option quiet
+
+struct bitRecord{
+ int a : 1;
+ int b : 0;
+ int c : 12;
+} var;
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFSIZE.ExceedBaseType.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFSIZE.ExceedBaseType.d
new file mode 100644
index 000000000000..d9abfd1330b9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFSIZE.ExceedBaseType.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Bit-field width must be of a number of bits not larger than
+ * that of the corresponding base type.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ */
+
+#pragma D option quiet
+
+struct bitRecord1{
+ char a : 10;
+} var1;
+
+struct bitRecord2{
+ short a : 33;
+} var2;
+
+struct bitRecord3{
+ long long a : 65;
+} var3;
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFSIZE.GreaterThan64.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFSIZE.GreaterThan64.d
new file mode 100644
index 000000000000..c1e359ed8efc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFSIZE.GreaterThan64.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Bit-field width cannot be greater than 64 bits in D.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ */
+
+#pragma D option quiet
+
+struct bitRecord{
+ int a : 1;
+ int b : 65;
+ int c : 12;
+} var;
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFTYPE.badtype.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFTYPE.badtype.d
new file mode 100644
index 000000000000..5e7b5233055b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_DECL_BFTYPE.badtype.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Non-integer types used for bitfields will result in a D_DECL_BFTYPE
+ * error.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ */
+
+#pragma D option quiet
+
+struct bits {
+ float : 1;
+} xyz;
+
+BEGIN
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_OFFSETOF_BITFIELD.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_OFFSETOF_BITFIELD.d
new file mode 100644
index 000000000000..402a209d1e39
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_OFFSETOF_BITFIELD.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Cannot apply offsetof operator to a bit-field member.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ *
+ */
+#pragma D option quiet
+
+struct bitRecord{
+ int a : 17;
+ int b : 3;
+ int c : 12;
+} var;
+
+BEGIN
+{
+ printf("offsetof(struct bitRecord, a): %d\n",
+ offsetof(struct bitRecord, a));
+ printf("offsetof(struct bitRecord, b): %d\n",
+ offsetof(struct bitRecord, b));
+ printf("offsetof(struct bitRecord, c): %d\n",
+ offsetof(struct bitRecord, c));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_SIZEOF_BITFIELD.SizeofBitfield.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_SIZEOF_BITFIELD.SizeofBitfield.d
new file mode 100644
index 000000000000..70c28340d425
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/err.D_SIZEOF_BITFIELD.SizeofBitfield.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Cannot apply sizeof operator to a bit-field member.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ */
+
+#pragma D option quiet
+
+struct bitRecord{
+ int a : 1;
+ int b : 3;
+ int c : 12;
+} var;
+
+BEGIN
+{
+ printf("sizeof (a): %d\nsizeof (b): %d\nsizeof (c): %n",
+ sizeof (var.a), sizeof (var.b), sizeof (var.c));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/tst.BitFieldPromotion.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/tst.BitFieldPromotion.d
new file mode 100644
index 000000000000..07ec728bc500
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/tst.BitFieldPromotion.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Bit-field will be automatically promoted to the next largest
+ * integer type for use in any expression and then the value assigned will
+ * warp around the maximum number assignable to the data type.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ */
+
+#pragma D option quiet
+
+struct bitRecord{
+ int a : 1;
+ int b : 15;
+ int c : 31;
+} var;
+
+BEGIN
+{
+ var.a = 256;
+ var.b = 65536;
+ var.c = 4294967296;
+
+ printf("bitRecord.a: %d\nbitRecord.b: %d\nbitRecord.c: %d\n",
+ var.a, var.b, var.c);
+ exit(0);
+}
+
+END
+/(0 != var.a) || (0 != var.b) || (0 != var.c)/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/tst.SizeofBitField.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/tst.SizeofBitField.d
new file mode 100644
index 000000000000..ce307de6194a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/bitfields/tst.SizeofBitField.d
@@ -0,0 +1,109 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: C and D compilers try to pack bits as efficiently as possible.
+ *
+ * SECTION: Structs and Unions/Bit-Fields
+ */
+
+#pragma D option quiet
+
+struct bitRecord1 {
+ int a : 1;
+} var1;
+
+struct bitRecord2 {
+ int a : 1;
+ int b : 3;
+} var2;
+
+struct bitRecord3 {
+ int a : 1;
+ int b : 3;
+ int c : 3;
+} var3;
+
+struct bitRecord4 {
+ int a : 1;
+ int b : 3;
+ int c : 3;
+ int d : 3;
+} var4;
+
+struct bitRecord5 {
+ int c : 12;
+ int a : 10;
+ int b : 3;
+} var5;
+
+struct bitRecord6 {
+ int a : 20;
+ int b : 3;
+ int c : 12;
+} var6;
+
+struct bitRecord7 {
+ long c : 32;
+ long long d: 9;
+ int e: 1;
+} var7;
+
+struct bitRecord8 {
+ char a : 2;
+ short b : 12;
+ long c : 32;
+} var8;
+
+struct bitRecord12 {
+ int a : 30;
+ int b : 30;
+ int c : 32;
+} var12;
+
+BEGIN
+{
+ printf("sizeof (bitRecord1): %d\n", sizeof (var1));
+ printf("sizeof (bitRecord2): %d\n", sizeof (var2));
+ printf("sizeof (bitRecord3): %d\n", sizeof (var3));
+ printf("sizeof (bitRecord4): %d\n", sizeof (var4));
+ printf("sizeof (bitRecord5): %d\n", sizeof (var5));
+ printf("sizeof (bitRecord6): %d\n", sizeof (var6));
+ printf("sizeof (bitRecord7): %d\n", sizeof (var7));
+ printf("sizeof (bitRecord8): %d\n", sizeof (var8));
+ printf("sizeof (bitRecord12): %d\n", sizeof (var12));
+ exit(0);
+}
+
+END
+/(1 != sizeof (var1)) || (2 != sizeof (var2)) || (3 != sizeof (var3)) ||
+ (4 != sizeof (var4)) || (5 != sizeof (var5)) || (6 != sizeof (var6))
+ || (7 != sizeof (var7)) || (8 != sizeof (var8)) || (12 != sizeof (var12))/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.end.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.end.d
new file mode 100644
index 000000000000..a480d67a476d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.end.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Checks that buffer space for an END enabling is always reserved in a
+ * fill buffer. This will fail because the size of the END enabling
+ * (64 bytes) exceeds the size of the buffer (32 bytes).
+ *
+ * SECTION: Buffers and Buffering/fill Policy;
+ * Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/strsize
+ */
+
+#pragma D option bufpolicy=fill
+#pragma D option bufsize=32
+#pragma D option strsize=64
+
+BEGIN
+{
+ exit(0);
+}
+
+END
+{
+ trace(execname);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize1.d
new file mode 100644
index 000000000000..4731bd1ff8d2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize1.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Checks that setting "bufresize" to "manual" will cause buffer
+ * allocation to fail for large principal buffer sizes.
+ *
+ * SECTION: Buffers and Buffering/Buffer Resizing Policy;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufresize
+ *
+ */
+
+#pragma D option bufresize=manual
+#pragma D option bufsize=100t
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize2.d
new file mode 100644
index 000000000000..4dfe6b65c545
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize2.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Checks that setting "bufresize" to "manual" will cause buffer
+ * allocation to fail for large aggregation buffer sizes.
+ *
+ * SECTION: Buffers and Buffering/Buffer Resizing Policy;
+ * Options and Tunables/bufresize;
+ * Options and Tunables/aggsize
+ *
+ */
+
+#pragma D option bufresize=manual
+#pragma D option aggsize=100t
+
+BEGIN
+{
+ @a[probeprov] = count();
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize3.d
new file mode 100644
index 000000000000..866a56c6112d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.resize3.d
@@ -0,0 +1,62 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Checks that setting "bufresize" to "manual" will cause buffer
+ * allocation to fail for large speculative buffer sizes.
+ *
+ * SECTION: Buffers and Buffering/Buffer Resizing Policy;
+ * Options and Tunables/bufresize;
+ * Options and Tunables/specsize
+ *
+ */
+
+#pragma D option bufresize=manual
+#pragma D option specsize=100t
+
+BEGIN
+{
+ spec = speculation();
+}
+
+BEGIN
+{
+ speculate(spec);
+ trace(epid);
+}
+
+BEGIN
+{
+ commit(spec);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.zerobuf.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.zerobuf.d
new file mode 100644
index 000000000000..a2e44350eeda
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/err.zerobuf.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test with a bufsize of 0 - should return an error.
+ *
+ * SECTION:
+ * Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufsize
+ */
+
+#pragma D option bufsize=0
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.alignring.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.alignring.d
new file mode 100644
index 000000000000..152acb61cd9c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.alignring.d
@@ -0,0 +1,81 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for ring buffer policy.
+ *
+ * SECTION: Buffers and Buffering/ring Policy;
+ * Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy
+ */
+
+#pragma D option bufpolicy=ring
+#pragma D option bufsize=4k
+
+profile:::profile-1009hz
+{
+ printf("%x %x\n", (int)0xaaaa, (int)0xbbbb);
+}
+
+profile:::profile-1237hz
+{
+ printf("%x %x %x %x %x %x\n",
+ (int)0xcccc,
+ (int)0xdddd,
+ (int)0xeeee,
+ (int)0xffff,
+ (int)0xabab,
+ (int)0xacac);
+ printf("%x %x\n",
+ (uint64_t)0xaabbaabbaabbaabb,
+ (int)0xadad);
+}
+
+profile:::profile-1789hz
+{
+ printf("%x %x %x %x %x\n",
+ (int)0xaeae,
+ (int)0xafaf,
+ (unsigned char)0xaa,
+ (int)0xbcbc,
+ (int)0xbdbd);
+}
+
+profile-1543hz
+{}
+
+profile-1361hz
+{}
+
+tick-1sec
+/i++ >= 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.cputime.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.cputime.ksh
new file mode 100644
index 000000000000..6ac0fa9e27a3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.cputime.ksh
@@ -0,0 +1,90 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -s /dev/stdin -x bufpolicy=$1 $1 <<EOF
+
+ #pragma D option quiet
+ #pragma D option statusrate=1hz
+
+ uint64_t total;
+ int thresh;
+
+ BEGIN
+ {
+ start = timestamp;
+ thresh = 10;
+ }
+
+ sched:::on-cpu
+ /pid == \$pid/
+ {
+ self->on = vtimestamp;
+ }
+
+ sched:::off-cpu
+ /self->on/
+ {
+ total += vtimestamp - self->on;
+ }
+
+ tick-1sec
+ /i++ == 10/
+ {
+ exit(0);
+ }
+
+ END
+ /((total * 100) / (timestamp - start)) > thresh/
+ {
+ printf("'%s' buffering policy took %d%% of CPU; ",
+ \$\$1, ((total * 100) / (timestamp - start)));
+ printf("expected no more than %d%%!\n", thresh);
+ exit(1);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+for policy in "fill ring switch"; do
+ script $policy
+
+ status=$?
+
+ if [ "$status" -ne 0 ]; then
+ exit $status
+ fi
+done
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.dynvarsize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.dynvarsize.d
new file mode 100644
index 000000000000..c8a074002d5d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.dynvarsize.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for dynamic variable size.
+ *
+ * SECTION: Buffers and Buffering/switch Policy;
+ * Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/switchrate
+ */
+
+#pragma D option dynvarsize=100
+#pragma D option quiet
+
+int n;
+
+tick-10ms
+/n++ < 100/
+{
+ a[n] = 1;
+}
+
+tick-10ms
+/n == 100/
+{
+ exit(2);
+}
+
+END
+/a[99]/
+{
+ exit(1);
+}
+
+END
+/!a[99]/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.fill1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.fill1.d
new file mode 100644
index 000000000000..fffc7e3d550c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.fill1.d
@@ -0,0 +1,118 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * Positive test for fill buffer policy.
+ *
+ * SECTION: Buffers and Buffering/fill Policy;
+ * Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+/*
+ * This is a brute-force way of testing fill buffers. We assume that
+ * each printf() stores 16 bytes (4x 32-bit words for EPID, timestamp
+ * lo, timestamp hi, and the variable i). Because each fill buffer is
+ * per-CPU, we must fill up our buffer in one series of enablings on a
+ * single CPU.
+ */
+#pragma D option bufpolicy=fill
+#pragma D option bufsize=128
+#pragma D option statusrate=10ms
+#pragma D option quiet
+
+int i;
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+{
+ printf("%d\n", i++);
+}
+
+tick-10ms
+/i >= 100/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.fill1.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.fill1.d.out
new file mode 100644
index 000000000000..fd8abec1dfe6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.fill1.d.out
@@ -0,0 +1,9 @@
+0
+1
+2
+3
+4
+5
+6
+7
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize1.d
new file mode 100644
index 000000000000..ca8ad44a621b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize1.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Checks that setting "bufresize" to "auto" will cause buffer
+ * allocation to succeed, even for large principal buffer sizes.
+ *
+ * SECTION: Buffers and Buffering/Buffer Resizing Policy;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufresize
+ */
+
+#pragma D option bufresize=auto
+#pragma D option bufsize=100t
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize2.d
new file mode 100644
index 000000000000..ddb97c89ec1f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize2.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Checks that setting "bufresize" to "auto" will cause buffer
+ * allocation to succeed, even for large aggregation buffer sizes.
+ *
+ * SECTION: Buffers and Buffering/Buffer Resizing Policy;
+ * Options and Tunables/aggsize;
+ * Options and Tunables/bufresize
+ */
+
+#pragma D option bufresize=auto
+#pragma D option aggsize=100t
+
+BEGIN
+{
+ @a[probeprov] = count();
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize3.d
new file mode 100644
index 000000000000..eb362fb31372
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize3.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Checks that setting "bufresize" to "auto" will cause buffer
+ * allocation to succeed, even for large speculative buffer sizes.
+ *
+ * SECTION: Buffers and Buffering/Buffer Resizing Policy;
+ * Options and Tunables/specsize;
+ * Options and Tunables/bufresize
+ *
+ * NOTES:
+ * On some small memory machines, this test may consume so much memory
+ * that it induces memory allocation failure in the dtrace library. This
+ * will manifest itself as an error like one of the following:
+ *
+ * dtrace: processing aborted: Memory allocation failure
+ * dtrace: could not enable tracing: Memory allocation failure
+ *
+ * These actually indicate that the test performed as expected; failures
+ * of the above nature should therefore be ignored.
+ *
+ */
+
+#pragma D option bufresize=auto
+#pragma D option specsize=100t
+
+BEGIN
+{
+ spec = speculation();
+}
+
+BEGIN
+{
+ speculate(spec);
+ trace(epid);
+}
+
+BEGIN
+{
+ commit(spec);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring1.d
new file mode 100644
index 000000000000..67e7b8755561
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring1.d
@@ -0,0 +1,75 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for ring buffer policy.
+ *
+ * SECTION: Buffers and Buffering/ring Policy;
+ * Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/switchrate
+ */
+
+/*
+ * We assume that a trace() of an integer stores at least 8 bytes. If ring
+ * buffering is not working properly, this trace() will induce a drop, and the
+ * counter won't be incremented. We set the switchrate to one second just to
+ * sure that a high switchrate doesn't mask broken ring buffers.
+ */
+#pragma D option bufpolicy=ring
+#pragma D option bufsize=50
+#pragma D option switchrate=1sec
+
+int n;
+int i;
+
+tick-10msec
+/n < 300/
+{
+ trace(i);
+ i++;
+}
+
+tick-10msec
+/n < 300/
+{
+ n++;
+}
+
+tick-10msec
+/n == 300/
+{
+ exit(2);
+}
+
+END
+{
+ exit(i == 300 ? 0 : 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring2.d
new file mode 100644
index 000000000000..cbf48f2b0103
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring2.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for ring buffer policy.
+ *
+ * SECTION: Buffers and Buffering/ring Policy;
+ * SECTION: Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy
+ */
+
+#pragma D option bufpolicy=ring
+#pragma D option bufsize=512k
+#pragma D option quiet
+
+tick-1sec
+/n < 5/
+{
+ printf("%d\n", n++);
+}
+
+tick-1sec
+/n == 5/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring2.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring2.d.out
new file mode 100644
index 000000000000..cc4d41aab2b2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring2.d.out
@@ -0,0 +1,6 @@
+0
+1
+2
+3
+4
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring3.d
new file mode 100644
index 000000000000..68e35889eca0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring3.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for ring buffer policy.
+ *
+ * SECTION: Buffers and Buffering/ring Policy;
+ * Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy
+ */
+
+/*
+ * We make some regrettable assumptions about the implementation in this test.
+ * First, we assume that each entry for the printf() of an int takes _exactly_
+ * eight bytes (four bytes for the EPID, four bytes for the payload). Second,
+ * we assume that by allocating storage for n + 1 records, we will get exactly
+ * n. Here is why: the final predicate that evaluates to false will reserve
+ * space that it won't use. This act of reservation will advance the wrapped
+ * offset. That record won't be subsequently used, but the wrapped offset has
+ * advanced. (And in this case, that old record is clobbered by the exit()
+ * anyway.) Thirdly: we rely on t_cpu/cpu_id. Finally: we rely on being
+ * able to run on the CPU that we first ran on.
+ */
+#pragma D option bufpolicy=ring
+#pragma D option bufsize=40
+#pragma D option quiet
+
+int n;
+
+BEGIN
+{
+ cpuid = -1;
+}
+
+tick-10msec
+/cpuid == -1/
+{
+ cpuid = curthread->t_cpu->cpu_id;
+}
+
+tick-10msec
+/curthread->t_cpu->cpu_id == cpuid && n < 100/
+{
+ printf("%d\n", n++);
+}
+
+tick-10msec
+/n == 100/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring3.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring3.d.out
new file mode 100644
index 000000000000..99fd231e65be
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.ring3.d.out
@@ -0,0 +1,5 @@
+96
+97
+98
+99
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.smallring.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.smallring.d
new file mode 100644
index 000000000000..2134a0b726ae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.smallring.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for ring buffer policy.
+ *
+ * SECTION: Buffers and Buffering/ring Policy;
+ * Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy
+ */
+
+#pragma D option bufpolicy=ring
+#pragma D option bufsize=16
+
+tick-10ms
+{
+ trace(0xbadbaddefec8d);
+}
+
+tick-10ms
+/0/
+{
+ trace((int)1);
+}
+
+tick-100ms
+/i++ > 2/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.switch1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.switch1.d
new file mode 100644
index 000000000000..2840feeffd5d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.switch1.d
@@ -0,0 +1,69 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for switch buffer policy.
+ *
+ * SECTION: Buffers and Buffering/switch Policy;
+ * Buffers and Buffering/Buffer Sizes;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/switchrate
+ */
+
+/*
+ * We assume that a printf() of an integer stores at least 8 bytes, and no more
+ * than 16 bytes.
+ */
+#pragma D option bufpolicy=switch
+#pragma D option bufsize=32
+#pragma D option switchrate=500msec
+#pragma D option quiet
+
+int n;
+int i;
+
+tick-1sec
+/n < 10/
+{
+ printf("%d\n", i);
+ i++;
+}
+
+tick-1sec
+/n < 10/
+{
+ n++;
+}
+
+tick-1sec
+/n == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.switch1.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.switch1.d.out
new file mode 100644
index 000000000000..ce6c2bcb01fc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.switch1.d.out
@@ -0,0 +1,11 @@
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.cpuusage.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.cpuusage.d
new file mode 100644
index 000000000000..e1e0dd83792d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.cpuusage.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print non assigned value and make sure it fails.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The cpuusage = %d\n", curlwpsinfo->pr_cpu);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.nice.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.nice.d
new file mode 100644
index 000000000000..c7a4ad21884e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.nice.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * print non assigned value and make sure it fails.
+ *
+ * SECTION: Variables/Built-in Variables
+ *
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The nice for cpu usage %c\n", curlwpsinfo->pr_nice);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.priority.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.priority.d
new file mode 100644
index 000000000000..6ebb3dfa1cd2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.priority.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Print non assigned variables and make sure it fails.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The low value is high priority field = %d\n",
+ curlwpsinfo->pr_nice);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.prsize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.prsize.d
new file mode 100644
index 000000000000..f467f1927ad8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.prsize.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print non assigned variables and make sure it fails.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("Size of process image in kbytes = %ld\n", curpsinfo->pr_size);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.rssize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.rssize.d
new file mode 100644
index 000000000000..48057e14c9d1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/err.D_XLATE_NOCONV.rssize.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print non assigned variables and make sure it fails.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("Size of process image in kbytes = %ld\n", curpsinfo->pr_rssize);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg0.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg0.d
new file mode 100644
index 000000000000..ec3c277f9abc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg0.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print arg0 and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The argument is %u\n", arg0);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg0clause.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg0clause.d
new file mode 100644
index 000000000000..4c782f835580
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg0clause.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print arg0 from a profile and make sure it succeeds
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("Call probe read\n");
+}
+
+syscall:::entry
+{
+ printf("The argument is %u", arg0);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1.d
new file mode 100644
index 000000000000..993a3765ffd4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print arg1 and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The argument is %u\n", arg1);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1to8.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1to8.d
new file mode 100644
index 000000000000..b696d7c22ca6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1to8.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print arg1 to arg8 and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The argument is %u %u %u %u %u %u %u %u\n", arg1, arg2,
+ arg3, arg4, arg5, arg6, arg7, arg8);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1to8clause.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1to8clause.d
new file mode 100644
index 000000000000..fa62b03b122e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.arg1to8clause.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print arg1 to arg8 from a profile and make sure it succeeds
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+syscall:::entry
+{
+ printf("The argument is %u %u %u %u %u %u %u %u\n", arg1, arg2,
+ arg3, arg4, arg5, arg6, arg7, arg8);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.caller.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.caller.d
new file mode 100644
index 000000000000..db1eabce2f02
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.caller.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print 'caller' and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The caller is %u\n", caller);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.caller1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.caller1.d
new file mode 100644
index 000000000000..f1bfeedfec6c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.caller1.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print caller form profile and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+tick-10ms
+{
+ printf("The caller is %u\n", caller);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.epid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.epid.d
new file mode 100644
index 000000000000..4f04c65679fa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.epid.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print 'epid'from profile and make sure it succeeds
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+tick-10ms
+{
+ printf("epid of this probe = %d\n", epid);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.epid1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.epid1.d
new file mode 100644
index 000000000000..4cba65e6da96
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.epid1.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * print epid and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("epid of this probe = %d\n", epid);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.errno.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.errno.d
new file mode 100644
index 000000000000..4d7a4ffcc5f1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.errno.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print errno from profile and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+tick-10ms
+{
+ printf("epid of this probe = %d\n", epid);
+ printf("the errno = %d\n", errno);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.errno1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.errno1.d
new file mode 100644
index 000000000000..ed233bf04d08
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.errno1.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print errno and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("epid of this probe = %d\n", epid);
+ printf("the errno = %d\n", errno);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.execname.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.execname.d
new file mode 100644
index 000000000000..b3007de38aee
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.execname.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print execname and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+/execname == "dtrace" || execname == "java"/
+{
+ trace("execname matched");
+ exit(0);
+}
+
+BEGIN
+{
+ trace("execname didn't match");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.hpriority.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.hpriority.d
new file mode 100644
index 000000000000..a0d8836780c8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.hpriority.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print hpriority and make sure it succeeds
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The high priority = %d\n", curlwpsinfo->pr_pri);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.id.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.id.d
new file mode 100644
index 000000000000..291d91d96e1b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.id.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print 'id' from profile.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+tick-10ms
+{
+ printf("id of this probe = %d\n", id);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.id1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.id1.d
new file mode 100644
index 000000000000..068cff65ede7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.id1.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print id and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("id of this probe = %d\n", id);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.ipl.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.ipl.d
new file mode 100644
index 000000000000..2e6f349d79f9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.ipl.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print variable ipl
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+tick-10ms
+{
+ printf("The interrupt priority level = %u\n", ipl);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.ipl1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.ipl1.d
new file mode 100644
index 000000000000..ef9278d1c6e9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.ipl1.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print ipl and make sure it succeeds
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The interrupt priority level = %u\n", ipl);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.lwpsinfo.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.lwpsinfo.d
new file mode 100644
index 000000000000..f0e9d4605bf2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.lwpsinfo.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print lwpsinfo_t structure values.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+tick-10ms
+{
+ printf("The current thread's pr_flag is %d\n", curlwpsinfo->pr_flag);
+ printf("The current threads lwpid is %d\n", curlwpsinfo->pr_lwpid);
+ printf("The current thread's internal address is %u\n",
+ curlwpsinfo->pr_addr);
+ printf("The current thread's wait addr for sleeping lwp is %u\n",
+ curlwpsinfo->pr_wchan);
+ printf("The current lwp stat is %d\n", curlwpsinfo->pr_state);
+ printf("The printable character for pr_state %c\n",
+ curlwpsinfo->pr_sname);
+ printf("The syscall number = %d\n", curlwpsinfo->pr_syscall);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.lwpsinfo1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.lwpsinfo1.d
new file mode 100644
index 000000000000..aa11b07d63a7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.lwpsinfo1.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print lwpsinfo_t variables and make sure it succeeds
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("The current thread's pr_flag is %d\n", curlwpsinfo->pr_flag);
+ printf("The current threads lwpid is %d\n", curlwpsinfo->pr_lwpid);
+ printf("The current thread's internal address is %u\n",
+ curlwpsinfo->pr_addr);
+ printf("The current thread's wait addr for sleeping lwp is %u\n",
+ curlwpsinfo->pr_wchan);
+ printf("The current lwp stat is %d\n", curlwpsinfo->pr_state);
+ printf("The printable character for pr_state %c\n",
+ curlwpsinfo->pr_sname);
+ printf("The syscall number = %d\n", curlwpsinfo->pr_syscall);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.pid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.pid.d
new file mode 100644
index 000000000000..2dd80d71cd19
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.pid.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print 'pid' from profile.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+tick-10ms
+{
+ printf("process id = %d \n", pid);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.pid1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.pid1.d
new file mode 100644
index 000000000000..5cee07c5fbfb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.pid1.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print 'pid' and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("process id = %d \n", pid);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.psinfo.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.psinfo.d
new file mode 100644
index 000000000000..6961a0d58055
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.psinfo.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print psinfo structure values from profile.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+tick-10ms
+{
+ printf("number of lwps in process = %d\n", curpsinfo->pr_nlwp);
+ printf("unique process id = %d\n", curpsinfo->pr_pid);
+ printf("process id of parent = %d\n", curpsinfo->pr_ppid);
+ printf("pid of process group leader = %d\n", curpsinfo->pr_pgid);
+ printf("session id = %d\n", curpsinfo->pr_sid);
+ printf("real user id = %d\n", curpsinfo->pr_uid);
+ printf("effective user id = %d\n", curpsinfo->pr_euid);
+ printf("real group id = %d\n", curpsinfo->pr_gid);
+ printf("effective group id = %d\n", curpsinfo->pr_egid);
+ printf("address of process = %u\n", curpsinfo->pr_addr);
+ exit (0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.psinfo1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.psinfo1.d
new file mode 100644
index 000000000000..b805e2754502
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.psinfo1.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print psinfo structure values.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("number of lwps in process = %d\n", curpsinfo->pr_nlwp);
+ printf("unique process id = %d\n", curpsinfo->pr_pid);
+ printf("process id of parent = %d\n", curpsinfo->pr_ppid);
+ printf("pid of process group leader = %d\n", curpsinfo->pr_pgid);
+ printf("session id = %d\n", curpsinfo->pr_sid);
+ printf("real user id = %d\n", curpsinfo->pr_uid);
+ printf("effective user id = %d\n", curpsinfo->pr_euid);
+ printf("real group id = %d\n", curpsinfo->pr_gid);
+ printf("effective group id = %d\n", curpsinfo->pr_egid);
+ printf("address of process = %u\n", curpsinfo->pr_addr);
+ exit (0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.tid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.tid.d
new file mode 100644
index 000000000000..1b16c8bb53da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.tid.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print tid from profile
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+
+tick-10ms
+{
+ printf("Thread id = %d \n", tid);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.tid1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.tid1.d
new file mode 100644
index 000000000000..a0567e7094dc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.tid1.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * To print tid and make sure it succeeds.
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("Thread id = %d \n", tid);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.timestamp.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.timestamp.d
new file mode 100644
index 000000000000..cd94eac842f2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.timestamp.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print build-in variable 'timestamp'
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ self->t = timestamp;
+ printf("The difftime = %d\n", timestamp - self->t);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.vtimestamp.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.vtimestamp.d
new file mode 100644
index 000000000000..cdbecfc7a134
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/builtinvar/tst.vtimestamp.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To print build-in variable 'vtimestamp'
+ *
+ * SECTION: Variables/Built-in Variables
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ self->t = vtimestamp;
+ printf("The difftime = %d\n", vtimestamp - self->t);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cg/err.D_NOREG.noreg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cg/err.D_NOREG.noreg.d
new file mode 100644
index 000000000000..636e5686433d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cg/err.D_NOREG.noreg.d
@@ -0,0 +1,41 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * Compile some code that requires exactly 9 registers. This should run out
+ * of registers.
+ *
+ * Changes to the code generator might cause this test to succeeed in which
+ * case the code should be changed to another sequence that exhausts the
+ * available internal registers.
+ *
+ * Note that this and err.baddif.d should be kept in sync.
+ */
+
+BEGIN
+{
+ a = 4;
+ trace((a + a) * ((a + a) * ((a + a) * ((a + a) * ((a + a) *
+ ((a + a) * (a + a)))))));
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cg/err.baddif.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cg/err.baddif.d
new file mode 100644
index 000000000000..d84934823354
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cg/err.baddif.d
@@ -0,0 +1,44 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * Compile some code that requires exactly 9 registers. This should generate
+ * invalid DIF because the kernel will flag the fact that we're using more
+ * registers than are available internally.
+ *
+ * Changes to the code generator might cause this test to succeeed in which
+ * case the code should be changed to another sequence that exhausts the
+ * available internal registers.
+ *
+ * Note that this and err.D_NOREG.noreg.d should be kept in sync.
+ */
+
+#pragma D option iregs=9
+
+BEGIN
+{
+ a = 4;
+ trace((a + a) * ((a + a) * ((a + a) * ((a + a) * ((a + a) *
+ ((a + a) * (a + a)))))));
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.aggfun.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.aggfun.d
new file mode 100644
index 000000000000..f687717431da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.aggfun.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause where an unknown identifier appears in a predicated
+ * clause inside an aggregating function.
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+/1/
+{
+ @a = max(x);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.aggtup.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.aggtup.d
new file mode 100644
index 000000000000..1fa49747f2a7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.aggtup.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause where an unknown identifier appears in a predicated
+ * clause inside an aggregation tuple.
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+/1/
+{
+ @a[x] = count();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.arrtup.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.arrtup.d
new file mode 100644
index 000000000000..6c1cdffbd37a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.arrtup.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause where an unknown identifier appears in a predicated
+ * clause inside an associate array tuple.
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+/1/
+{
+ a[x]++;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.body.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.body.d
new file mode 100644
index 000000000000..da499cb570cd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.body.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause where an unknown identifier appears in a clause.
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+{
+ exit(x);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.both.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.both.d
new file mode 100644
index 000000000000..007082730c30
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.both.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause where an unknown identifier appears in a predicate
+ * and in a clause body.
+ *
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+/x != 0/
+{
+ exit(x);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.pred.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.pred.d
new file mode 100644
index 000000000000..0bfc86f4cb87
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/err.D_IDENT_UNDEF.pred.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause where an unknown identifier appears in a predicate.
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+/x != 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.nopred.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.nopred.d
new file mode 100644
index 000000000000..44d11675f5b2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.nopred.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause that has a body but no predicate.
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.pred.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.pred.d
new file mode 100644
index 000000000000..43bfedd8edce
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.pred.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause that has a body and a predicate.
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+/$pid != 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.predfirst.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.predfirst.d
new file mode 100644
index 000000000000..c7f0b4eb2b75
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.predfirst.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause that has a body and a predicate where the
+ * predicate must be cooked first because it creates a variable.
+ *
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+/x++ == 0/
+{
+ exit(x - 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.predlast.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.predlast.d
new file mode 100644
index 000000000000..9ed904f765c6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/clauses/tst.predlast.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test a clause that has a body and a predicate where the
+ * predicate must be cooked last because the clause creates
+ * a variable which is referenced in the predicate.
+ *
+ * SECTION: Program Structure / Probe Clauses and Declarations
+ *
+ */
+
+BEGIN
+/x == 0/
+{
+ exit(x++);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.lowfrequency.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.lowfrequency.d
new file mode 100644
index 000000000000..1015a251cfeb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.lowfrequency.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Test to check that attempting to enable a valid event with a frequency
+ * lower than the default platform limit will fail.
+ *
+ * This test will fail if:
+ * 1) The system under test does not define the 'PAPI_tot_ins' event.
+ * 2) The 'dcpc-min-overflow' variable in dcpc.conf has been modified.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ exit(0);
+}
+
+cpc:::PAPI_tot_ins-all-100
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.malformedoverflow.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.malformedoverflow.d
new file mode 100644
index 000000000000..f9b780942fab
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.malformedoverflow.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Tests that specifying an overflow value containing extraneous characters
+ * (only digits are allowed) will fail.
+ */
+
+BEGIN
+{
+ exit(0);
+}
+
+cpc:::PAPI_tot_ins-all-10000bonehead
+{
+ @[probename] = count();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.nonexistentevent.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.nonexistentevent.d
new file mode 100644
index 000000000000..73f9575fbe6b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.nonexistentevent.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Tests that attempting to enable a probe containing a non existent event
+ * will fail.
+ */
+
+BEGIN
+{
+ exit(0);
+}
+
+cpc:::PAPI_cpc_bad-all-10000
+{
+ @[probename] = count();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart1.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart1.ksh
new file mode 100644
index 000000000000..767d493a76b7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart1.ksh
@@ -0,0 +1,78 @@
+#!/bin/ksh
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+
+#
+# This tests that cpustat(1) should fail to start if the cpc provider
+# is already calling the shots.
+#
+# This script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins'
+# generic event.
+
+script()
+{
+ $dtrace -o $dtraceout -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+
+ cpc:::PAPI_tot_ins-all-10000
+ {
+ @[probename] = count();
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+dtraceout=/tmp/dtrace.out.$$
+script 2>/dev/null &
+timeout=15
+
+#
+# Sleep while the above script fires into life. To guard against dtrace dying
+# and us sleeping forever we allow 15 secs for this to happen. This should be
+# enough for even the slowest systems.
+#
+while [ ! -f $dtraceout ]; do
+ sleep 1
+ timeout=$(($timeout-1))
+ if [ $timeout -eq 0 ]; then
+ echo "dtrace failed to start. Exiting."
+ exit 1
+ fi
+done
+
+cpustat -c PAPI_tot_ins 1 5
+status=$?
+
+rm $dtraceout
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart2.ksh
new file mode 100644
index 000000000000..584469c3fe9c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart2.ksh
@@ -0,0 +1,70 @@
+#!/bin/ksh -p
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+
+#
+# This tests that enablings from the cpc provider will fail if cpustat(1) is
+# already master of the universe.
+#
+# This script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins'
+# generic event.
+
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+
+ BEGIN
+ {
+ exit(0);
+ }
+
+ cpc:::PAPI_tot_ins-all-10000
+ {
+ @[probename] = count();
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+dtraceout=/tmp/dtrace.out.$$
+
+cpustat -c PAPI_tot_ins 1 20 &
+pid=$!
+sleep 5
+script 2>/dev/null
+
+status=$?
+
+kill $pid
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cputrackfailtostart.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cputrackfailtostart.ksh
new file mode 100644
index 000000000000..f62b83d5714b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cputrackfailtostart.ksh
@@ -0,0 +1,77 @@
+#!/bin/ksh
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+#
+# This script ensures that cputrack(1M) will fail to start when the cpc
+# provider has active enablings.
+#
+# The script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins' event.
+#
+
+script()
+{
+ $dtrace -o $dtraceout -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+
+ cpc:::PAPI_tot_ins-all-10000
+ {
+ @[probename] = count();
+ }
+EOF
+}
+
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+dtraceout=/tmp/dtrace.out.$$
+script 2>/dev/null &
+timeout=15
+
+#
+# Sleep while the above script fires into life. To guard against dtrace dying
+# and us sleeping forever we allow 15 secs for this to happen. This should be
+# enough for even the slowest systems.
+#
+while [ ! -f $dtraceout ]; do
+ sleep 1
+ timeout=$(($timeout-1))
+ if [ $timeout -eq 0 ]; then
+ echo "dtrace failed to start. Exiting."
+ exit 1
+ fi
+done
+
+cputrack -c PAPI_tot_ins sleep 10
+status=$?
+
+rm $dtraceout
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cputrackterminates.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cputrackterminates.ksh
new file mode 100644
index 000000000000..58d1e798f10e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.cputrackterminates.ksh
@@ -0,0 +1,70 @@
+#!/bin/ksh
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+#
+# This script ensures that cputrack(1) will terminate when the cpc provider
+# kicks into life.
+#
+# The script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins' event.
+#
+
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+
+ cpc:::PAPI_tot_ins-all-10000
+ {
+ @[probename] = count();
+ }
+
+ tick-1s
+ /n++ > 10/
+ {
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+cputrack -c PAPI_tot_ins sleep 20 &
+cputrack_pid=$!
+sleep 5
+script 2>/dev/null &
+
+wait $cputrack_pid
+status=$?
+
+rm $dtraceout
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.toomanyenablings.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.toomanyenablings.d
new file mode 100644
index 000000000000..a50bd71ae6ae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/err.toomanyenablings.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Test to check that attempting to enable too many probes will fail.
+ *
+ * This test will fail if:
+ * 1) We ever execute on a platform which is capable of programming 10
+ * 'PAPI_tot_ins' events simultaneously (which no current platforms are
+ * capable of doing).
+ * 2) The system under test does not define the 'PAPI_tot_ins' event.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ exit(0);
+}
+
+cpc:::PAPI_tot_ins-all-10000,
+cpc:::PAPI_tot_ins-all-10001,
+cpc:::PAPI_tot_ins-all-10002,
+cpc:::PAPI_tot_ins-all-10003,
+cpc:::PAPI_tot_ins-all-10004,
+cpc:::PAPI_tot_ins-all-10005,
+cpc:::PAPI_tot_ins-all-10006,
+cpc:::PAPI_tot_ins-all-10007,
+cpc:::PAPI_tot_ins-all-10008,
+cpc:::PAPI_tot_ins-all-10009
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.allcpus.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.allcpus.ksh
new file mode 100644
index 000000000000..7f026c9ebca7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.allcpus.ksh
@@ -0,0 +1,107 @@
+#!/bin/ksh
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This script verifies that we can fire a probe on each CPU that is in
+# an online state.
+#
+# The script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins' event.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+numproc=`psrinfo | tail -1 | cut -f1`
+cpu=0
+dtraceout=/var/tmp/dtrace.out.$$
+scriptout=/var/tmp/script.out.$$
+
+spin()
+{
+ while [ 1 ]; do
+ :
+ done
+}
+
+script()
+{
+ $dtrace -o $dtraceout -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+ #pragma D option quiet
+
+ cpc:::PAPI_tot_ins-user-10000
+ /cpus[cpu] != 1/
+ {
+ cpus[cpu] = 1;
+ @a[cpu] = count();
+ }
+
+ tick-1s
+ /n++ > 10/
+ {
+ printa(@a);
+ exit(0);
+ }
+EOF
+}
+
+echo "" > $scriptout
+while [ $cpu -le $numproc ]
+do
+ if [ "`psrinfo -s $cpu 2> /dev/null`" -eq 1 ]; then
+ printf "%9d %16d\n" $cpu 1 >> $scriptout
+ spin &
+ allpids[$cpu]=$!
+ pbind -b $cpu $!
+ fi
+ cpu=$(($cpu+1))
+done
+echo "" >> $scriptout
+
+script
+
+diff $dtraceout $scriptout >/dev/null 2>&1
+status=$?
+
+# kill off the spinner processes
+cpu=0
+while [ $cpu -le $numproc ]
+do
+ if [ "`psrinfo -s $cpu 2> /dev/null`" -eq 1 ]; then
+ kill ${allpids[$cpu]}
+ fi
+ cpu=$(($cpu+1))
+done
+
+rm $dtraceout
+rm $scriptout
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.genericevent.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.genericevent.d
new file mode 100644
index 000000000000..7ebf844e9cbe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.genericevent.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Test that we can successfully enable a probe using a generic event.
+ * Currently, all platforms implement 'PAPI_tot_ins' so we'll use that.
+ * Note that this test will fail if the system under test does not
+ * implement that event.
+ *
+ * This test will fail if:
+ * 1) The system under test does not define the 'PAPI_tot_ins' event.
+ */
+
+#pragma D option quiet
+#pragma D option bufsize=128k
+
+cpc:::PAPI_tot_ins-all-10000
+{
+ @[probename] = count();
+}
+
+tick-1s
+/n++ > 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.platformevent.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.platformevent.ksh
new file mode 100644
index 000000000000..96d1ab8c6a71
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/cpc/tst.platformevent.ksh
@@ -0,0 +1,81 @@
+#!/bin/ksh
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This script ensures that we can enable a probe which specifies a platform
+# specific event.
+#
+
+if [ $# != 1 ]; then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+
+get_event()
+{
+ perl /dev/stdin /dev/stdout << EOF
+ open CPUSTAT, '/usr/sbin/cpustat -h |'
+ or die "Couldn't run cpustat: \$!\n";
+ while (<CPUSTAT>) {
+ if (/(\s+)event\[*[0-9]-*[0-9]*\]*:/ && !/PAPI/) {
+ @a = split(/ /, \$_);
+ \$event = \$a[\$#a-1];
+ }
+ }
+
+ close CPUSTAT;
+ print "\$event\n";
+EOF
+}
+
+script()
+{
+ $dtrace -s /dev/stdin << EOD
+ #pragma D option quiet
+ #pragma D option bufsize=128k
+
+ cpc:::$1-all-10000
+ {
+ @[probename] = count();
+ }
+
+ tick-1s
+ /n++ > 5/
+ {
+ exit(0);
+ }
+EOD
+}
+
+event=$(get_event)
+script $event
+
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_LOCASSC.NonLocalAssoc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_LOCASSC.NonLocalAssoc.d
new file mode 100644
index 000000000000..4c8ee508c682
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_LOCASSC.NonLocalAssoc.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * associative arrays may not be declared as local variables
+ *
+ * SECTION: Errtags/D_DECL_LOCASSC
+ *
+ */
+
+#pragma D option quiet
+
+this int a[int];
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_LONGINT.LongStruct.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_LONGINT.LongStruct.d
new file mode 100644
index 000000000000..2c92bfdbaac3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_LONGINT.LongStruct.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * long and long long may only be used with integer or floating-point type
+ *
+ * SECTION: Errtags/D_DECL_LONGINT
+ *
+ */
+
+#pragma D option quiet
+
+long struct mystruct
+{
+ int i;
+};
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PARMCLASS.BadStorageClass.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PARMCLASS.BadStorageClass.d
new file mode 100644
index 000000000000..8278747ed6ec
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PARMCLASS.BadStorageClass.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * inappropriate storage class for function or associative array parameter
+ * throws a D_DECL_PARMCLASS
+ *
+ * SECTION: Errtags/D_DECL_PARMCLASS
+ *
+ */
+
+#pragma D option quiet
+
+
+int foo(static int);
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_NAME.VoidName.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_NAME.VoidName.d
new file mode 100644
index 000000000000..3676c21cb713
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_NAME.VoidName.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Assert that a void parameter in a declaration where void is permitted
+ * may not have a parameter formal name associated with it.
+ */
+
+int a(void v);
+
+BEGIN,
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_TYPE.Dyn.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_TYPE.Dyn.d
new file mode 100644
index 000000000000..aecf54999970
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_TYPE.Dyn.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Assert that a function parameter in a declaration may not use a dynamic
+ * DTrace type such as an associative array type.
+ */
+
+int a(int a[int]);
+
+BEGIN,
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_VARARGS.VarLenArgs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_VARARGS.VarLenArgs.d
new file mode 100644
index 000000000000..22dbbe9b82c0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_VARARGS.VarLenArgs.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * array tuples may not use variable-length argument lists
+ *
+ * SECTION: Errtags/ D_DECL_ARRVA
+ *
+ */
+
+#pragma D option quiet
+
+
+int a[...];
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_VOID.NonSoleVoid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_VOID.NonSoleVoid.d
new file mode 100644
index 000000000000..620f0d7cca76
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_PROTO_VOID.NonSoleVoid.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * void must be sole parameter in a function declaration.
+ *
+ * SECTION: Errtags/D_DECL_FUNCVOID
+ *
+ */
+
+#pragma D option quiet
+
+int foo(int, void);
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_SIGNINT.UnsignedStruct.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_SIGNINT.UnsignedStruct.d
new file mode 100644
index 000000000000..db2e4510db30
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_SIGNINT.UnsignedStruct.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * signed and unsigned may only be used with integer type
+ *
+ * SECTION: Errtags/D_DECL_SIGNINT
+ *
+ */
+
+#pragma D option quiet
+
+/*DSTYLED*/
+unsigned struct mystruct {
+ int i;
+};
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_VOIDATTR.ShortVoidDecl.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_VOIDATTR.ShortVoidDecl.d
new file mode 100644
index 000000000000..81f90814bc8f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/err.D_DECL_VOIDATTR.ShortVoidDecl.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Attributes may not be used with void type.
+ *
+ * SECTION: Errtags/D_DECL_VOIDATTR
+ *
+ */
+
+#pragma D option quiet
+
+short void ptr;
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.arrays.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.arrays.d
new file mode 100644
index 000000000000..34ddd5fcad66
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.arrays.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Test various kinds of array declarations.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+extern int a1[];
+
+extern int a2[1];
+
+extern int a3[123][456];
+
+extern int a4[123][456][789];
+
+extern int a5[5], a6[6][6], a7[7][7][7];
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.basics.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.basics.d
new file mode 100644
index 000000000000..4c1483e2381e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.basics.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Test a variety of extern declarations that exercise the different
+ * kinds of declarations that we can process.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+extern void *e1;
+extern char e2;
+extern signed char e3;
+extern unsigned char e4;
+extern short e5;
+extern signed short e6;
+extern unsigned short e7;
+extern int e8;
+extern e9;
+extern signed int e10;
+extern unsigned int e11;
+extern long e12;
+extern signed long e13;
+extern unsigned long e14;
+extern long long e15;
+extern signed long long e16;
+extern unsigned long long e17;
+extern float e18;
+extern double e19;
+extern long double e20;
+extern vnode_t e21;
+extern struct vnode e22;
+extern union sigval e23;
+extern enum uio_rw e24;
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.funcs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.funcs.d
new file mode 100644
index 000000000000..3b691eb2873c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.funcs.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Test various kinds of function declarations.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ */
+
+extern int getint(void);
+extern int *getptr(void);
+extern int *(*funcptr)(void);
+extern int **(**funcptrptr)(void);
+
+extern int noparms();
+extern int oneparm(int);
+extern int twoparms(int, int);
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.pointers.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.pointers.d
new file mode 100644
index 000000000000..d0ab6087a00f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.pointers.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Test multiple extern declarations in a single list which build
+ * up a chain of pointers to pointers to pointers ...
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ */
+
+extern int e0, *e1, **e2, ***e3, ****e4, *****e5;
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.varargsfuncs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.varargsfuncs.d
new file mode 100644
index 000000000000..c12363fb9595
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/decls/tst.varargsfuncs.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Test functions declarations with varargs
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ */
+
+#pragma D option quiet
+
+extern int varargs1(...);
+extern int varargs2(int, ...);
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/badptr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/badptr.d
new file mode 100644
index 000000000000..c48c7294b102
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/badptr.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 5-1
+ *
+ * SECTION:
+ * DocExamples/badptr
+ */
+
+BEGIN
+{
+ x = (int *)NULL;
+ y = *x;
+ trace(y);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/countdown.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/countdown.d
new file mode 100644
index 000000000000..56b988154f6c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/countdown.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example
+ *
+ * SECTION:
+ * DocExamples/other
+ */
+
+dtrace:::BEGIN
+{
+ i = 10;
+}
+
+profile:::tick-1sec
+/i > 0/
+{
+ trace(i--);
+}
+
+profile:::tick-1000
+/i == 0/
+{
+ trace("blastoff!");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/counter.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/counter.d
new file mode 100644
index 000000000000..8b7b1b3b19b0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/counter.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc
+ *
+ * SECTION:
+ * DocExamples/other
+ */
+
+
+dtrace:::BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+{
+ i = i + 1;
+ trace(i);
+}
+
+dtrace:::END
+{
+ trace(i);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/errorpath.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/errorpath.d
new file mode 100644
index 000000000000..76fd07c2068b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/errorpath.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 17-1
+ *
+ * SECTION:
+ * DocExamples/errorpath
+ */
+
+
+BEGIN
+{
+ *(char *)NULL;
+}
+
+ERROR
+{
+ printf("Hit an error!");
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/hello.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/hello.d
new file mode 100644
index 000000000000..8e1ef8f79f30
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/hello.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 1-1
+ *
+ * SECTION:
+ * DocExamples/hello
+ */
+
+
+BEGIN
+{
+ trace("hello, world");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/kstat.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/kstat.d
new file mode 100644
index 000000000000..49871497baea
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/kstat.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 7-3
+ *
+ * SECTION:
+ * DocExamples/kstat
+ */
+
+
+#pragma D option quiet
+
+pid$1:libkstat:kstat_data_lookup:entry
+{
+ self->ksname = arg1;
+}
+
+pid$1:libkstat:kstat_data_lookup:return
+/self->ksname != NULL && arg1 != NULL/
+{
+ this->str = copyinstr(self->ksname);
+ this->ksp = (kstat_named_t *)copyin(arg1, sizeof (kstat_named_t));
+ printf("%s has ui64 value %u\n", this->str, this->ksp->value.ui64);
+}
+
+pid$1:libkstat:kstat_data_lookup:return
+/self->ksname != NULL && arg1 == NULL/
+{
+ self->ksname = NULL;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/ksyms.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/ksyms.d
new file mode 100644
index 000000000000..932262b0b913
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/ksyms.d
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 7-2
+ *
+ * SECTION:
+ * DocExamples/ksyms
+ */
+
+
+/* Must run "strings -a /dev/ksyms in another shell on the system */
+
+
+#pragma D option quiet
+
+syscall::read:entry
+/curpsinfo->pr_psargs == "strings -a /dev/ksyms"/
+{
+ printf("read %u bytes to user address %x\n", arg2, arg1);
+ self->watched = 1;
+}
+
+syscall::read:return
+/self->watched/
+{
+ self->watched = 0;
+}
+
+fbt::uiomove:entry
+/self->watched/
+{
+ this->iov = args[3]->uio_iov;
+
+ printf("uiomove %u bytes to %p in pid %d\n", this->iov->iov_len,
+ this->iov->iov_base, pid);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/renormalize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/renormalize.d
new file mode 100644
index 000000000000..7d2c6af76f46
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/renormalize.d
@@ -0,0 +1,55 @@
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Verify doc example 9-1
+ *
+ * SECTION:
+ * DocExamples/renormalize
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ start = timestamp;
+}
+
+syscall:::entry
+{
+ @func[execname] = count();
+}
+
+tick-10sec
+{
+ normalize(@func, (timestamp - start) / 1000000000);
+ printa(@func);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rtime.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rtime.d
new file mode 100644
index 000000000000..087e819314f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rtime.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 3-1
+ *
+ * SECTION:
+ * DocExamples/rtime
+ */
+
+
+#pragma D option quiet
+
+syscall::read:entry
+{
+ self->t = timestamp;
+}
+
+syscall::read:return
+/self->t != 0/
+{
+ printf("%d/%d spent %d nsecs in read(2)\n", pid,
+ tid, timestamp - self->t);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rw.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rw.d
new file mode 100644
index 000000000000..6358a7dc0078
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rw.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example
+ *
+ * SECTION:
+ * DocExamples/other
+ */
+
+
+syscall::read:entry,
+syscall::write:entry
+/pid == 102429/
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rwinfo.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rwinfo.d
new file mode 100644
index 000000000000..60f2b12a971e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rwinfo.d
@@ -0,0 +1,74 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 7-1
+ *
+ * SECTION:
+ * DocExamples/rwinfo
+ */
+
+
+#pragma D option quiet
+
+struct callinfo {
+ uint64_t ts;
+ uint64_t elapsed;
+ uint64_t calls;
+ size_t maxbytes;
+};
+
+struct callinfo i[string];
+
+syscall::read:entry,
+syscall::write:entry
+/pid == 100551/
+{
+ i[probefunc].ts = timestamp;
+ i[probefunc].calls++;
+ i[probefunc].maxbytes = arg2 > i[probefunc].maxbytes ?
+ arg2 : i[probefunc].maxbytes;
+}
+
+syscall::read:return,
+syscall::write:return
+/i[probefunc].ts != 0 && pid == 100551/
+{
+ i[probefunc].elapsed += timestamp - i[probefunc].ts;
+}
+
+END
+{
+ printf(" calls max bytes elapsed nsecs\n");
+ printf("----- ----- --------- -------------\n");
+ printf(" read %5d %9d %d\n", i["read"].calls,
+ i["read"].maxbytes, i["read"].elapsed);
+ printf(" write %5d %9d %d\n", i["write"].calls,
+ i["write"].maxbytes, i["write"].elapsed);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rwtime.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rwtime.d
new file mode 100644
index 000000000000..2edffb907398
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/rwtime.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 7-1
+ *
+ * SECTION:
+ * DocExamples/rwinfo
+ */
+
+
+syscall::read:entry,
+syscall::write:entry
+/pid == 100551/
+{
+ ts[probefunc] = timestamp;
+}
+
+syscall::read:return,
+syscall::write:return
+/(ts[probefunc] != 0) && (pid == 100551)/
+{
+ printf("%d nsecs\n", timestamp - ts[probefunc]);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/specopen.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/specopen.d
new file mode 100644
index 000000000000..dff3e6227b1b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/specopen.d
@@ -0,0 +1,79 @@
+#!/usr/sbin/dtrace -Fs
+
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 13-1
+ *
+ * SECTION:
+ * DocExamples/specopen
+ */
+
+syscall::open:entry,
+syscall::open64:entry
+{
+ self->spec = speculation();
+ speculate(self->spec);
+
+ printf("%s", stringof(copyinstr(arg0)));
+}
+
+fbt:::
+/self->spec/
+{
+ speculate(self->spec);
+}
+
+syscall::open:return,
+syscall::open64:return
+/self->spec/
+{
+ speculate(self->spec);
+ trace(errno);
+}
+
+syscall::open:return,
+syscall::open64:return
+/self->spec && errno != 0/
+{
+ commit(self->spec);
+ self->spec = 0;
+}
+
+syscall::open:return,
+syscall::open64:return
+/self->spec && errno == 0/
+{
+ discard(self->spec);
+ self->spec = 0;
+}
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/truss.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/truss.d
new file mode 100644
index 000000000000..b79252051ac7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/truss.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc
+ *
+ * SECTION:
+ * DocExamples/truss
+ */
+
+
+
+dtrace:::BEGIN
+{
+ var = 30;
+ self->vaa = 24;
+}
+
+syscall::read:entry
+/pid == 102473/
+{
+ printf("var: %d, self->vaa: %d", var++, self->vaa++);
+}
+
+syscall::write:entry
+/pid == 102473/
+{
+ printf("var: %d, self->vaa: %d", var++, self->vaa++);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/trussrw.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/trussrw.d
new file mode 100644
index 000000000000..9eb9bceda935
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/trussrw.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify doc example 1-2
+ *
+ * SECTION:
+ * DocExamples/trussrw
+ */
+
+
+#pragma D option quiet
+
+syscall::read:entry,
+syscall::write:entry
+/pid == 100551/
+{
+ printf("%s(%d, 0x%x, %4d)", probefunc, arg0, arg1, arg2);
+}
+
+syscall::read:return,
+syscall::write:return
+/pid == 100551/
+{
+ printf("\t\t = %d\n", arg1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/userfunc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/userfunc.d
new file mode 100644
index 000000000000..0d83465d0ae0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/docsExamples/userfunc.d
@@ -0,0 +1,61 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verifying doc example 21-1
+ *
+ * SECTION:
+ * DocExamples/userfunc
+ *
+ */
+
+pid$1::$2:entry
+{
+ self->trace = 1;
+}
+
+pid$1::$2:return
+/self->trace/
+{
+ self->trace = 0;
+}
+
+pid$1:::entry,
+pid$1:::return
+/self->trace/
+{
+}
+
+
+
+
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_AGGREGATION.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_AGGREGATION.d
new file mode 100644
index 000000000000..02b32438a560
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_AGGREGATION.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+#pragma D option strsize=1024
+#pragma D option aggsize=512
+
+BEGIN
+{
+ @["Harding"] = count();
+ @["Hoover"] = count();
+ @["Nixon"] = count();
+ @["Bush"] = count();
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_DBLERROR.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_DBLERROR.d
new file mode 100644
index 000000000000..face4c8c0948
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_DBLERROR.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ trace(*(int *)NULL);
+}
+
+ERROR
+{
+ trace(*(int *)NULL);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_DYNAMIC.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_DYNAMIC.d
new file mode 100644
index 000000000000..f8a90f068f6b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_DYNAMIC.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option strsize=1024
+#pragma D option dynvarsize=512
+
+BEGIN
+{
+ a["Harding"] = 1;
+ a["Hoover"] = 1;
+ a["Nixon"] = 1;
+ a["Bush"] = 1;
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_PRINCIPAL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_PRINCIPAL.d
new file mode 100644
index 000000000000..8389ce02d2cb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_PRINCIPAL.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option strsize=1024
+#pragma D option bufsize=512
+
+BEGIN
+{
+ trace("Harding");
+ trace("Hoover");
+ trace("Nixon");
+ trace("Bush");
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_PRINCIPAL.end.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_PRINCIPAL.end.d
new file mode 100644
index 000000000000..a723019f96a5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_PRINCIPAL.end.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option strsize=1024
+#pragma D option bufsize=512
+
+BEGIN
+{
+ exit(0);
+}
+
+END
+{
+ trace("Harding");
+ trace("Hoover");
+ trace("Nixon");
+ trace("Bush");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_SPEC.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_SPEC.d
new file mode 100644
index 000000000000..8f6df3c0a520
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_SPEC.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option nspec=1
+#pragma D option specsize=32
+#pragma D option strsize=512
+
+BEGIN
+{
+ spec = speculation();
+ speculate(spec);
+ trace("The, SystemTap, The.");
+}
+
+BEGIN
+{
+ commit(spec);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_SPECUNAVAIL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_SPECUNAVAIL.d
new file mode 100644
index 000000000000..1fd39748d3d7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_SPECUNAVAIL.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option nspec=1
+
+BEGIN,
+BEGIN,
+BEGIN,
+BEGIN
+{
+ spec = speculation();
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_STKSTROVERFLOW.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_STKSTROVERFLOW.d
new file mode 100644
index 000000000000..f5d6416bce8f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/drops/drp.DTRACEDROP_STKSTROVERFLOW.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option destructive
+#pragma D option jstackstrsize=1
+#pragma D option quiet
+
+BEGIN
+{
+ system("java -version");
+}
+
+syscall:::entry
+{
+ @[jstack()] = count();
+}
+
+proc:::exit
+/progenyof($pid) && execname == "java"/
+{
+ exit(0);
+}
+
+END
+{
+ printa("\r", @);
+ printf("\n");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/err.D_PDESC_ZERO.InvalidDescription1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/err.D_PDESC_ZERO.InvalidDescription1.d
new file mode 100644
index 000000000000..a0d17676140f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/err.D_PDESC_ZERO.InvalidDescription1.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: An invalid probe description throws a D_PDESC_ZERO error.
+ *
+ * SECTION: Errtags/D_PDESC_ZERO
+ *
+ */
+
+#pragma D option quiet
+
+fbt:bippity:boppity:boo
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.APIVersion.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.APIVersion.d
new file mode 100644
index 000000000000..21564897f120
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.APIVersion.d
@@ -0,0 +1,37 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Assertion:
+ * Use the -V option to printout API version.
+ *
+ * SECTION:
+ * dtrace Utility/-V Option
+ *
+ * NOTES:
+ * Use /usr/sbin/dtrace -V on command line.
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.AddSearchPath.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.AddSearchPath.d
new file mode 100644
index 000000000000..53fe67af7b70
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.AddSearchPath.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * The -I option can be used to search path for #include files when used
+ * in conjunction with the -C option. The specified directory is inserted into
+ * the search path adhead of the default directory list.
+ *
+ * SECTION: dtrace Utility/-C Option;
+ * dtrace Utility/-I Option
+ *
+ * NOTES:
+ * Create a file <filename> and define the variable VALUE in it. Move it a
+ * directory <dirname> different from the current directory. Change the value
+ * of <filename> appropriately in the code below.
+ * Invoke: dtrace -C -I <dirname> -s man.AddSearchPath.d
+ * Verify VALUE.
+ */
+
+
+#pragma D option quiet
+
+#include "filename"
+
+BEGIN
+{
+ printf("Value of VALUE: %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.CoalesceTrace.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.CoalesceTrace.d
new file mode 100644
index 000000000000..77d4b7b7c788
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.CoalesceTrace.d
@@ -0,0 +1,67 @@
+#!/usr/bin/env ksh -p
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * ASSERTION:
+ * Testing -F option with several probes.
+ *
+ * SECTION: dtrace Utility/-F Option
+ *
+ * NOTES: Manually verify using:
+ * "/usr/sbin/dtrace -F -s man.CoalesceTrace.d" on command line.
+ *
+ * Verify that the for the indent characters are -> <- for non-syscall
+ * entry/return pairs (e.g. fbt ones) and => <= for syscall ones and
+ * | for profile ones.
+ *
+ */
+
+BEGIN
+{
+ i = 0;
+ j = 0;
+ k = 0;
+}
+
+syscall::read:
+{
+ printf("syscall: %d\n", i++);
+}
+
+fbt:genunix:read:
+{
+ printf("fbt: %d\n", j++);
+}
+
+profile:::tick-10sec
+{
+ printf("profile: %d\n", k++);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ELFGeneration.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ELFGeneration.d
new file mode 100644
index 000000000000..a30a140e501a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ELFGeneration.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -G option with dtrace utility produces an ELF file containing a
+ * DTrace program. If the filename used with the -s option does ends
+ * with .d, and the -o option is not used, then the output ELF file is
+ * in filename.o
+ *
+ * SECTION: dtrace Utility/-G Option
+ *
+ * NOTES: Use this file as
+ * /usr/sbin/dtrace -G -s man.ELFGeneration.d
+ * Delete the file man.ELFGeneration.d.o
+ *
+ */
+
+BEGIN
+{
+ printf("This test should compile.\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.IncludedFilePath.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.IncludedFilePath.d
new file mode 100644
index 000000000000..f4e4e4e1c51f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.IncludedFilePath.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using the -CH option with dtrace invocation displays the list of
+ * pathnames of included files one per line to the stderr.
+ *
+ * SECTION: dtrace Utility/-C Option;
+ * dtrace Utility/-H Option
+ *
+ * NOTES: Use this file as
+ * /usr/sbin/dtrace -qCH -s man.IncludedFilePath.d
+ *
+ */
+
+#include "stdio.h"
+
+BEGIN
+{
+ printf("This test should compile.\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithFunctions b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithFunctions
new file mode 100644
index 000000000000..e3db1270abbd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithFunctions
@@ -0,0 +1,99 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -l option with -f option.
+ *
+ * SECTION: dtrace Utility/-l Option;
+ * dtrace Utility/-f Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1)
+ * /usr/sbin/dtrace -lf profile
+ * RESULT: Silent output without any probes listed.
+ *
+ * 2)
+ * /usr/sbin/dtrace -lf genunix
+ * RESULT: Silent output without any probes listed.
+ *
+ * 3)
+ * /usr/sbin/dtrace -lf read
+ * RESULT: matching list of probes with function read.
+ *
+ * 4)
+ * /usr/sbin/dtrace -lf genunix:read
+ * RESULT: matching list of probes with module genunix and
+ * function read.
+ *
+ * 5)
+ * /usr/sbin/dtrace -lf sysinfo:genunix:read
+ * RESULT: matching list of probes with provider sysinfo, module
+ * genunix and function read.
+ *
+ * 6)
+ * /usr/sbin/dtrace -lf :genunix::
+ * RESULT: Silent output without any probes listed.
+ *
+ * 7)
+ * /usr/sbin/dtrace -lf ::read:
+ * RESULT: Silent output without any probes listed.
+ *
+ * 8)
+ * /usr/sbin/dtrace -lf profile:::profile-97
+ * RESULT: not a valid probe description.
+ *
+ * 9)
+ * /usr/sbin/dtrace -lf read -lf write
+ * RESULT: matching list of both read and write probes.
+ *
+ * 10)
+ * /usr/sbin/dtrace -lf read -lm fight
+ * RESULT: List of only read probes.
+ *
+ * 11)
+ * /usr/sbin/dtrace -lf fight -lf write
+ * RESULT: List of only write probes.
+ *
+ * 12) Has been automated.
+ * /usr/sbin/dtrace -lf fbt:des:des3_crunch_block:return
+ * RESULT: not a valid probe description.
+ *
+ * 13)
+ * /usr/sbin/dtrace -lf read'{printf("FOUND");}'
+ * RESULT: Silent output without any probes listed.
+ *
+ * 14)
+ * /usr/sbin/dtrace -lf read '{printf("FOUND");}'
+ * RESULT: List of only read probes.
+ *
+ * 15)
+ * /usr/sbin/dtrace -lf read'/probename == "entry"/{printf("FOUND");}'
+ * RESULT: Silent output without any probes listed.
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithIDs b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithIDs
new file mode 100644
index 000000000000..2b46ce34091b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithIDs
@@ -0,0 +1,77 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -l option with -i option.
+ *
+ * SECTION: dtrace Utility/-l Option;
+ * dtrace Utility/-i Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1)
+ * /usr/sbin/dtrace -l
+ * RESULT: List of all available probes.
+ *
+ * 2)
+ * /usr/sbin/dtrace -li 0
+ * RESULT: invalid probe identifier 0.
+ *
+ * 3) automated in tst.InvalidId1.d.ksh
+ * /usr/sbin/dtrace -li -3
+ * RESULT: not a valid id range
+ *
+ * 4)
+ * /usr/sbin/dtrace -li 0-2
+ * RESULT: List of probes including 1 and 2 or error.
+ *
+ * 5) automated in tst.InvalidId2.d.ksh
+ * /usr/sbin/dtrace -li 4-2
+ * RESULT: not a valid id range
+ *
+ * 6) automated in tst.InvalidId3.d.ksh
+ * /usr/sbin/dtrace -li 2-2
+ * RESULT: not a valid id range
+ *
+ * 7)
+ * /usr/sbin/dtrace -li 1 2 3 4
+ * RESULT: only the first probe id is listed and other extraneous
+ * charaters are not considered.
+ *
+ * 8)
+ * /usr/sbin/dtrace -li 0 - 2
+ * RESULT: only the first probe id is listed and other extraneous
+ * charaters are not considered.
+ *
+ * 9)
+ * /usr/sbin/dtrace -li 1 -li 2-4 -li 4 -li 5
+ * RESULT: Probe descriptions listed for all ids specified. Once
+ * for each specification on the command line.
+ *
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithModules b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithModules
new file mode 100644
index 000000000000..167c72a02160
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithModules
@@ -0,0 +1,91 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -l option with -m option.
+ *
+ * SECTION: dtrace Utility/-l Option;
+ * dtrace Utility/-m Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1)
+ * /usr/sbin/dtrace -lm profile
+ * RESULT: Silent output without any probes listed.
+ *
+ * 2)
+ * /usr/sbin/dtrace -lm genunix
+ * RESULT: matching list of probes with module name genunix.
+ *
+ * 3)
+ * /usr/sbin/dtrace -lm vtrace:genunix
+ * RESULT: matching list of probes with provider vtrace and module
+ * genunix.
+ *
+ * 4) automated in tst.InvalidModule1.d.ksh
+ * /usr/sbin/dtrace -lm :genunix::
+ * RESULT: not a valid probe description
+ *
+ * 5) automated in tst.InvalidModule2.d.ksh
+ * /usr/sbin/dtrace -lm profile:::profile-97
+ * RESULT: not a valid probe description.
+ *
+ * 6)
+ * /usr/sbin/dtrace -lm genunix -lm unix
+ * RESULT: matching list of both genunix and unix probes.
+ *
+ * 7)
+ * /usr/sbin/dtrace -lm genunix -lm foounix
+ * RESULT: List of only genunix probes.
+ *
+ * 8)
+ * /usr/sbin/dtrace -lm foounix -lm unix
+ * RESULT: List of only unix probes.
+ *
+ * 9) automated in tst.InvalidModule3.d.ksh
+ * /usr/sbin/dtrace -lm fbt:des:des3_crunch_block:return
+ * RESULT: not a valid probe description.
+ *
+ * 10)
+ * /usr/sbin/dtrace -lm fbt:genunix'{printf("FOUND");}'
+ * RESULT: Silent output without any probes listed.
+ *
+ * 11)
+ * /usr/sbin/dtrace -lm genunix'{printf("FOUND");}'
+ * RESULT: Silent output without any probes listed.
+ *
+ * 12)
+ * /usr/sbin/dtrace -lm unix '{printf("FOUND");}'
+ * RESULT: List of only unix probes.
+ *
+ * 13) automated in tst.InvalidModule4.d.ksh
+ * /usr/sbin/dtrace -lm
+ * unix'/probefunc == "preempt"/{printf("FOUND");}'
+ * RESULT: not a valid probe description.
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithNames b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithNames
new file mode 100644
index 000000000000..aabf1b2dfff6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithNames
@@ -0,0 +1,128 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -l option with -n option.
+ *
+ * SECTION: dtrace Utility/-l Option;
+ * dtrace Utility/-n Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1)
+ * /usr/sbin/dtrace -ln profile
+ * RESULT: Silent output without any probes listed.
+ *
+ * 2)
+ * /usr/sbin/dtrace -ln genunix
+ * RESULT: Silent output without any probes listed.
+ *
+ * 3)
+ * /usr/sbin/dtrace -ln read
+ * RESULT: Silent output without any probes listed.
+ *
+ * 4)
+ * /usr/sbin/dtrace -ln BEGIN
+ * RESULT: list of one probe with name BEGIN.
+ *
+ * 5)
+ * /usr/sbin/dtrace -ln begin
+ * RESULT: Silent output without any probes listed.
+ *
+ * 6)
+ * /usr/sbin/dtrace -ln genunix:read
+ * RESULT: Silent output without any probes listed.
+ *
+ * 7)
+ * /usr/sbin/dtrace -ln genunix:read:
+ * RESULT: matching list of probes with module genunix and
+ * function read.
+ *
+ * 8)
+ * /usr/sbin/dtrace -ln sysinfo:genunix:read
+ * RESULT: Silent output without any probes listed.
+ *
+ * 9)
+ * /usr/sbin/dtrace -ln sysinfo:genunix:read:
+ * RESULT: matching list of probes with provider sysinfo, module
+ * genunix and function read.
+ *
+ * 10) /usr/sbin/dtrace -ln :genunix::
+ * RESULT: matching list of probes with module genunix
+ *
+ * 11)
+ * /usr/sbin/dtrace -ln :genunix:
+ * RESULT: Silent output without any probes listed.
+ *
+ * 12)
+ * /usr/sbin/dtrace -ln ::read:
+ * RESULT: matching list of probes with and function read.
+ *
+ * 13)
+ * /usr/sbin/dtrace -ln profile:::profile-97
+ * RESULT: matching list of probes with provider profile and function
+ * profile-97
+ *
+ * 14)
+ * /usr/sbin/dtrace -ln read: -ln write:
+ * RESULT: matching list of both read and write probes.
+ *
+ * 15)
+ * /usr/sbin/dtrace -ln read: -ln fight:
+ * RESULT: List of only read probes.
+ *
+ * 16)
+ * /usr/sbin/dtrace -ln fight: -ln write:
+ * RESULT: List of only write probes.
+ *
+ * 17)
+ * /usr/sbin/dtrace -ln fbt:des:des3_crunch_block:return
+ * RESULT: Silent output of only the header.
+ *
+ * 18)
+ * /usr/sbin/dtrace -ln read:'{printf("FOUND");}'
+ * RESULT: Silent output without any probes listed.
+ *
+ * 19)
+ * /usr/sbin/dtrace -ln read:entry'{printf("FOUND");}'
+ * RESULT: Silent output without any probes listed.
+ *
+ * 20)
+ * /usr/sbin/dtrace -ln BEGIN'{Printf("FOUND");}'
+ * RESULT: Silent output without any probes listed.
+ *
+ * 21)
+ * /usr/sbin/dtrace -ln BEGIN '{printf("FOUND");}'
+ * RESULT: List of only BEGIN probe.
+ *
+ * 22)
+ * /usr/sbin/dtrace -ln
+ * BEGIN'/probename == "entry"/{printf("FOUND");}'
+ * RESULT: Silent output without any probes listed.
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithProviders b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithProviders
new file mode 100644
index 000000000000..961d409640d7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ListProbesWithProviders
@@ -0,0 +1,82 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -l option with -P option.
+ *
+ * SECTION: dtrace Utility/-l Option;
+ * dtrace Utility/-P Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1)
+ * /usr/sbin/dtrace -lP profile
+ * RESULT: List of only profile probes.
+ *
+ * 2)
+ * /usr/sbin/dtrace -lP foofile
+ * RESULT: Silent output without any probes listed.
+ *
+ * 3) automated in tst.InvalidProvider2.d.ksh
+ * /usr/sbin/dtrace -lP profile:::
+ * RESULT: not a valid probe description
+ *
+ * 4) automated in tst.InvalidProvider1.d.ksh
+ * /usr/sbin/dtrace -lP profile:::profile-97
+ * RESULT: not a valid probe description.
+ *
+ * 5)
+ * /usr/sbin/dtrace -lP profile -lP syscall
+ * RESULT: matching list of both profile and syscall probes.
+ *
+ * 6)
+ * /usr/sbin/dtrace -lP profile -lP foofile
+ * RESULT: List of only profile probes.
+ *
+ * 7)
+ * /usr/sbin/dtrace -lP foofile -lP profile
+ * RESULT: List of only profile probes.
+ *
+ * 8) authomated in tst.InvalidProvider3.d.ksh
+ * /usr/sbin/dtrace -lP fbt:des:des3_crunch_block:return
+ * RESULT: not a valid probe description.
+ *
+ * 9)
+ * /usr/sbin/dtrace -lP profile'{printf("FOUND");}'
+ * RESULT: Silent output without any probes listed.
+ *
+ * 10)
+ * /usr/sbin/dtrace -lP profile '{printf("FOUND");}'
+ * RESULT: List of only profile probes.
+ *
+ * 11) automated in tst.InvalidProvider4.d.ksh
+ * /usr/sbin/dtrace -lP
+ * profile'/probename == "profile-199"/{printf("FOUND");}'
+ * RESULT: not a valid probe description.
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ShowCompilerCode.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ShowCompilerCode.d
new file mode 100644
index 000000000000..556811d2db7c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.ShowCompilerCode.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -S option with dtrace utility shows the intermediate compiler code.
+ *
+ * SECTION: dtrace Utility/-S Option
+ *
+ * NOTES: Use this file as
+ * /usr/sbin/dtrace -qSs man.ShowCompilerCode.d
+ *
+ */
+
+BEGIN
+{
+ printf("This test should compile %d\n", 1);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceFunctions b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceFunctions
new file mode 100644
index 000000000000..4c9c1c5696a3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceFunctions
@@ -0,0 +1,115 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -f option.
+ *
+ * SECTION: dtrace Utility/-f Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1) automated in tst.InvalidTraceFunc1.d.ksh
+ * /usr/sbin/dtrace -f profile
+ * RESULT: invalid probe specifier
+ *
+ * 2) automated in tst.InvalidTraceFunc2.d.ksh
+ * /usr/sbin/dtrace -f genunix
+ * RESULT: invalid probe specifier
+ *
+ * 3)
+ * /usr/sbin/dtrace -f read
+ * RESULT: tracing of matching list of probes with function read.
+ *
+ * 4) automated in tst.InvalidTraceFunc3.d.ksh
+ * /usr/sbin/dtrace -f read:
+ * RESULT: invalid probe specifier
+ *
+ * 5)
+ * /usr/sbin/dtrace -f ::read
+ * RESULT: tracing of matching list of probes with function read.
+ *
+ * 6) automated in tst.InvalidTraceFunc4.d.ksh
+ * /usr/sbin/dtrace -f ::read:
+ * RESULT: invalid probe specifier
+ *
+ * 7)
+ * /usr/sbin/dtrace -f genunix:read
+ * RESULT: tracing of probes with module genunix and function read.
+ *
+ * 8)
+ * /usr/sbin/dtrace -f sysinfo:genunix:read
+ * RESULT: tracing of probes with provider sysinfo, module genunix
+ * and function read.
+ *
+ * 9)
+ * /usr/sbin/dtrace -f sysinfo::read
+ * RESULT: tracing of probes with provider sysinfo and function read.
+ *
+ * 10) automated in tst.InvalidTraceFunc5.d.ksh
+ * /usr/sbin/dtrace -f :genunix::
+ * RESULT: invalid probe specifier
+ *
+ * 11) automated in tst.InvalidTraceFunc6.d.ksh
+ * /usr/sbin/dtrace -f profile:::profile-97
+ * RESULT: invalid probe specifier.
+ *
+ * 12)
+ * /usr/sbin/dtrace -f read -f write
+ * RESULT: tracing of both read and write probes.
+ *
+ * 13)
+ * /usr/sbin/dtrace -f read -f fight
+ * RESULT: Count of matching read probes and invalid probe specifier
+ * for fight
+ *
+ * 14) automated in tst.InvalidTraceFunc8.d.ksh
+ * /usr/sbin/dtrace -f fight -f write
+ * RESULT: invalid probe specifier.
+ *
+ * 15) automated in tst.InvalidTraceFunc7.d.ksh
+ * /usr/sbin/dtrace -f fbt:des:des3_crunch_block:return
+ * RESULT: invalid probe specifier.
+ *
+ * 16)
+ * /usr/sbin/dtrace -f read'{printf("FOUND");}'
+ * RESULT: tracing of probes with function read and with message FOUND
+ *
+ * 17)
+ * /usr/sbin/dtrace -f ::read'{printf("FOUND");}'
+ * RESULT: tracing of probes with function read and with message FOUND
+ *
+ * 18) automated in tst.InvalidTraceFunc9.d.ksh
+ * /usr/sbin/dtrace -f read '{printf("FOUND");}'
+ * RESULT: invalid probe specifier.
+ *
+ * 19)
+ * /usr/sbin/dtrace -f read'/probename == "entry"/{printf("FOUND");}'
+ * RESULT: tracing of probes with function read, name entry and with
+ * message FOUND
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceIDs b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceIDs
new file mode 100644
index 000000000000..d9615b5aadb8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceIDs
@@ -0,0 +1,70 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -l option with -i option.
+ *
+ * SECTION: dtrace Utility/-l Option;
+ * dtrace Utility/-i Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1) automated in tst.InvalidTraceID1.d.ksh
+ * /usr/sbin/dtrace -i 0
+ * RESULT: invalid probe specifier.
+ *
+ * 2) automated in tst.InvalidTraceID2.d.ksh
+ * /usr/sbin/dtrace -i -3
+ * RESULT: not a valid id range
+ *
+ * 3) automated in tst.InvalidTraceID3.d.ksh
+ * /usr/sbin/dtrace -i 0-2
+ * RESULT: not a valid id range
+ *
+ * 4) automated in tst.InvalidTraceID4.d.ksh
+ * /usr/sbin/dtrace -i 4-2
+ * RESULT: not a valid id range
+ *
+ * 5) automated in tst.InvalidTraceID5.d.ksh
+ * /usr/sbin/dtrace -i 2-2
+ * RESULT: not a valid id range
+ *
+ * 6) automated in tst.InvalidTraceID6.d.ksh
+ * /usr/sbin/dtrace -i 1 2 3 4
+ * RESULT: invalid probe specifier.
+ *
+ * 7) automated in tst.InvalidTraceID7.d.ksh
+ * /usr/sbin/dtrace -i 0 - 2
+ * RESULT: invalid probe specifier.
+ *
+ * 8)
+ * /usr/sbin/dtrace -i 1 -i 2-4 -i 4 -i 5
+ * RESULT: Only the BEGIN probe is traced and the others are not.
+ *
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceModule b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceModule
new file mode 100644
index 000000000000..9c4401ead040
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceModule
@@ -0,0 +1,114 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Tracing a module using the -m option.
+ *
+ * SECTION: dtrace Utility/-m Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1) automated in tst.InvalidTraceModule1.d.ksh
+ * /usr/sbin/dtrace -m profile
+ * RESULT: invalid probe specifier
+ *
+ * 2)
+ * /usr/sbin/dtrace -m genunix
+ * RESULT: trace of all probes with module genunix.
+ *
+ * 3)
+ * /usr/sbin/dtrace -m vtrace:genunix
+ * RESULT: trace of probes with provider vtrace and module genunix.
+ *
+ * 4) automated in tst.InvalidTraceModule2.d.ksh
+ * /usr/sbin/dtrace -m :genunix::
+ * RESULT: invalid probe specifier
+ *
+ * 5)
+ * /usr/sbin/dtrace -m :genunix
+ * RESULT: trace of all probes with module genunix.
+ *
+ * 6) automated in tst.InvalidTraceModule3.d.ksh
+ * /usr/sbin/dtrace -m genunix::
+ * RESULT: invalid probe specifier
+ *
+ * 7) automated in tst.InvalidTraceModule4.d.ksh
+ * /usr/sbin/dtrace -m profile:::profile-97
+ * RESULT: not a valid probe description.
+ *
+ * 8)
+ * /usr/sbin/dtrace -m genunix -m unix
+ * RESULT: tracing of both genunix and unix probes.
+ *
+ * 9)
+ * /usr/sbin/dtrace -m genunix -m foounix
+ * RESULT: Number of probes matching the description genunix
+ * and an invalid probe specifier for foounix.
+ *
+ * 10) automated in tst.InvalidTraceModule5.d.ksh
+ * /usr/sbin/dtrace -m foounix -m unix
+ * RESULT: invalid probe specifier for foounix.
+ *
+ * 11) automated in tst.InvalidTraceModule6.d.ksh
+ * /usr/sbin/dtrace -m fbt:des:des3_crunch_block:return
+ * RESULT: invalid probe description.
+ *
+ * 12)
+ * /usr/sbin/dtrace -m fbt:genunix'{printf("FOUND");}'
+ * RESULT: tracing of all the probes matching provider fbt and module
+ * genunix.
+ *
+ * 13)
+ * /usr/sbin/dtrace -m genunix'{printf("FOUND");}'
+ * RESULT: tracing of all the probes matching module genunix with
+ * message FOUND
+ *
+ * 14)
+ * /usr/sbin/dtrace -m :genunix'{printf("FOUND");}'
+ * RESULT: tracing of all the probes matching module genunix with
+ * message FOUND
+ *
+ * 15) automated in tst.InvalidTraceModule7.d.ksh
+ * /usr/sbin/dtrace -m genunix::'{printf("FOUND");}'
+ * RESULT: invalid probe specifier.
+ *
+ * 16) automated in tst.InvalidTraceModule8.d.ksh
+ * /usr/sbin/dtrace -m genunix:'{printf("FOUND");}'
+ * RESULT: invalid probe specifier.
+ *
+ * 17)
+ * /usr/sbin/dtrace -m unix '{printf("FOUND");}'
+ * RESULT: invalid probe specifier.
+ *
+ * 18)
+ * /usr/sbin/dtrace -m
+ * unix'/probefunc == "preempt"/{printf("FOUND");}'
+ * RESULT: tracing of all the probes matching module genunix,
+ * probe function preempt with message FOUND.
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceNames b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceNames
new file mode 100644
index 000000000000..c3e75554e025
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceNames
@@ -0,0 +1,129 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -n option.
+ *
+ * SECTION: dtrace Utility/-n Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1) automated in tst.InvalidTraceName1.d.ksh
+ * /usr/sbin/dtrace -n profile
+ * RESULT: invalid probe specifier
+ *
+ * 2) automated in tst.InvalidTraceName2.d.ksh
+ * /usr/sbin/dtrace -n genunix
+ * RESULT: invalid probe specifier
+ *
+ * 3) automated in tst.InvalidTraceName3.d.ksh
+ * /usr/sbin/dtrace -n read
+ * RESULT: invalid probe specifier
+ *
+ * 4)
+ * /usr/sbin/dtrace -n BEGIN
+ * RESULT: trace of one probe with name BEGIN.
+ *
+ * 5) automated in tst.InvalidTraceName4.d.ksh
+ * /usr/sbin/dtrace -n begin
+ * RESULT: invalid probe specifier
+ *
+ * 6) automated in tst.InvalidTraceName5.d.ksh
+ * /usr/sbin/dtrace -n genunix:read
+ * RESULT: invalid probe specifier
+ *
+ * 7)
+ * /usr/sbin/dtrace -n genunix:read:
+ * RESULT: trace of probes with module genunix and function read.
+ *
+ * 8) automated in tst.InvalidTraceName6.d.ksh
+ * /usr/sbin/dtrace -n sysinfo:genunix:read
+ * RESULT: invalid probe specifier
+ *
+ * 9)
+ * /usr/sbin/dtrace -n sysinfo:genunix:read:
+ * RESULT: tracing of probes with provider sysinfo, module genunix
+ * and function read.
+ *
+ * 10)
+ * /usr/sbin/dtrace -n :genunix::
+ * RESULT: tracing of probes with module genunix
+ *
+ * 11) automated in tst.InvalidTraceName7.d.ksh
+ * /usr/sbin/dtrace -n :genunix:
+ * RESULT: invalid probe specifier
+ *
+ * 12)
+ * /usr/sbin/dtrace -n ::read:
+ * RESULT: tracing of probes with function read.
+ *
+ * 13)
+ * /usr/sbin/dtrace -n profile:::profile-97
+ * RESULT: tracing of probes with provider profile and name
+ * profile-97
+ *
+ * 14)
+ * /usr/sbin/dtrace -n read: -n write:
+ * RESULT: tracing of both read and write probes.
+ *
+ * 15)
+ * /usr/sbin/dtrace -n read: -n fight:
+ * RESULT: Count of mathching read probes and invalid probe specifier
+ * for fight:
+ *
+ * 16) automated in tst.InvalidTraceName8.d.ksh
+ * /usr/sbin/dtrace -n fight: -n write:
+ * RESULT: invalid probe specifier
+ *
+ * 17)
+ * /usr/sbin/dtrace -n fbt:des:des3_crunch_block:return
+ * RESULT: trace of the specified probe.
+ *
+ * 18)
+ * /usr/sbin/dtrace -n read:'{printf("FOUND");}'
+ * RESULT: Trace of all the probes with module read and a message
+ * saying FOUND.
+ *
+ * 19)
+ * /usr/sbin/dtrace -n read:entry'{printf("FOUND");}'
+ * RESULT: Trace of all the probes with module read, name entry.Output
+ * of a message saying FOUND.
+ *
+ * 20)
+ * /usr/sbin/dtrace -n BEGIN'{printf("FOUND");}'
+ * RESULT: Trace of the BEGIN probe with the message FOUND.
+ *
+ * 21) automated in tst.InvalidTraceName9.d.ksh
+ * /usr/sbin/dtrace -n BEGIN '{printf("FOUND");}'
+ * RESULT: invalid probe specifier
+ *
+ * 22)
+ * /usr/sbin/dtrace -n BEGIN'/probename == "entry"/{printf("FOUND");}'
+ * RESULT: Tracing of BEGIN function but no message FOUND.
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceProvider b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceProvider
new file mode 100644
index 000000000000..f52f395c41fe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.TraceProvider
@@ -0,0 +1,83 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -P option to trace all the probes provided by the particular
+ * provider.
+ *
+ * SECTION: dtrace Utility/-P Option
+ *
+ * NOTES: Manually check:
+ *
+ * 1)
+ * /usr/sbin/dtrace -P profile
+ * RESULT: Trace of all profile probes.
+ *
+ * 2) automated in tst.InvalidTraceProvider1.d.ksh
+ * /usr/sbin/dtrace -P foofile
+ * RESULT: invalid probe specifier
+ *
+ * 3) automated in tst.InvalidTraceProvider2.d.ksh
+ * /usr/sbin/dtrace -P profile:::
+ * RESULT: invalid probe specifier
+ *
+ * 4) automated in tst.InvalidTraceProvider3.d.ksh
+ * /usr/sbin/dtrace -P profile:::profile-97
+ * RESULT: invalid probe specifier
+ *
+ * 5)
+ * /usr/sbin/dtrace -P profile -P syscall
+ * RESULT: matching traces of both profile and syscall probes.
+ *
+ * 6)
+ * /usr/sbin/dtrace -P profile -P foofile
+ * RESULT: Count of profile probes that matched and invalid
+ * probe specifier for foofile and no tracing.
+ *
+ * 7) automated in tst.InvalidTraceProvider4.d.ksh
+ * /usr/sbin/dtrace -P fbt:des:des3_crunch_block:return
+ * RESULT: invalid probe specifier
+ *
+ * 8)
+ * /usr/sbin/dtrace -P profile'{printf("FOUND");}'
+ * RESULT: Traces of all the matching profile probes with the
+ * FOUND message.
+ *
+ * 9) automated in tst.InvalidTraceProvider5.d.ksh
+ * /usr/sbin/dtrace -P profile '{printf("FOUND");}'
+ * RESULT: invalid probe specifier
+ *
+ * 10)
+ * /usr/sbin/dtrace -P
+ * profile'/probename == "profile-199"/{printf("FOUND");}'
+ * RESULT: Traces of the matching profile probe with the
+ * FOUND message.
+ *
+ *
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.VerboseStabilityReport.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.VerboseStabilityReport.d
new file mode 100644
index 000000000000..23742284cb98
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/man.VerboseStabilityReport.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using -v option with dtrace utility produces a program stability report
+ * showing the minimum interface stability and dependency level for
+ * the specified D programs.
+ *
+ * SECTION: dtrace Utility/-s Option;
+ * dtrace Utility/-v Option
+ *
+ * NOTES: Use this file as
+ * /usr/sbin/dtrace -vs man.VerboseStabilityReport.d
+ *
+ */
+
+BEGIN
+{
+ printf("This test should compile: %d\n", 2);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.AddSearchPath.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.AddSearchPath.d.ksh
new file mode 100644
index 000000000000..b36f1e4c181d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.AddSearchPath.d.ksh
@@ -0,0 +1,82 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -I option can be used to search path for #include files when used
+# in conjunction with the -C option. The specified directory is inserted into
+# the search path adhead of the default directory list.
+#
+# SECTION: dtrace Utility/-C Option
+# SECTION: dtrace Utility/-I Option
+#
+##
+
+script()
+{
+ $dtrace -C -I /tmp -s /dev/stdin <<EOF
+ #pragma D option quiet
+#include "test.h"
+
+ BEGIN
+ /1520 != VALUE/
+ {
+ printf("VALUE: %d, Test should fail\n", VALUE);
+ exit(1);
+ }
+
+ BEGIN
+ /1520 == VALUE/
+ {
+ printf("VALUE: %d, Test should pass\n", VALUE);
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+tempfile=/tmp/test.h
+echo "#define VALUE 1520" > $tempfile
+
+dtrace=$1
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+ exit $status
+fi
+
+/bin/rm -f $tempfile
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeGiga.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeGiga.d.ksh
new file mode 100644
index 000000000000..2f0c56739426
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeGiga.d.ksh
@@ -0,0 +1,45 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# ASSERTION:
+# The trace buffer size can include any of the size suffixes k, m, g or t
+#
+# SECTION: dtrace Utility/-b Option
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -b 1g -b 2g -e
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeKilo.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeKilo.d.ksh
new file mode 100644
index 000000000000..d969b481d33f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeKilo.d.ksh
@@ -0,0 +1,45 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# ASSERTION:
+# The trace buffer size can include any of the size suffixes k, m, g or t
+#
+# SECTION: dtrace Utility/-b Option
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -b 1k -b 2k -e
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeMega.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeMega.d.ksh
new file mode 100644
index 000000000000..a08327a30a51
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeMega.d.ksh
@@ -0,0 +1,45 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# ASSERTION:
+# The trace buffer size can include any of the size suffixes k, m, g or t
+#
+# SECTION: dtrace Utility/-b Option
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -b 1m -b 2m -e
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeTera.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeTera.d.ksh
new file mode 100644
index 000000000000..00f2c6622f3d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.BufsizeTera.d.ksh
@@ -0,0 +1,45 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# ASSERTION:
+# The trace buffer size can include any of the size suffixes k, m, g or t
+#
+# SECTION: dtrace Utility/-b Option
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -b 1t -b 2t -e
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DataModel32.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DataModel32.d.ksh
new file mode 100644
index 000000000000..e4ef38db431e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DataModel32.d.ksh
@@ -0,0 +1,73 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# If the -32 option is specified, dtrace will force the D compiler to
+# compile a program using the 32-bit data model.
+#
+# SECTION: dtrace Utility/-32 Option
+#
+##
+
+script()
+{
+ $dtrace -32 -s /dev/stdin <<EOF
+ BEGIN
+ /4 != sizeof(long)/
+ {
+ printf("Not targeted for 32 bit machine\n");
+ exit(1);
+ }
+
+ BEGIN
+ /4 == sizeof(long)/
+ {
+ printf("Targeted for 32 bit machine\n");
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DataModel64.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DataModel64.d.ksh
new file mode 100644
index 000000000000..8a9de0c87c73
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DataModel64.d.ksh
@@ -0,0 +1,74 @@
+#!/bin/ksh
+
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# If the -64 option is specified, dtrace will force the D compiler to
+# compile a program using the 64-bit data model.
+#
+# SECTION: dtrace Utility/-64 Option
+#
+##
+
+script()
+{
+ $dtrace -64 -s /dev/stdin <<EOF
+ BEGIN
+ /8 != sizeof(long)/
+ {
+ printf("Not targeted for 64 bit machine\n");
+ exit(1);
+ }
+
+ BEGIN
+ /8 == sizeof(long)/
+ {
+ printf("Targeted for 64 bit machine\n");
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DefineNameWithCPP.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DefineNameWithCPP.d.ksh
new file mode 100644
index 000000000000..9be2b291d43f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DefineNameWithCPP.d.ksh
@@ -0,0 +1,68 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -D option can be used to define a name when used in conjunction
+# with the -C option.
+#
+# SECTION: dtrace Utility/-C Option;
+# dtrace Utility/-D Option
+#
+##
+
+script()
+{
+ $dtrace -C -D VALUE=40 -s /dev/stdin <<EOF
+ #pragma D option quiet
+
+ BEGIN
+ {
+ printf("Value of VALUE: %d\n", VALUE);
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DefineNameWithCPP.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DefineNameWithCPP.d.ksh.out
new file mode 100644
index 000000000000..5f91ad16d56b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DefineNameWithCPP.d.ksh.out
@@ -0,0 +1,2 @@
+Value of VALUE: 40
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithFunction.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithFunction.d.ksh
new file mode 100644
index 000000000000..8e9e3497a0da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithFunction.d.ksh
@@ -0,0 +1,69 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -w option can be used to permit destructive actions in D programs.
+#
+# SECTION: dtrace Utility/-w Option;
+# dtrace Utility/-f Option
+#
+##
+
+
+reader()
+{
+ while true
+ do
+ sleep 0.1
+ cat /COPYRIGHT > /dev/null
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+reader &
+child=$!
+
+$dtrace -qwf read'{chill(15); printf("Done chilling"); exit(0);}'
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+kill $child
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithFunction.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithFunction.d.ksh.out
new file mode 100644
index 000000000000..8975980fdc0b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithFunction.d.ksh.out
@@ -0,0 +1 @@
+Done chilling
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithID.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithID.d.ksh
new file mode 100644
index 000000000000..6d3913f852a9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithID.d.ksh
@@ -0,0 +1,54 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -w option can be used to permit destructive actions in D programs.
+#
+# SECTION: dtrace Utility/-w Option;
+# dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qwi 1'{chill(15); printf("Done chilling"); exit(0);}'
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithID.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithID.d.ksh.out
new file mode 100644
index 000000000000..8975980fdc0b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithID.d.ksh.out
@@ -0,0 +1 @@
+Done chilling
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithModule.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithModule.d.ksh
new file mode 100644
index 000000000000..8ab32fdb40ee
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithModule.d.ksh
@@ -0,0 +1,54 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -w option can be used to permit destructive actions in D programs.
+#
+# SECTION: dtrace Utility/-w Option;
+# dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qwm kernel'{chill(15); printf("Done chilling"); exit(0);}'
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithModule.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithModule.d.ksh.out
new file mode 100644
index 000000000000..8975980fdc0b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithModule.d.ksh.out
@@ -0,0 +1 @@
+Done chilling
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithName.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithName.d.ksh
new file mode 100644
index 000000000000..b21903fb5734
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithName.d.ksh
@@ -0,0 +1,54 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -w option can be used to permit destructive actions in D programs.
+#
+# SECTION: dtrace Utility/-w Option;
+# dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qwn BEGIN'{chill(15); printf("Done chilling"); exit(0);}'
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithName.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithName.d.ksh.out
new file mode 100644
index 000000000000..8975980fdc0b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithName.d.ksh.out
@@ -0,0 +1 @@
+Done chilling
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithProvider.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithProvider.d.ksh
new file mode 100644
index 000000000000..09dafecb9c90
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithProvider.d.ksh
@@ -0,0 +1,54 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -w option can be used to permit destructive actions in D programs.
+#
+# SECTION: dtrace Utility/-w Option;
+# dtrace Utility/-P Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qwP syscall'{chill(15); printf("Done chilling"); exit(0);}'
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithProvider.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithProvider.d.ksh.out
new file mode 100644
index 000000000000..8975980fdc0b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithProvider.d.ksh.out
@@ -0,0 +1 @@
+Done chilling
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithoutW.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithoutW.d.ksh
new file mode 100644
index 000000000000..9f051b4cbd41
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.DestructWithoutW.d.ksh
@@ -0,0 +1,55 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Destructive actions will not compile or are not enabled without the
+# -w option in D programs.
+#
+# SECTION: dtrace Utility/-w Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qP syscall'{chill(15); printf("Done chilling"); exit(0);}'
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ELFGenerationOut.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ELFGenerationOut.d.ksh
new file mode 100644
index 000000000000..a4f4670c02ce
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ELFGenerationOut.d.ksh
@@ -0,0 +1,73 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Using -G option with dtrace utility produces an ELF file containing a
+# DTrace program. If the filename used with the -s option does not end
+# with .d, and the -o option is not used, then the output ELF file is
+# in d.out.
+#
+# SECTION: dtrace Utility/-G Option
+#
+##
+
+script()
+{
+ $dtrace -G -s /dev/stdin <<EOF
+ BEGIN
+ {
+ printf("This test should compile.\n");
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+ exit $status
+fi
+
+if [ ! -a "d.out" ]; then
+ echo $tst: file not generated
+ exit 1
+fi
+
+/bin/rm -f "d.out"
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ELFGenerationWithO.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ELFGenerationWithO.d.ksh
new file mode 100644
index 000000000000..503dd50e0891
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ELFGenerationWithO.d.ksh
@@ -0,0 +1,74 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Using -G option with dtrace utility produces an ELF file containing a
+# DTrace program. The output file can be named as required using the
+# -o option in conjunction with the -G option.
+#
+# SECTION: dtrace Utility/-G Option;
+# dtrace Utility/-o Option
+#
+##
+
+script()
+{
+ $dtrace -G -o outputFile -s /dev/stdin <<EOF
+ BEGIN
+ {
+ printf("This test should compile.\n");
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+ exit $status
+fi
+
+if [ ! -a "outputFile" ]; then
+ echo $tst: file not generated
+ exit 1
+fi
+
+/bin/rm -f "outputFile"
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExitStatus1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExitStatus1.d.ksh
new file mode 100644
index 000000000000..70a9f498fc5e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExitStatus1.d.ksh
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# When a fatal error occurs such that the program compilation fails or the
+# specified request cannot be satisfied, an exit status of 1 is returned.
+#
+#
+# SECTION: dtrace Utility/Exit Status
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -s wassup
+status=$?
+
+if [ "$status" -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExitStatus2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExitStatus2.d.ksh
new file mode 100644
index 000000000000..a058d3a35b52
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExitStatus2.d.ksh
@@ -0,0 +1,55 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# When invalid command line options or arguments are specified an exit status
+# of 2 is returned.
+#
+# SECTION: dtrace Utility/Exit Status
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -9
+status=$?
+
+if [ "$status" -ne 2 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExtraneousProbeIds.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExtraneousProbeIds.d.ksh
new file mode 100644
index 000000000000..090fc4a069a4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ExtraneousProbeIds.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -i option with extraneous probe identifiers.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i 12 10 -i 23
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidFuncName1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidFuncName1.d.ksh
new file mode 100644
index 000000000000..c28c782374b2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidFuncName1.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f BEGIN
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidFuncName2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidFuncName2.d.ksh
new file mode 100644
index 000000000000..d431579db6c5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidFuncName2.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f 4.56
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId1.d.ksh
new file mode 100644
index 000000000000..814b88dd8188
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId1.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -li option can be used to list the probes from their ids. An id of
+# negative integer is invalid
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -li -3
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId2.d.ksh
new file mode 100644
index 000000000000..f9f440786669
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId2.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -li option can be used to list the probes from their ids. A
+# non-increasing range will not list any probes.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -li 4-2
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId3.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId3.d.ksh
new file mode 100644
index 000000000000..efb03ae2f5d5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidId3.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -li option can be used to list the probes from their ids. A
+# non-increasing range will not list any probes.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -li 2-2
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule1.d.ksh
new file mode 100644
index 000000000000..a896ff3d1539
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule1.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -lm option can be used to list the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -lm :genunix::
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule2.d.ksh
new file mode 100644
index 000000000000..820cc64dfbef
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule2.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -lm option can be used to list the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -lm profile:::profile-97
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule3.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule3.d.ksh
new file mode 100644
index 000000000000..b56e6c376fd3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule3.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -lm option can be used to list the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -lm fbt:des:des3_crunch_block:return
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule4.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule4.d.ksh
new file mode 100644
index 000000000000..0ef9d9563fdb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidModule4.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -lm option can be used to list the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -lm unix'/probefunc == "preempt"/{printf("FOUND");}'
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProbeIdentifier.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProbeIdentifier.d.ksh
new file mode 100644
index 000000000000..66e0e1a514ea
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProbeIdentifier.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -i option with invalid probe identifier.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i i23
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider1.d.ksh
new file mode 100644
index 000000000000..327e2d01bc04
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider1.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -lP option can be used to list the probes from their provider names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-P Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -lP profile:::profile-97
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider2.d.ksh
new file mode 100644
index 000000000000..22624495c699
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider2.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -lP option can be used to list the probes from their provider names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-P Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -lP profile:::
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider3.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider3.d.ksh
new file mode 100644
index 000000000000..775b327c469d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider3.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -lP option can be used to list the probes from their provider names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-P Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -lP fbt:des:des3_crunch_block:return
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider4.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider4.d.ksh
new file mode 100644
index 000000000000..04343f3e5425
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidProvider4.d.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -lP option can be used to list the probes from their provider names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-l Option;
+# dtrace Utility/-P Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -lP profile'/probename == "profile-199"/{printf("FOUND");}'
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc1.d.ksh
new file mode 100644
index 000000000000..1395f3be807f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc1.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f profile
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc2.d.ksh
new file mode 100644
index 000000000000..4231e5c7057f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc2.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f genunix
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc3.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc3.d.ksh
new file mode 100644
index 000000000000..3c5b17831eb0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc3.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f read:
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc4.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc4.d.ksh
new file mode 100644
index 000000000000..bb8460d06181
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc4.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f ::read:
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc5.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc5.d.ksh
new file mode 100644
index 000000000000..544667618726
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc5.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f :genunix::
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc6.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc6.d.ksh
new file mode 100644
index 000000000000..645e6d9f3f05
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc6.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f profile:::profile-97
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc7.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc7.d.ksh
new file mode 100644
index 000000000000..a93d5c4b0772
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc7.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f fbt:des:des3_crunch_block:return
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc8.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc8.d.ksh
new file mode 100644
index 000000000000..22ab3b16bc46
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc8.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f fight -f write
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc9.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc9.d.ksh
new file mode 100644
index 000000000000..2af27a325aa4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceFunc9.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -f option with an invalid function name.
+#
+# SECTION: dtrace Utility/-f Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -f read '{printf("FOUND");}'
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID1.d.ksh
new file mode 100644
index 000000000000..46096d216b6b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID1.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -i option can be used to enable the trace of probes from their ids. A
+# non-increasing range will not list any probes.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i 0
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID2.d.ksh
new file mode 100644
index 000000000000..f406ce005948
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID2.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -i option can be used to enable the trace of probes from their ids. A
+# non-increasing range will not list any probes.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i -3
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID3.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID3.d.ksh
new file mode 100644
index 000000000000..fc2a24d57051
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID3.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -i option can be used to enable the trace of probes from their ids. A
+# non-increasing range will not list any probes.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i 0-2
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID4.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID4.d.ksh
new file mode 100644
index 000000000000..5fd6fd6c52b4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID4.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -i option can be used to enable the trace of probes from their ids. A
+# non-increasing range will not list any probes.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i 4-2
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID5.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID5.d.ksh
new file mode 100644
index 000000000000..0ac46dbbad01
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID5.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -i option can be used to enable the trace of probes from their ids. A
+# non-increasing range will not list any probes.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i 2-2
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID6.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID6.d.ksh
new file mode 100644
index 000000000000..778d485ad21d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID6.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -i option can be used to enable the trace of probes from their ids. A
+# non-increasing range will not list any probes.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i 1 2 3 4
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID7.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID7.d.ksh
new file mode 100644
index 000000000000..8a0f2d4e5394
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceID7.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -i option can be used to enable the trace of probes from their ids. A
+# non-increasing range will not list any probes.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i 0 - 2
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule1.d.ksh
new file mode 100644
index 000000000000..56dee0dd30af
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule1.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -m option can be used to enable the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -m profile
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule2.d.ksh
new file mode 100644
index 000000000000..a508fe1030e2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule2.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -m option can be used to enable the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -m :genunix::
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule3.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule3.d.ksh
new file mode 100644
index 000000000000..599ce93e1d6d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule3.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -m option can be used to enable the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -m genunix::
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule4.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule4.d.ksh
new file mode 100644
index 000000000000..e0e87861f732
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule4.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -m option can be used to enable the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -m profile:::profile-97
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule5.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule5.d.ksh
new file mode 100644
index 000000000000..858306021cc9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule5.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -m option can be used to enable the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -m foounix -m unix
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule6.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule6.d.ksh
new file mode 100644
index 000000000000..6125fb0f309f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule6.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -m option can be used to enable the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -m fbt:des:des3_crunch_block:return
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule7.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule7.d.ksh
new file mode 100644
index 000000000000..e689627b8c81
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule7.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -m option can be used to enable the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -m genunix::'{printf("FOUND");}'
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule8.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule8.d.ksh
new file mode 100644
index 000000000000..692821b56159
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceModule8.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -m option can be used to enable the probes from their module names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -m genunix:'{printf("FOUND");}'
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName1.d.ksh
new file mode 100644
index 000000000000..43c61af3e359
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName1.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -n option can be used to enable the trace of probes from their names.
+#
+# SECTION: dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n profile
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName2.d.ksh
new file mode 100644
index 000000000000..70a52188021c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName2.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -n option can be used to enable the trace of probes from their names.
+#
+# SECTION: dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n genunix
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName3.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName3.d.ksh
new file mode 100644
index 000000000000..efb5ad088cf1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName3.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -n option can be used to enable the trace of probes from their names.
+#
+# SECTION: dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n not_a_valid_probe
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName4.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName4.d.ksh
new file mode 100644
index 000000000000..04845b997117
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName4.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -n option can be used to enable the trace of probes from their names.
+#
+# SECTION: dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n begin
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName5.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName5.d.ksh
new file mode 100644
index 000000000000..df17231fc2de
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName5.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -n option can be used to enable the trace of probes from their names.
+#
+# SECTION: dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n genunix:read
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName6.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName6.d.ksh
new file mode 100644
index 000000000000..10f13cb3188b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName6.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -n option can be used to enable the trace of probes from their names.
+#
+# SECTION: dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n sysinfo:genunix:read
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName7.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName7.d.ksh
new file mode 100644
index 000000000000..b22561fa0e19
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName7.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -n option can be used to enable the trace of probes from their names.
+#
+# SECTION: dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n :genunix:
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName8.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName8.d.ksh
new file mode 100644
index 000000000000..f66055e242fe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName8.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -n option can be used to enable the trace of probes from their names.
+#
+# SECTION: dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n fight: -n write:
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName9.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName9.d.ksh
new file mode 100644
index 000000000000..a4239ff90375
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceName9.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -n option can be used to enable the trace of probes from their names.
+#
+# SECTION: dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n BEGIN '{printf("FOUND");}'
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider1.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider1.d.ksh
new file mode 100644
index 000000000000..0a792c595b15
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider1.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -P option can be used to list the probes from their provider names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-P Option;
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -P foofile
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider2.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider2.d.ksh
new file mode 100644
index 000000000000..1763142b7a8b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider2.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -P option can be used to list the probes from their provider names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-P Option;
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -P profile:::
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider3.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider3.d.ksh
new file mode 100644
index 000000000000..a8549329cdca
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider3.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -P option can be used to list the probes from their provider names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-P Option;
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -P profile:::profile-97
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider4.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider4.d.ksh
new file mode 100644
index 000000000000..f8a1359c5458
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider4.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -P option can be used to list the probes from their provider names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-P Option;
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -P fbt:des:des3_crunch_block:return
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider5.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider5.d.ksh
new file mode 100644
index 000000000000..cec4297c0328
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.InvalidTraceProvider5.d.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -P option can be used to list the probes from their provider names.
+# Invalid module names result in error.
+#
+# SECTION: dtrace Utility/-P Option;
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -P profile '{printf("FOUND");}'
+
+status=$?
+
+echo $status
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.MultipleInvalidProbeId.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.MultipleInvalidProbeId.d.ksh
new file mode 100644
index 000000000000..8f2ceefd9211
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.MultipleInvalidProbeId.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -i option with multiple valid and invalid probe identifiers.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i 12 -i 10 -i 0
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.PreprocessorStatement.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.PreprocessorStatement.d.ksh
new file mode 100644
index 000000000000..e4d093e4fc22
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.PreprocessorStatement.d.ksh
@@ -0,0 +1,69 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -C option is used to run the C preprocessor over D programs before
+# compiling them. The -H option used in conjuction with the -C option
+# lists the pathnames of the included files to STDERR.
+#
+# SECTION: dtrace Utility/-C Option;
+# dtrace Utility/-H Option
+#
+##
+
+script()
+{
+ $dtrace -CH -s /dev/stdin <<EOF
+
+
+ BEGIN
+ {
+ printf("This test should compile\n");
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.QuietMode.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.QuietMode.d.ksh
new file mode 100644
index 000000000000..4bfbf767d677
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.QuietMode.d.ksh
@@ -0,0 +1,65 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Using the -q option suppresses the dtrace messages and prints only the
+# data traced by trace() and printf() to stdout.
+#
+# SECTION: dtrace Utility/-q Option
+#
+##
+
+script()
+{
+ $dtrace -q -s /dev/stdin <<EOF
+
+ BEGIN
+ {
+ printf("I am the only one.");
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.QuietMode.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.QuietMode.d.ksh.out
new file mode 100644
index 000000000000..20e31b50ec48
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.QuietMode.d.ksh.out
@@ -0,0 +1 @@
+I am the only one.
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.TestCompile.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.TestCompile.d.ksh
new file mode 100644
index 000000000000..16cd05f95b4c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.TestCompile.d.ksh
@@ -0,0 +1,67 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Using the -e option exits after compiling any requests but before
+# enabling probes.
+#
+# SECTION: dtrace Utility/-e Option
+#
+##
+
+script()
+{
+ $dtrace -e -s /dev/stdin <<EOF
+ #pragma D option quiet
+ BEGIN
+ {
+ i = 100;
+ printf("Value of i: %d\n", i);
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.TestCompile.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.TestCompile.d.ksh.out
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.TestCompile.d.ksh.out
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.UnDefineNameWithCPP.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.UnDefineNameWithCPP.d.ksh
new file mode 100644
index 000000000000..4c1eb507d5eb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.UnDefineNameWithCPP.d.ksh
@@ -0,0 +1,71 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -D option can be used to define a name when used in conjunction
+# with the -C option. The -U option can be used to undefine a name in
+# conjunction with the -C option.
+#
+# SECTION: dtrace Utility/-C Option;
+# dtrace Utility/-D Option;
+# dtrace Utility/-U Option
+#
+##
+
+script()
+{
+ $dtrace -C -D VALUE=40 -U VALUE -s /dev/stdin <<EOF
+ #pragma D option quiet
+
+ BEGIN
+ {
+ printf("Value of VALUE: %d\n", VALUE);
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroFunctionProbes.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroFunctionProbes.d.ksh
new file mode 100644
index 000000000000..cdd4c43264d5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroFunctionProbes.d.ksh
@@ -0,0 +1,72 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -Z option can be used to permit descriptions that match
+# zero probes.
+#
+# SECTION: dtrace Utility/-Z Option;
+# dtrace Utility/-f Option
+#
+##
+
+
+reader()
+{
+ while true
+ do
+ sleep 0.1
+ cat /COPYRIGHT > /dev/null
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+reader &
+child=$!
+
+$dtrace -qZf wassup'{printf("Iamkool");}' \
+-qf read'{printf("I am done"); exit(0);}'
+
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+kill $child
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroFunctionProbes.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroFunctionProbes.d.ksh.out
new file mode 100644
index 000000000000..0f2e1aacd09e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroFunctionProbes.d.ksh.out
@@ -0,0 +1 @@
+I am done
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroModuleProbes.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroModuleProbes.d.ksh
new file mode 100644
index 000000000000..dbea8ef73d9a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroModuleProbes.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -Z option can be used to permit descriptions that match
+# zero probes.
+#
+# SECTION: dtrace Utility/-Z Option;
+# dtrace Utility/-m Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qZm wassup'{printf("Iamkool");}' \
+-qm kernel'{printf("I am done"); exit(0);}'
+
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroModuleProbes.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroModuleProbes.d.ksh.out
new file mode 100644
index 000000000000..0f2e1aacd09e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroModuleProbes.d.ksh.out
@@ -0,0 +1 @@
+I am done
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroNameProbes.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroNameProbes.d.ksh
new file mode 100644
index 000000000000..90175a50b7b0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroNameProbes.d.ksh
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -Z option can be used to permit descriptions that match
+# zero probes.
+#
+# SECTION: dtrace Utility/-Z Option;
+# dtrace Utility/-n Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qZn wassup'{printf("Iamkool");}' \
+-qn BEGIN'{printf("I am done"); exit(0);}'
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroNameProbes.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroNameProbes.d.ksh.out
new file mode 100644
index 000000000000..0f2e1aacd09e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroNameProbes.d.ksh.out
@@ -0,0 +1 @@
+I am done
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProbeIdentfier.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProbeIdentfier.d.ksh
new file mode 100644
index 000000000000..9af4d2b8c836
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProbeIdentfier.d.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Testing -i option with zero probe identifier.
+#
+# SECTION: dtrace Utility/-i Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -i 0
+
+if [ $? -ne 1 ]; then
+ echo $tst: dtrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProbesWithoutZ.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProbesWithoutZ.d.ksh
new file mode 100644
index 000000000000..afc7d76d22bb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProbesWithoutZ.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# Without the -Z option probe descriptions that do not match any known
+# probes will cause an error or will not be enabled.
+#
+# SECTION: dtrace Utility/-Z Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qP wassup'{printf("Iamkool");}' \
+-qP profile'{printf("I am done"); exit(0);}'
+
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo $tst: dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProviderProbes.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProviderProbes.d.ksh
new file mode 100644
index 000000000000..f2646bd53401
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProviderProbes.d.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+##
+#
+# ASSERTION:
+# The -Z option can be used to permit descriptions that match
+# zero probes.
+#
+# SECTION: dtrace Utility/-Z Option;
+# dtrace Utility/-P Option
+#
+##
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qZP wassup'{printf("Iamkool");}' \
+-qP profile'{printf("I am done"); exit(0);}'
+
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProviderProbes.d.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProviderProbes.d.ksh.out
new file mode 100644
index 000000000000..0f2e1aacd09e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/dtraceUtil/tst.ZeroProviderProbes.d.ksh.out
@@ -0,0 +1 @@
+I am done
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/err.D_IDENT_UNDEF.timespent.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/err.D_IDENT_UNDEF.timespent.d
new file mode 100644
index 000000000000..04ccb7266816
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/err.D_IDENT_UNDEF.timespent.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Calculate timestamp between BEGIN and END.
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+END
+{
+ total = timestamp - start;
+}
+
+BEGIN
+{
+ start = timestamp;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.end.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.end.d
new file mode 100644
index 000000000000..56c1a4c42617
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.end.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Sequence flow of END profile.
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+END
+{
+ printf("End fired after exit\n");
+}
+
+BEGIN
+{
+ printf("Begin fired first\n");
+}
+
+tick-1
+{
+ printf("tick fired second\n");
+ printf("Call exit\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.endwithoutbegin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.endwithoutbegin.d
new file mode 100644
index 000000000000..6291960701cc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.endwithoutbegin.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * END without BEGIN profile
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+END
+{
+ printf("End fired after exit\n");
+}
+
+tick-1
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.multibeginend.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.multibeginend.d
new file mode 100644
index 000000000000..4f6ec9210beb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.multibeginend.d
@@ -0,0 +1,77 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Tests multiple END profile.
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+END
+{
+ printf("End1 fired after exit\n");
+}
+END
+{
+ printf("End2 fired after exit\n");
+}
+END
+{
+ printf("End3 fired after exit\n");
+}
+END
+{
+ printf("End4 fired after exit\n");
+}
+
+BEGIN
+{
+ printf("Begin fired first\n");
+}
+BEGIN
+{
+ printf("Begin fired second\n");
+}
+BEGIN
+{
+ printf("Begin fired third\n");
+}
+BEGIN
+{
+ printf("Begin fired fourth\n");
+}
+BEGIN
+{
+ printf("Begin fired fifth\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.multiend.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.multiend.d
new file mode 100644
index 000000000000..e6629fb5cb31
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/end/tst.multiend.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Tests Multiple END and single BEGIN
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+END
+{
+ printf("End1 fired after exit\n");
+}
+END
+{
+ printf("End2 fired after exit\n");
+}
+END
+{
+ printf("End3 fired after exit\n");
+}
+END
+{
+ printf("End4 fired after exit\n");
+}
+
+BEGIN
+{
+ printf("Begin fired first\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/err.D_DECL_IDRED.EnumSameName.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/err.D_DECL_IDRED.EnumSameName.d
new file mode 100644
index 000000000000..7e5427a51085
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/err.D_DECL_IDRED.EnumSameName.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Enumerations assigning same or different values to the same identifier in
+ * different enumerations should throw a compiler error.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ *
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+enum colors {
+ RED,
+ GREEN,
+ BLUE
+};
+
+enum shades {
+ RED,
+ ORANGE,
+ GREEN,
+ WHITE
+};
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/err.D_UNKNOWN.RepeatIdentifiers.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/err.D_UNKNOWN.RepeatIdentifiers.d
new file mode 100644
index 000000000000..2b4266d5c015
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/err.D_UNKNOWN.RepeatIdentifiers.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Repeating the same identifier in the same enumeration will throw a compiler
+ * error.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ *
+ * NOTES:
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+enum colors {
+ RED,
+ GREEN,
+ GREEN = 2,
+ BLUE
+};
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumEquality.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumEquality.d
new file mode 100644
index 000000000000..cbf9369a8a6a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumEquality.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the identifiers in different D enumerations at same position for
+ * equality.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ */
+
+#pragma D option quiet
+
+enum colors {
+ RED,
+ GREEN,
+ BLUE
+};
+
+enum shades {
+ WHITE,
+ BLACK,
+ YELLOW
+};
+
+
+profile:::tick-1sec
+/(WHITE == RED) && (YELLOW == BLUE) && (GREEN == BLACK)/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumSameValue.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumSameValue.d
new file mode 100644
index 000000000000..26a4d504dcc4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumSameValue.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Enumerations assigning the same value to different identifiers in the same
+ * enumeration should work okay.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ *
+ * NOTES:
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+enum colors {
+ RED = 2,
+ GREEN = 2,
+ BLUE = 2
+};
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumValAssign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumValAssign.d
new file mode 100644
index 000000000000..f721c50a3941
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/enum/tst.EnumValAssign.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Test the D enumerations with and without initilialization of the identifiers.
+ * Also test for values with negative integer assignments, expressions and
+ * fractions.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+enum colors {
+ RED,
+ ORANGE = 5 + 5,
+ YELLOW = 2,
+ GREEN,
+ BLUE = GREEN + ORANGE,
+ PINK = 5/4,
+ INDIGO = -2,
+ VIOLET
+};
+
+profile:::tick-1sec
+/(0 == RED) && (10 == ORANGE) && (2 == YELLOW) && (3 == GREEN) &&
+ (13 == BLUE) && (1 == PINK) && (-2 == INDIGO) && (-1 == VIOLET)/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d
new file mode 100644
index 000000000000..ec4b4ee0b179
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d
@@ -0,0 +1,25 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#pragma D option setenv=balloon=something_bad_happens
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d
new file mode 100644
index 000000000000..7adc77fe7ea6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d
@@ -0,0 +1,25 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#pragma D option unsetenv=rectalexambot
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh
new file mode 100644
index 000000000000..731a207e6a7f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Check that the LD_NOLAZYLOAD variable is set to 1 as expected.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -q -Z -n doogle -c 'printenv LD_NOLAZYLOAD'
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out
new file mode 100644
index 000000000000..d474e1b4d626
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out
@@ -0,0 +1,2 @@
+1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh
new file mode 100644
index 000000000000..b72b23d8a037
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Reset an environment variable we already know to be set.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -q -Z -n doogle -xsetenv=LD_NOLAZYLOAD=0 -c 'printenv LD_NOLAZYLOAD'
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out
new file mode 100644
index 000000000000..77ac542d4fbf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out
@@ -0,0 +1,2 @@
+0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh
new file mode 100644
index 000000000000..4e962a812682
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Test setting a variable that we isn't already set.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -q -Z -n doogle -xsetenv=CORPORATIONS=PEOPLE -c 'printenv CORPORATIONS'
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out
new file mode 100644
index 000000000000..ca5c4ffdda9e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out
@@ -0,0 +1,2 @@
+PEOPLE
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv3.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv3.ksh
new file mode 100644
index 000000000000..50eb16e45d44
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv3.ksh
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Reset an environment variable we already know to be set.
+# Regression test for FreeBSD r327794.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -q -Z -n doogle -xsetenv=PATH=/foo -c '/usr/bin/printenv PATH'
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv3.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv3.ksh.out
new file mode 100644
index 000000000000..699539b069ec
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv3.ksh.out
@@ -0,0 +1,2 @@
+/foo
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh
new file mode 100644
index 000000000000..73e1297d23b7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Test unsetting a variable we know to be set.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -q -Z -n doogle -xunsetenv=LD_NOLAZYLOAD -c 'printenv LD_NOLAZYLOAD'
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out
new file mode 100644
index 000000000000..8b137891791f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out
@@ -0,0 +1 @@
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh
new file mode 100644
index 000000000000..467c60d775a6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Test invalid syntax to the unsetenv option.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -q -Z -n doogle -xunsetenv=ed=screven -c 'true' 2>&1
+
+[[ $? -eq 1 ]] && exit 0
+
+exit 1
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out
new file mode 100644
index 000000000000..a2dd32a393c2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out
@@ -0,0 +1 @@
+dtrace: failed to set -x unsetenv: Invalid value for specified option
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_BADADDR.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_BADADDR.d
new file mode 100644
index 000000000000..5eb3e94c2e38
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_BADADDR.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To test DTRACEFLT_BADADDR error
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+ERROR
+{
+ printf("The arguments are %u %u %u %u %u\n",
+ arg1, arg2, arg3, arg4, arg5);
+ printf("The value of arg4 = %u\n", DTRACEFLT_BADADDR);
+ exit(0);
+}
+
+BEGIN
+{
+ *(char *)NULL;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_DIVZERO.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_DIVZERO.d
new file mode 100644
index 000000000000..5b93168a127d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_DIVZERO.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To test DTRACEFLT_DIVZERO error
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+ERROR
+{
+ printf("The arguments are %u %u %u %d %u\n",
+ arg1, arg2, arg3, arg4, arg5);
+ exit(0);
+}
+
+char *s;
+
+BEGIN
+{
+ i = 1;
+ j = 2;
+ j = i/(j-2);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_UNKNOWN.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_UNKNOWN.d
new file mode 100644
index 000000000000..6de75bbcce79
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.DTRACEFLT_UNKNOWN.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To test DTRACEFLT_UNKNOWN error
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+ERROR
+{
+ printf("The arguments are %u %u %u %u %u\n",
+ arg1, arg2, arg3, arg4, arg5);
+ printf("The value of arg4 = %u\n", DTRACEFLT_UNKNOWN);
+ exit(0);
+}
+
+BEGIN
+{
+ x = (int *) 64;
+ y = *x;
+ trace(y);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.error.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.error.d
new file mode 100644
index 000000000000..3b1d65399db6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.error.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To fire ERROR probe
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+ERROR
+{
+ printf("Error fired\n");
+ exit(0);
+}
+
+BEGIN
+{
+ *(char *)NULL;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.errorend.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.errorend.d
new file mode 100644
index 000000000000..0bb4a6efce5b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/error/tst.errorend.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Flow of ERROR probe
+ *
+ * SECTION: dtrace Provider
+ *
+ */
+
+
+#pragma D option quiet
+
+ERROR
+{
+ printf("Error fired\n");
+ exit(0);
+}
+
+END
+{
+ printf("End fired after exit\n");
+}
+
+BEGIN
+{
+ *(char *)NULL;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/err.D_PROTO_LEN.noarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/err.D_PROTO_LEN.noarg.d
new file mode 100644
index 000000000000..9a9a8f934c18
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/err.D_PROTO_LEN.noarg.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Call exit() without arguments.
+ *
+ * SECTION: Actions and Subroutines/exit()
+ */
+
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ exit()
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/err.exitarg1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/err.exitarg1.d
new file mode 100644
index 000000000000..d3067d126977
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/err.exitarg1.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Basic test - call with 1
+ *
+ * SECTION: Actions and Subroutines/exit()
+ */
+
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/tst.basic1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/tst.basic1.d
new file mode 100644
index 000000000000..24f841c3478c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/exit/tst.basic1.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test
+ *
+ * SECTION: Actions and Subroutines/exit()
+ */
+
+
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/err.D_PDESC_ZERO.notreturn.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/err.D_PDESC_ZERO.notreturn.d
new file mode 100644
index 000000000000..5e3d5fa7eb06
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/err.D_PDESC_ZERO.notreturn.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: Call fbt provider over non existent function and make
+ * sure it results in compilation error.
+ *
+ * SECTION: FBT Provider/Probes
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ self->traceme = 1;
+}
+
+void bar();
+
+fbt::bar:entry
+{
+ printf("Entering the function\n");
+}
+
+fbt::bar:return
+{
+ printf("Returning the function\n");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.basic.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.basic.d
new file mode 100644
index 000000000000..ff6da26f318c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.basic.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: simple fbt arguments test.
+ *
+ * SECTION: FBT Provider/Probes
+ */
+
+#pragma D option quiet
+
+tick-1
+{
+ self->traceme = 1;
+}
+
+fbt:::
+/self->traceme/
+{
+ printf("The arguments are %u %u %u %u %u %u %u %u\n", arg0, arg1,
+ arg3, arg4, arg5, arg6, arg7, arg8);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.functionentry.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.functionentry.d
new file mode 100644
index 000000000000..e625cd9996d4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.functionentry.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: FBT provider function entry and exit test.
+ *
+ * SECTION: FBT Provider/Probe arguments
+ */
+
+#pragma D option quiet
+#pragma D option statusrate=10ms
+
+fbt::kern_ioctl:entry
+{
+ printf("Entering the ioctl function\n");
+}
+
+fbt::kern_ioctl:return
+{
+ printf("Returning from ioctl function\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.functionreturnvalue.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.functionreturnvalue.d
new file mode 100644
index 000000000000..f0338ec57133
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.functionreturnvalue.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: Fbt provider return value verify test.
+ *
+ * SECTION: FBT Provider/Probe arguments
+ */
+
+#pragma D option quiet
+#pragma D option statusrate=10ms
+
+fbt::kern_ioctl:return
+{
+ printf("The function return value is stored in %u\n", arg1);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.ioctlargs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.ioctlargs.d
new file mode 100644
index 000000000000..5a26459a2eef
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.ioctlargs.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: FBT provider arguments scan test.
+ *
+ * SECTION: FBT Provider/Probe arguments
+ */
+
+#pragma D option quiet
+#pragma D option statusrate=10ms
+
+fbt::kern_ioctl:entry
+{
+ printf("Entering the ioctl function\n");
+ printf("The few arguments are %u %u %u %u\n", arg0, arg1, arg2, arg3);
+}
+
+fbt::kern_ioctl:return
+{
+ printf("Returning from ioctl function\n");
+ printf("The few arguments are %u %u %u %u\n", arg0, arg1, arg2, arg3);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.offset.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.offset.d
new file mode 100644
index 000000000000..2ee8080305ba
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.offset.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: FBT provider return value offset verification test.
+ *
+ * SECTION: FBT Provider/Probe arguments
+ */
+
+#pragma D option quiet
+#pragma D option statusrate=10ms
+
+BEGIN
+{
+ self->traceme = 1;
+}
+
+fbt::kern_ioctl:entry
+{
+ printf("Entering the function\n");
+}
+
+fbt::kern_ioctl:return
+{
+ printf("The offset = %u\n", arg0);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.offsetzero.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.offsetzero.d
new file mode 100644
index 000000000000..1e8ae16e0970
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.offsetzero.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: FBT provider argument 0 test
+ *
+ * SECTION: FBT Provider/Probe arguments
+ */
+
+#pragma D option quiet
+#pragma D option statusrate=10ms
+
+fbt::kern_ioctl:entry
+{
+ printf("Entering the ioctl function\n");
+ printf("The few arguments are %u %u %u %u\n", arg0, arg1, arg2, arg3);
+ exit(0);
+}
+
+fbt::kern_ioctl:return
+{
+ printf("Returning from ioctl function\n");
+ printf("The few arguments are %u %u %u %u\n", arg0, arg1, arg2, arg3);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.return.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.return.d
new file mode 100644
index 000000000000..b269710ec844
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.return.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: simple fbt provider return test.
+ *
+ * SECTION: FBT Provider/Probe arguments
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ self->traceme = 1;
+}
+
+fbt:::entry
+{
+ printf("Entering the function\n");
+}
+
+fbt:::return
+{
+ printf("Returning the function\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.return0.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.return0.d
new file mode 100644
index 000000000000..3fb54227b050
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.return0.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: simple fbt provider arg0 and probfunc print test.
+ *
+ * SECTION: FBT Provider/Probe arguments
+ */
+
+#pragma D option quiet
+#pragma D option statusrate=10ms
+
+fbt::kern_ioctl:return
+/arg1 == 0/
+{
+ printf("%s %x returned 0", probefunc, arg0);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.tailcall.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.tailcall.d
new file mode 100644
index 000000000000..8dbb0abe39c0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/fbtprovider/tst.tailcall.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION: simple fbt provider tailcall test.
+ *
+ * SECTION: FBT Provider/Probe arguments
+ */
+
+#pragma D option quiet
+#pragma D option statusrate=10ms
+
+fbt::kern_ioctl:entry
+{
+ self->traceme = 1;
+}
+
+fbt:::entry
+/self->traceme/
+{
+ printf("called %s\n", probefunc);
+}
+
+fbt::kern_ioctl:return
+/self->traceme/
+{
+ self->traceme = 0;
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_FUNC_UNDEF.progenyofbad1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_FUNC_UNDEF.progenyofbad1.d
new file mode 100644
index 000000000000..bfd1eedf83c0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_FUNC_UNDEF.progenyofbad1.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * progenyof() should accept one argument - a pid
+ *
+ * SECTION: Actions and Subroutines/progenyof()
+ *
+ */
+
+
+BEGIN
+{
+ progencyof(1, 2);
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_OP_VFPTR.badop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_OP_VFPTR.badop.d
new file mode 100644
index 000000000000..d219bb1fe9e2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_OP_VFPTR.badop.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * +=, -= must handle invalid variables.
+ *
+ * SECTION: Types, Operators, and Expressions/Assignment Operators
+ *
+ */
+
+
+int p;
+
+BEGIN
+{
+ p = 1;
+ p -= alloca(10);
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.chillbadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.chillbadarg.d
new file mode 100644
index 000000000000..08bd98191f95
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.chillbadarg.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * chill() should handle a bad argument.
+ *
+ * SECTION: Actions and Subroutines/chill()
+ *
+ */
+
+
+BEGIN
+{
+ chill("badarg");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.copyoutbadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.copyoutbadarg.d
new file mode 100644
index 000000000000..5c02378fb28c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.copyoutbadarg.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * copyout() must handle invalid argument types.
+ *
+ * SECTION: Actions and Subroutines/copyout()
+ *
+ */
+
+
+BEGIN
+{
+ copyout("not_void_*", "not_uinptr_t", "not_size_t");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.mobadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.mobadarg.d
new file mode 100644
index 000000000000..4df8d1868cf8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.mobadarg.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * mutex_owned() should handle an invalid argument passed.
+ *
+ * SECTION: Actions and Subroutines/mutex_owned()
+ *
+ */
+
+BEGIN
+{
+ mutex_owned("badarg");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.raisebadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.raisebadarg.d
new file mode 100644
index 000000000000..a3336efe8a98
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.raisebadarg.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * raise() should generate an error if any arguments are sent.
+ *
+ * SECTION: Actions and Subroutines/raise()
+ *
+ */
+
+
+BEGIN
+{
+ raise("badarg");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.tolower.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.tolower.d
new file mode 100644
index 000000000000..9d4e40b4dbde
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.tolower.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ trace(tolower(2152006));
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.toupper.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.toupper.d
new file mode 100644
index 000000000000..2c1389bdeb48
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_ARG.toupper.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ trace(toupper(timestamp));
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.allocanoarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.allocanoarg.d
new file mode 100644
index 000000000000..a2af00f9ea54
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.allocanoarg.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * alloca() should handle no arguments as an error
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ *
+ */
+
+#pragma D option quiet
+
+
+
+BEGIN
+{
+ ptr = alloca();
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.badbreakpoint.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.badbreakpoint.d
new file mode 100644
index 000000000000..0cb567a51b67
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.badbreakpoint.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * breakpoint() should handle arguments passed as an error.
+ *
+ * SECTION: Actions and Subroutines/breakpoint()
+ *
+ */
+
+
+BEGIN
+{
+ breakpoint(1, 2);
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.chilltoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.chilltoofew.d
new file mode 100644
index 000000000000..a0018fa85c4e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.chilltoofew.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * chill() should handle no arguments.
+ *
+ * SECTION: Actions and Subroutines/chill()
+ *
+ */
+
+
+BEGIN
+{
+ chill();
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.chilltoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.chilltoomany.d
new file mode 100644
index 000000000000..f24e9ef1d284
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.chilltoomany.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * chill() should handle too many arguments.
+ *
+ * SECTION: Actions and Subroutines/chill()
+ *
+ */
+
+BEGIN
+{
+ chill(1000, 1000, 1000);
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyoutstrbadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyoutstrbadarg.d
new file mode 100644
index 000000000000..1f07814b6789
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyoutstrbadarg.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * copyoutstr() must handle invalid argument types.
+ *
+ * SECTION: Actions and Subroutines/copyoutstr()
+ *
+ */
+
+
+BEGIN
+{
+ copyoutstr("string", "not_uintptr_t");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyoutstrtoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyoutstrtoofew.d
new file mode 100644
index 000000000000..e01868c030ca
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyoutstrtoofew.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Calling copyoutstr() with less than 2 arguments will generate an error
+ *
+ * SECTION: Actions and Subroutines/copyoutstr()
+ *
+ */
+
+
+BEGIN
+{
+ copyoutstr("string");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyouttoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyouttoofew.d
new file mode 100644
index 000000000000..f3706f622805
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyouttoofew.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Calling copyout() with less than 3 arguments will generate an error
+ *
+ * SECTION: Actions and Subroutines/copyout()
+ *
+ */
+
+
+BEGIN
+{
+ copyout(0, 20);
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyouttoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyouttoomany.d
new file mode 100644
index 000000000000..6fab90d8fc53
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.copyouttoomany.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * copyout() should handle too many arguments passed.
+ *
+ * SECTION: Actions and Subroutines/copyin();
+ * Actions and Subroutines/copyinstr()
+ *
+ */
+
+
+BEGIN
+{
+ copyout((void *)3, (uintptr_t)1000, (size_t)1000, "toomany");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.motoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.motoofew.d
new file mode 100644
index 000000000000..823a98d4dd3e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.motoofew.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * mutex_owned() should handle too few args passed
+ *
+ * SECTION: Actions and Subroutines/mutex_owned()
+ *
+ */
+
+lockstat:::adaptive-acquire
+{
+ mutex_owned();
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.motoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.motoomany.d
new file mode 100644
index 000000000000..37637c052b20
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.motoomany.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * mutex_owned() should handle too many args passed
+ *
+ * SECTION: Actions and Subroutines/mutex_owned()
+ *
+ */
+
+lockstat:::adaptive-acquire
+{
+ mutex_owned((kmutex_t *)arg0, 99);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtabadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtabadarg.d
new file mode 100644
index 000000000000..6ad1e47b434c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtabadarg.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * mutex_type_adaptive() should handle an invalid argument passed.
+ *
+ * SECTION: Actions and Subroutines/mutex_type_adaptive()
+ *
+ */
+
+
+BEGIN
+{
+ mutex_type_adaptive(trace());
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtatoofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtatoofew.d
new file mode 100644
index 000000000000..2d299d4b7312
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtatoofew.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * mutex_type_adaptive() should handle too few args passed
+ *
+ * SECTION: Actions and Subroutines/mutex_type_adaptive()
+ *
+ */
+
+
+lockstat:::adaptive-acquire
+{
+ mutex_type_adaptive();
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtatoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtatoomany.d
new file mode 100644
index 000000000000..42ae0168644a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.mtatoomany.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * mutex_type_adaptive() should handle too many args passed
+ *
+ * SECTION: Actions and Subroutines/mutex_type_adaptive()
+ *
+ */
+
+
+lockstat:::adaptive-acquire
+{
+ mutex_type_adaptive((kmutex_t *)arg0, 99);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.panicbadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.panicbadarg.d
new file mode 100644
index 000000000000..87589b48491c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.panicbadarg.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * panic() should handle any argument passed as an error.
+ *
+ * SECTION: Actions and Subroutines/panic()
+ *
+ */
+
+
+BEGIN
+{
+ panic("badarg");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.progenyofbad2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.progenyofbad2.d
new file mode 100644
index 000000000000..51c8674defe6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.progenyofbad2.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * progenyof() should return an error if the argument is an
+ * incorrect type.
+ *
+ * SECTION: Actions and Subroutines/progenyof()
+ *
+ */
+
+
+BEGIN
+{
+ progenyof(trace());
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.stopbadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.stopbadarg.d
new file mode 100644
index 000000000000..8b6050715878
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.stopbadarg.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * stop() should generate an error if any arguments are sent.
+ *
+ * SECTION: Actions and Subroutines/stop()
+ *
+ */
+
+
+BEGIN
+{
+ stop("badarg");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.tolower.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.tolower.d
new file mode 100644
index 000000000000..7d9c27f902d9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.tolower.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ trace(tolower());
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.tolowertoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.tolowertoomany.d
new file mode 100644
index 000000000000..afaa7f976ed6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.tolowertoomany.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ trace(tolower("dory", "eel", "roughy"));
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.toupper.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.toupper.d
new file mode 100644
index 000000000000..9658f6a75441
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.toupper.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ trace(toupper());
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.touppertoomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.touppertoomany.d
new file mode 100644
index 000000000000..bee8697fb2c4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_PROTO_LEN.touppertoomany.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ trace(tolower("haino", "tylo"));
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_STRINGOF_TYPE.badstringof.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_STRINGOF_TYPE.badstringof.d
new file mode 100644
index 000000000000..fec5649b5d30
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_STRINGOF_TYPE.badstringof.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * stringof() accepts a scalar, pointer, or string
+ *
+ * SECTION: Types, Operators, and Expressions/Precedence
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("%s", stringof (trace(0)));
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_VAR_UNDEF.badvar.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_VAR_UNDEF.badvar.d
new file mode 100644
index 000000000000..bb4fd2d18e97
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.D_VAR_UNDEF.badvar.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * +=, -= must handle invalid variables.
+ *
+ * SECTION: Types, Operators, and Expressions/Assignment Operators
+ *
+ */
+
+
+BEGIN
+{
+ p -= trace(0);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badalloca.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badalloca.d
new file mode 100644
index 000000000000..572daa39fec0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badalloca.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * memory allocated by alloca() is only valid within the clause
+ * it is allocated.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ ptr = alloca(sizeof (int));
+}
+
+tick-1
+{
+ bcopy((void *)&`kmem_flags, ptr, sizeof (int));
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badalloca2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badalloca2.d
new file mode 100644
index 000000000000..fbbf8e2e0503
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badalloca2.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * alloca() cannot be used to "unconsume" scratch space memory by
+ * accepting a negative offset.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ *
+ */
+
+BEGIN
+{
+ ptr = alloca(10);
+ ptr = alloca(0xffffffffffffffff);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy.d
new file mode 100644
index 000000000000..d7184b0f42b4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * bcopy should not allow a copy to memory that is not scratch memory.
+ *
+ * SECTION: Actions and Subroutines/alloca();
+ * Actions and Subroutines/bcopy()
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ ptr = alloca(sizeof (int));
+
+ /* Attempt a copy from scratch memory to a kernel address */
+
+ bcopy(ptr, (void *)&`kmem_flags, sizeof (int));
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy1.d
new file mode 100644
index 000000000000..c29eb2bb8139
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy1.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * bcopy should not copy from one memory location to another
+ * if the memory is not properly allocated
+ *
+ * SECTION: Actions and Subroutines/alloca();
+ * Actions and Subroutines/bcopy()
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ ptr = alloca(0);
+
+ /* Attempt to bcopy to scratch memory that isn't allocated */
+ bcopy((void *)&`kmem_flags, ptr, sizeof (int));
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy2.d
new file mode 100644
index 000000000000..6d49e6ec5ff6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy2.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * bcopy should not copy from one memory location to another
+ * if the memory is not properly allocated
+ *
+ * SECTION: Actions and Subroutines/bcopy()
+ *
+ */
+
+#pragma D option quiet
+
+int *ptr;
+
+BEGIN
+{
+ /* Attempt to copy to non-scratch memory */
+
+ bcopy((void *)&`kmem_flags, ptr, sizeof (int));
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy3.d
new file mode 100644
index 000000000000..c362caad574c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy3.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * bcopy should not copy from one memory location to another
+ * if the memory is not properly allocated
+ *
+ * SECTION: Actions and Subroutines/bcopy()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ /* Attempt to copy to a NULL address */
+ bcopy((void *)&`kmem_flags, (void *)NULL, sizeof (int));
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy4.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy4.d
new file mode 100644
index 000000000000..4148ae7bf311
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy4.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * bcopy should not copy from one memory location to another
+ * if the source memory location is not valid.
+ *
+ * SECTION: Actions and Subroutines/alloca();
+ * Actions and Subroutines/bcopy()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ ptr = alloca(sizeof (int));
+
+ /* Attempt to copy from a NULL address */
+ bcopy((void *)NULL, ptr, sizeof (int));
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy5.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy5.d
new file mode 100644
index 000000000000..a0cbd5d4a1f3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy5.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * bcopy should not copy from one memory location to another
+ * if the source memory location is not valid.
+ *
+ * SECTION: Actions and Subroutines/alloca();
+ * Actions and Subroutines/bcopy()
+ *
+ */
+
+#pragma D option quiet
+
+int *badptr;
+
+BEGIN
+{
+ ptr = alloca(sizeof (int));
+
+ /* Attempt to copy from a invalid address */
+ bcopy(badptr, ptr, sizeof (int));
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy6.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy6.d
new file mode 100644
index 000000000000..32770145ad6c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badbcopy6.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ bcopy("bad news", alloca(1), -1);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badchill.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badchill.d
new file mode 100644
index 000000000000..b394a88b4ca1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.badchill.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ chill(200);
+ chill(((hrtime_t)1 << 63) - 1);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.chillbadarg.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.chillbadarg.ksh
new file mode 100644
index 000000000000..98f04dd20ce1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.chillbadarg.ksh
@@ -0,0 +1,69 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+# ident "%Z%%M% %I% %E% SMI"
+
+dtrace_script()
+{
+
+ $dtrace -w -s /dev/stdin <<EOF
+
+ /*
+ * ASSERTION:
+ * Verify that chill() refuses args greater than
+ * 500 milliseconds.
+ *
+ * SECTION: Actions and Subroutines/chill()
+ *
+ */
+
+ BEGIN
+ {
+ chill(500000001);
+ exit(1);
+ }
+
+ ERROR
+ {
+ exit(1)
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+dtrace_script &
+child=$!
+
+wait $child
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyout.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyout.d
new file mode 100644
index 000000000000..6b9db3b811a7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyout.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * copyout() should handle invalid args.
+ *
+ * SECTION: Actions and Subroutines/copyout()
+ *
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ i = 3;
+ copyout((void *)i, 0, 5);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyoutbadaddr.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyoutbadaddr.ksh
new file mode 100644
index 000000000000..de5c47d5c043
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyoutbadaddr.ksh
@@ -0,0 +1,71 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+# ident "%Z%%M% %I% %E% SMI"
+
+
+dtrace_script()
+{
+
+ $dtrace -w -s /dev/stdin <<EOF
+
+ /*
+ * ASSERTION:
+ * Verify that copyout() handles bad addresses.
+ *
+ * SECTION: Actions and Subroutines/copyout()
+ *
+ */
+
+ BEGIN
+ {
+ ptr = alloca(sizeof (char *));
+ copyinto(curpsinfo->pr_envp, sizeof (char *), ptr);
+ copyout(ptr, 0, sizeof (char *));
+ }
+
+ ERROR
+ {
+ exit(1)
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+dtrace_script &
+child=$!
+
+wait $child
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyoutstrbadaddr.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyoutstrbadaddr.ksh
new file mode 100644
index 000000000000..181702b8ecf0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.copyoutstrbadaddr.ksh
@@ -0,0 +1,70 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+# ident "%Z%%M% %I% %E% SMI"
+
+
+dtrace_script()
+{
+
+ $dtrace -w -s /dev/stdin <<EOF
+
+ /*
+ * ASSERTION:
+ * Verify that copyout() handles bad addresses.
+ *
+ * SECTION: Actions and Subroutines/copyout()
+ *
+ */
+
+ BEGIN
+ {
+ ptr = alloca(sizeof (char *));
+ copyinto(curpsinfo->pr_envp, sizeof (char *), ptr);
+ copyout(ptr, 0, sizeof (char *));
+ }
+
+ ERROR
+ {
+ exit(1)
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+dtrace_script &
+child=$!
+
+wait $child
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntoa6badaddr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntoa6badaddr.d
new file mode 100644
index 000000000000..81ce643f6b0b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntoa6badaddr.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+struct in6_addr *ip6a;
+
+BEGIN
+{
+ ip6a = 0;
+
+ printf("%s\n", inet_ntop(AF_INET6, ip6a));
+
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntoabadaddr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntoabadaddr.d
new file mode 100644
index 000000000000..3f0d8e45ff8b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntoabadaddr.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+ipaddr_t *ip4a;
+
+BEGIN
+{
+ ip4a = 0;
+
+ printf("%s\n", inet_ntoa(ip4a));
+
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntopbadaddr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntopbadaddr.d
new file mode 100644
index 000000000000..74ce760d8b66
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntopbadaddr.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+ipaddr_t *ip4a;
+
+BEGIN
+{
+ ip4a = 0;
+
+ printf("%s\n", inet_ntop(AF_INET, ip4a));
+
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntopbadarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntopbadarg.d
new file mode 100644
index 000000000000..2731385d2db4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/err.inet_ntopbadarg.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+ipaddr_t *ip4a;
+
+BEGIN
+{
+ this->buf4a = alloca(sizeof (ipaddr_t));
+ ip4a = this->buf4a;
+ *ip4a = htonl(0xc0a80117);
+
+ printf("%s\n", inet_ntop(-1, ip4a));
+
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.badfreopen.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.badfreopen.ksh
new file mode 100644
index 000000000000..72f6b87f8115
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.badfreopen.ksh
@@ -0,0 +1,102 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -wq -o $tmpfile -s /dev/stdin 2> $errfile <<EOF
+ BEGIN
+ {
+ /*
+ * All of these should fail...
+ */
+ freopen("..");
+ freopen("%s", ".");
+ freopen("%c%c", '.', '.');
+ freopen("%c", '.');
+
+ /*
+ * ...so stdout should still be open here.
+ */
+ printf("%d", ++i);
+
+ freopen("%s%s", ".", ".");
+ freopen("%s%s", ".", ".");
+
+ printf("%d", ++i);
+ }
+
+ BEGIN
+ /i == 2/
+ {
+ /*
+ * ...and here.
+ */
+ printf("%d\n", ++i);
+ exit(0);
+ }
+
+ BEGIN
+ {
+ exit(1);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+tmpfile=/tmp/tst.badfreopen.$$
+errfile=/tmp/tst.badfreopen.$$.stderr
+
+script
+status=$?
+
+if [ "$status" -eq 0 ]; then
+ i=`cat $tmpfile`
+
+ if [[ $i != "123" ]]; then
+ echo "$0: unexpected contents in $tmpfile: " \
+ "expected 123, found $i"
+ status=100
+ fi
+
+ i=`wc -l $errfile | nawk '{ print $1 }'`
+
+ if [ "$i" -lt 6 ]; then
+ echo "$0: expected at least 6 lines of stderr, found $i lines"
+ status=101
+ fi
+else
+ cat $errfile > /dev/fd/2
+fi
+
+rm $tmpfile $errfile
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.basename.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.basename.d
new file mode 100644
index 000000000000..e4eae881432f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.basename.d
@@ -0,0 +1,106 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+#pragma D option dynvarsize=2m
+
+/*
+ * This test verifies that the basename() and dirname() functions are working
+ * properly. Note that the output of this is a ksh script. When run,
+ * it will give no output if the output is correct.
+ */
+BEGIN
+{
+ dir[i++] = "/foo/bar/baz";
+ dir[i++] = "/foo/bar///baz/";
+ dir[i++] = "/foo/bar/baz/";
+ dir[i++] = "/foo/bar/baz//";
+ dir[i++] = "/foo/bar/baz/.";
+ dir[i++] = "/foo/bar/baz/./";
+ dir[i++] = "/foo/bar/baz/.//";
+ dir[i++] = "foo/bar/baz/";
+ dir[i++] = "/";
+ dir[i++] = "./";
+ dir[i++] = "//";
+ dir[i++] = "/.";
+ dir[i++] = "/./";
+ dir[i++] = "/./.";
+ dir[i++] = "/.//";
+ dir[i++] = ".";
+ dir[i++] = "f";
+ dir[i++] = "f/";
+ dir[i++] = "/////";
+ /*
+ * basename(3) and basename(1) return different results for the empty
+ * string on FreeBSD, so we need special handling.
+ dir[i++] = "";
+ */
+
+ end = i;
+ i = 0;
+
+ printf("#!/usr/bin/env ksh\n\n");
+}
+
+tick-1ms
+/i < end/
+{
+ printf("if [ `basename \"%s\"` != \"%s\" ]; then\n",
+ dir[i], basename(dir[i]));
+ printf(" echo \"basename(\\\"%s\\\") is \\\"%s\\\"; ",
+ dir[i], basename(dir[i]));
+ printf("expected \\\"`basename \"%s\"`\"\\\"\n", dir[i]);
+ printf("fi\n\n");
+ printf("if [ `dirname \"%s\"` != \"%s\" ]; then\n",
+ dir[i], dirname(dir[i]));
+ printf(" echo \"dirname(\\\"%s\\\") is \\\"%s\\\"; ",
+ dir[i], dirname(dir[i]));
+ printf("expected \\\"`dirname \"%s\"`\"\\\"\n", dir[i]);
+ printf("fi\n\n");
+ i++;
+}
+
+tick-1ms
+/i == end/
+{
+ dir[i] = "";
+ printf("if [ \"`basename \"%s\"`\" != \"%s\" -a \".\" != \"%s\" ]; then\n",
+ dir[i], basename(dir[i]), basename(dir[i]));
+ printf(" echo \"basename(\\\"%s\\\") is \\\"%s\\\"; ",
+ dir[i], basename(dir[i]));
+ printf("expected \\\"`basename \"%s\"`\\\" or \\\".\\\"\"\n", dir[i]);
+ printf("fi\n\n");
+ printf("if [ `dirname \"%s\"` != \"%s\" ]; then\n",
+ dir[i], dirname(dir[i]));
+ printf(" echo \"dirname(\\\"%s\\\") is \\\"%s\\\"; ",
+ dir[i], dirname(dir[i]));
+ printf("expected \\\"`dirname \"%s\"`\"\\\"\n", dir[i]);
+ printf("fi\n\n");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.basename.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.basename.d.out
new file mode 100644
index 000000000000..0f94599df1ea
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.basename.d.out
@@ -0,0 +1,163 @@
+#!/usr/bin/env ksh
+
+if [ `basename "/foo/bar/baz"` != "baz" ]; then
+ echo "basename(\"/foo/bar/baz\") is \"baz\"; expected \"`basename "/foo/bar/baz"`"\"
+fi
+
+if [ `dirname "/foo/bar/baz"` != "/foo/bar" ]; then
+ echo "dirname(\"/foo/bar/baz\") is \"/foo/bar\"; expected \"`dirname "/foo/bar/baz"`"\"
+fi
+
+if [ `basename "/foo/bar///baz/"` != "baz" ]; then
+ echo "basename(\"/foo/bar///baz/\") is \"baz\"; expected \"`basename "/foo/bar///baz/"`"\"
+fi
+
+if [ `dirname "/foo/bar///baz/"` != "/foo/bar" ]; then
+ echo "dirname(\"/foo/bar///baz/\") is \"/foo/bar\"; expected \"`dirname "/foo/bar///baz/"`"\"
+fi
+
+if [ `basename "/foo/bar/baz/"` != "baz" ]; then
+ echo "basename(\"/foo/bar/baz/\") is \"baz\"; expected \"`basename "/foo/bar/baz/"`"\"
+fi
+
+if [ `dirname "/foo/bar/baz/"` != "/foo/bar" ]; then
+ echo "dirname(\"/foo/bar/baz/\") is \"/foo/bar\"; expected \"`dirname "/foo/bar/baz/"`"\"
+fi
+
+if [ `basename "/foo/bar/baz//"` != "baz" ]; then
+ echo "basename(\"/foo/bar/baz//\") is \"baz\"; expected \"`basename "/foo/bar/baz//"`"\"
+fi
+
+if [ `dirname "/foo/bar/baz//"` != "/foo/bar" ]; then
+ echo "dirname(\"/foo/bar/baz//\") is \"/foo/bar\"; expected \"`dirname "/foo/bar/baz//"`"\"
+fi
+
+if [ `basename "/foo/bar/baz/."` != "." ]; then
+ echo "basename(\"/foo/bar/baz/.\") is \".\"; expected \"`basename "/foo/bar/baz/."`"\"
+fi
+
+if [ `dirname "/foo/bar/baz/."` != "/foo/bar/baz" ]; then
+ echo "dirname(\"/foo/bar/baz/.\") is \"/foo/bar/baz\"; expected \"`dirname "/foo/bar/baz/."`"\"
+fi
+
+if [ `basename "/foo/bar/baz/./"` != "." ]; then
+ echo "basename(\"/foo/bar/baz/./\") is \".\"; expected \"`basename "/foo/bar/baz/./"`"\"
+fi
+
+if [ `dirname "/foo/bar/baz/./"` != "/foo/bar/baz" ]; then
+ echo "dirname(\"/foo/bar/baz/./\") is \"/foo/bar/baz\"; expected \"`dirname "/foo/bar/baz/./"`"\"
+fi
+
+if [ `basename "/foo/bar/baz/.//"` != "." ]; then
+ echo "basename(\"/foo/bar/baz/.//\") is \".\"; expected \"`basename "/foo/bar/baz/.//"`"\"
+fi
+
+if [ `dirname "/foo/bar/baz/.//"` != "/foo/bar/baz" ]; then
+ echo "dirname(\"/foo/bar/baz/.//\") is \"/foo/bar/baz\"; expected \"`dirname "/foo/bar/baz/.//"`"\"
+fi
+
+if [ `basename "foo/bar/baz/"` != "baz" ]; then
+ echo "basename(\"foo/bar/baz/\") is \"baz\"; expected \"`basename "foo/bar/baz/"`"\"
+fi
+
+if [ `dirname "foo/bar/baz/"` != "foo/bar" ]; then
+ echo "dirname(\"foo/bar/baz/\") is \"foo/bar\"; expected \"`dirname "foo/bar/baz/"`"\"
+fi
+
+if [ `basename "/"` != "/" ]; then
+ echo "basename(\"/\") is \"/\"; expected \"`basename "/"`"\"
+fi
+
+if [ `dirname "/"` != "/" ]; then
+ echo "dirname(\"/\") is \"/\"; expected \"`dirname "/"`"\"
+fi
+
+if [ `basename "./"` != "." ]; then
+ echo "basename(\"./\") is \".\"; expected \"`basename "./"`"\"
+fi
+
+if [ `dirname "./"` != "." ]; then
+ echo "dirname(\"./\") is \".\"; expected \"`dirname "./"`"\"
+fi
+
+if [ `basename "//"` != "/" ]; then
+ echo "basename(\"//\") is \"/\"; expected \"`basename "//"`"\"
+fi
+
+if [ `dirname "//"` != "/" ]; then
+ echo "dirname(\"//\") is \"/\"; expected \"`dirname "//"`"\"
+fi
+
+if [ `basename "/."` != "." ]; then
+ echo "basename(\"/.\") is \".\"; expected \"`basename "/."`"\"
+fi
+
+if [ `dirname "/."` != "/" ]; then
+ echo "dirname(\"/.\") is \"/\"; expected \"`dirname "/."`"\"
+fi
+
+if [ `basename "/./"` != "." ]; then
+ echo "basename(\"/./\") is \".\"; expected \"`basename "/./"`"\"
+fi
+
+if [ `dirname "/./"` != "/" ]; then
+ echo "dirname(\"/./\") is \"/\"; expected \"`dirname "/./"`"\"
+fi
+
+if [ `basename "/./."` != "." ]; then
+ echo "basename(\"/./.\") is \".\"; expected \"`basename "/./."`"\"
+fi
+
+if [ `dirname "/./."` != "/." ]; then
+ echo "dirname(\"/./.\") is \"/.\"; expected \"`dirname "/./."`"\"
+fi
+
+if [ `basename "/.//"` != "." ]; then
+ echo "basename(\"/.//\") is \".\"; expected \"`basename "/.//"`"\"
+fi
+
+if [ `dirname "/.//"` != "/" ]; then
+ echo "dirname(\"/.//\") is \"/\"; expected \"`dirname "/.//"`"\"
+fi
+
+if [ `basename "."` != "." ]; then
+ echo "basename(\".\") is \".\"; expected \"`basename "."`"\"
+fi
+
+if [ `dirname "."` != "." ]; then
+ echo "dirname(\".\") is \".\"; expected \"`dirname "."`"\"
+fi
+
+if [ `basename "f"` != "f" ]; then
+ echo "basename(\"f\") is \"f\"; expected \"`basename "f"`"\"
+fi
+
+if [ `dirname "f"` != "." ]; then
+ echo "dirname(\"f\") is \".\"; expected \"`dirname "f"`"\"
+fi
+
+if [ `basename "f/"` != "f" ]; then
+ echo "basename(\"f/\") is \"f\"; expected \"`basename "f/"`"\"
+fi
+
+if [ `dirname "f/"` != "." ]; then
+ echo "dirname(\"f/\") is \".\"; expected \"`dirname "f/"`"\"
+fi
+
+if [ `basename "/////"` != "/" ]; then
+ echo "basename(\"/////\") is \"/\"; expected \"`basename "/////"`"\"
+fi
+
+if [ `dirname "/////"` != "/" ]; then
+ echo "dirname(\"/////\") is \"/\"; expected \"`dirname "/////"`"\"
+fi
+
+if [ "`basename ""`" != "." -a "." != "." ]; then
+ echo "basename(\"\") is \".\"; expected \"`basename ""`\" or \".\""
+fi
+
+if [ `dirname ""` != "." ]; then
+ echo "dirname(\"\") is \".\"; expected \"`dirname ""`"\"
+fi
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.bcopy.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.bcopy.d
new file mode 100644
index 000000000000..8501ff441fc7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.bcopy.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * bcopy should copy from one memory location to another
+ *
+ * SECTION: Actions and Subroutines/alloca();
+ * Actions and Subroutines/bcopy()
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ ptr = alloca(sizeof (int));
+ bcopy((void *)&`kmem_flags, ptr, sizeof (int));
+ intp = (int *)ptr;
+ ret = (`kmem_flags == *intp) ? 0 : 1;
+}
+
+tick-1
+/ret == 0/
+{
+ exit(0);
+}
+
+tick-1
+/ret == 1/
+{
+ printf("memory address contained 0x%x, expected 0x%x\n",
+ *intp, `kmem_flags);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.chill.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.chill.ksh
new file mode 100644
index 000000000000..aae1c6881b4d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.chill.ksh
@@ -0,0 +1,77 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+dtrace_script()
+{
+
+ $dtrace -w -s /dev/stdin <<EOF
+
+ /*
+ * ASSERTION:
+ * Positive test of chill()
+ *
+ * SECTION: Actions and Subroutines/chill()
+ *
+ * NOTES: This test does no verification - it's not possible. So,
+ * we just run this and make sure it runs.
+ */
+
+ BEGIN
+ {
+ i = 0;
+ }
+
+ syscall:::entry
+ /i <= 5/
+ {
+ chill(100000000);
+ i++;
+ }
+
+ syscall:::entry
+ /i > 5/
+ {
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+dtrace_script &
+child=$!
+
+wait $child
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.cleanpath.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.cleanpath.d
new file mode 100644
index 000000000000..842eb67fc75e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.cleanpath.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+#pragma D option dynvarsize=2m
+
+BEGIN
+{
+ path[i++] = "/foo/bar/baz";
+ path[i++] = "/foo/bar///baz/";
+ path[i++] = "/foo/bar/baz/";
+ path[i++] = "/foo/bar/baz//";
+ path[i++] = "/foo/bar/baz/.";
+ path[i++] = "/foo/bar/baz/./";
+ path[i++] = "/foo/bar/../../baz/.//";
+ path[i++] = "foo/bar/./././././baz/";
+ path[i++] = "/foo/bar/baz/../../../../../../";
+ path[i++] = "/../../../../../../";
+ path[i++] = "/./";
+ path[i++] = "/foo/bar/baz/../../bop/bang/../../bar/baz/";
+ path[i++] = "./";
+ path[i++] = "//";
+ path[i++] = "/.";
+ path[i++] = "/./";
+ path[i++] = "/./.";
+ path[i++] = "/.//";
+ path[i++] = ".";
+ path[i++] = "/////";
+ path[i++] = "";
+
+ end = i;
+ i = 0;
+}
+
+tick-1ms
+/i < end/
+{
+ printf("cleanpath(\"%s\") = \"%s\"\n", path[i], cleanpath(path[i]));
+ i++;
+}
+
+tick-1ms
+/i == end/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.cleanpath.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.cleanpath.d.out
new file mode 100644
index 000000000000..b8bdc0991e27
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.cleanpath.d.out
@@ -0,0 +1,22 @@
+cleanpath("/foo/bar/baz") = "/foo/bar/baz"
+cleanpath("/foo/bar///baz/") = "/foo/bar/baz/"
+cleanpath("/foo/bar/baz/") = "/foo/bar/baz/"
+cleanpath("/foo/bar/baz//") = "/foo/bar/baz/"
+cleanpath("/foo/bar/baz/.") = "/foo/bar/baz/."
+cleanpath("/foo/bar/baz/./") = "/foo/bar/baz/"
+cleanpath("/foo/bar/../../baz/.//") = "/baz/"
+cleanpath("foo/bar/./././././baz/") = "foo/bar/baz/"
+cleanpath("/foo/bar/baz/../../../../../../") = "/"
+cleanpath("/../../../../../../") = "/"
+cleanpath("/./") = "/"
+cleanpath("/foo/bar/baz/../../bop/bang/../../bar/baz/") = "/foo/bar/baz/"
+cleanpath("./") = "./"
+cleanpath("//") = "/"
+cleanpath("/.") = "/."
+cleanpath("/./") = "/"
+cleanpath("/./.") = "/."
+cleanpath("/.//") = "/"
+cleanpath(".") = "."
+cleanpath("/////") = "/"
+cleanpath("") = ""
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.copyin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.copyin.d
new file mode 100644
index 000000000000..186b97419e82
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.copyin.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * This D ditty tests the ability to perform both copyin and copyinstr. We
+ * grab the value or pr_envp, read the first pointer from the user stack,
+ * and then copyinstr the first environment variable and print it.
+ *
+ * SECTION: Actions and Subroutines/copyin();
+ * Actions and Subroutines/copyinstr();
+ * User Process Tracing/copyin() and copyinstr()
+ */
+
+BEGIN
+/curpsinfo->pr_dmodel == PR_MODEL_ILP32/
+{
+ envp = *(uint32_t *)copyin(curpsinfo->pr_envp, sizeof (uint32_t));
+ printf("envp[0] = \"%s\"", copyinstr(envp));
+ exit(0);
+}
+
+BEGIN
+/curpsinfo->pr_dmodel == PR_MODEL_LP64/
+{
+ envp = *(uint64_t *)copyin(curpsinfo->pr_envp, sizeof (uint64_t));
+ printf("envp[0] = \"%s\"", copyinstr(envp));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.copyinto.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.copyinto.d
new file mode 100644
index 000000000000..c282e61dec47
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.copyinto.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * test copyinto by copying the first string of the user's
+ * environment.
+ *
+ * SECTION: Actions and Subroutines/copyinto()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+/curpsinfo->pr_dmodel == PR_MODEL_ILP32/
+{
+ envp = alloca(sizeof (uint32_t));
+ copyinto(curpsinfo->pr_envp, sizeof (uint32_t), envp);
+ printf("envp[0] = \"%s\"", copyinstr(*(uint32_t *)envp));
+ exit(0);
+}
+
+BEGIN
+/curpsinfo->pr_dmodel == PR_MODEL_LP64/
+{
+ envp = alloca(sizeof (uint64_t));
+ copyinto(curpsinfo->pr_envp, sizeof (uint64_t), envp);
+ printf("envp[0] = \"%s\"", copyinstr(*(uint64_t *)envp));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ddi_pathname.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ddi_pathname.d
new file mode 100644
index 000000000000..3716d0cef3ea
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ddi_pathname.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ this->dev = (struct dev_info *)alloca(sizeof (struct dev_info));
+ this->minor1 =
+ (struct ddi_minor_data *)alloca(sizeof (struct ddi_minor_data));
+ this->minor2 =
+ (struct ddi_minor_data *)alloca(sizeof (struct ddi_minor_data));
+ this->minor3 =
+ (struct ddi_minor_data *)alloca(sizeof (struct ddi_minor_data));
+
+ this->minor1->d_minor.dev = 0;
+ this->minor1->next = this->minor2;
+
+ this->minor2->d_minor.dev = 0;
+ this->minor2->next = this->minor3;
+
+ this->minor3->d_minor.dev = 0;
+ this->minor3->next = this->minor1;
+
+ this->dev->devi_minor = this->minor1;
+ trace(ddi_pathname(this->dev, 1));
+}
+
+ERROR
+/arg4 == DTRACEFLT_ILLOP/
+{
+ exit(0);
+}
+
+ERROR
+/arg4 != DTRACEFLT_ILLOP/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.default.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.default.d
new file mode 100644
index 000000000000..c4a4e4f3b343
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.default.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Verify that empty clauses are OK.
+ *
+ * SECTION: Actions and Subroutines/Default Action
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 1;
+
+}
+
+syscall:::entry
+{
+
+
+}
+
+tick-1
+/i != 0/
+{
+ exit(0);
+}
+
+
+END
+{
+
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.freopen.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.freopen.ksh
new file mode 100644
index 000000000000..f87d6e18fae5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.freopen.ksh
@@ -0,0 +1,111 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -wq -o $tmpfile -s /dev/stdin $tmpfile <<EOF
+ BEGIN
+ {
+ i = 0;
+ }
+
+ tick-10ms
+ {
+ freopen("%s.%d", \$\$1, i);
+ printf("%d\n", i)
+ }
+
+ tick-10ms
+ /++i == $iter/
+ {
+ freopen("");
+ printf("%d\n", i);
+ exit(0);
+ }
+EOF
+}
+
+cleanup()
+{
+ let i=0
+
+ if [ -f $tmpfile ]; then
+ rm $tmpfile
+ fi
+
+ while [ "$i" -lt "$iter" ]; do
+ if [ -f $tmpfile.$i ]; then
+ rm $tmpfile.$i
+ fi
+ let i=i+1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+tmpfile=/tmp/tst.freopen.$$
+iter=20
+
+script
+status=$?
+
+let i=0
+
+if [ -f $tmpfile.$iter ]; then
+ echo "$0: did not expect to find file: $tmpfile.$iter"
+ cleanup
+ exit 100
+fi
+
+mv $tmpfile $tmpfile.$iter
+let iter=iter+1
+
+while [ "$i" -lt "$iter" ]; do
+ if [ ! -f $tmpfile.$i ]; then
+ echo "$0: did not find expected file: $tmpfile.$i"
+ cleanup
+ exit 101
+ fi
+
+ j=`cat $tmpfile.$i`
+
+ if [ "$i" -ne "$j" ]; then
+ echo "$0: unexpected contents in $tmpfile.$i: " \
+ "expected $i, found $j"
+ cleanup
+ exit 102
+ fi
+
+ rm $tmpfile.$i
+ let i=i+1
+done
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ftruncate.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ftruncate.ksh
new file mode 100644
index 000000000000..b02af07b4a69
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ftruncate.ksh
@@ -0,0 +1,64 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -q -o $tmpfile -s /dev/stdin <<EOF
+ tick-10ms
+ {
+ printf("%d\n", i++);
+ }
+
+ tick-10ms
+ /i == 10/
+ {
+ ftruncate();
+ }
+
+ tick-10ms
+ /i == 20/
+ {
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+tmpfile=/tmp/tst.ftruncate.$$
+
+script
+status=$?
+
+cat $tmpfile
+rm $tmpfile
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ftruncate.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ftruncate.ksh.out
new file mode 100644
index 000000000000..3360fd26d24b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.ftruncate.ksh.out
@@ -0,0 +1,11 @@
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.hton.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.hton.d
new file mode 100644
index 000000000000..4908251a68e0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.hton.d
@@ -0,0 +1,99 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test network byte-ordering routines.
+ */
+
+#if defined(__amd64__) || defined(__i386__)
+#define _LITTLE_ENDIAN
+#endif
+
+BEGIN
+{
+ before[0] = 0x1122LL;
+ before[1] = 0x11223344LL;
+ before[2] = 0x1122334455667788LL;
+
+#ifdef _LITTLE_ENDIAN
+ after[0] = 0x2211LL;
+ after[1] = 0x44332211LL;
+ after[2] = 0x8877665544332211LL;
+#else
+ after[0] = 0x1122LL;
+ after[1] = 0x11223344LL;
+ after[2] = 0x1122334455667788LL;
+#endif
+}
+
+BEGIN
+/after[0] != htons(before[0])/
+{
+ printf("%x rather than %x", htons(before[0]), after[0]);
+ exit(1);
+}
+
+BEGIN
+/after[0] != ntohs(before[0])/
+{
+ printf("%x rather than %x", ntohs(before[0]), after[0]);
+ exit(1);
+}
+
+BEGIN
+/after[1] != htonl(before[1])/
+{
+ printf("%x rather than %x", htonl(before[1]), after[1]);
+ exit(1);
+}
+
+BEGIN
+/after[1] != ntohl(before[1])/
+{
+ printf("%x rather than %x", ntohl(before[1]), after[1]);
+ exit(1);
+}
+
+BEGIN
+/after[2] != htonll(before[2])/
+{
+ printf("%x rather than %x", htonll(before[2]), after[2]);
+ exit(1);
+}
+
+BEGIN
+/after[2] != ntohll(before[2])/
+{
+ printf("%x rather than %x", ntohll(before[2]), after[2]);
+ exit(1);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.index.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.index.d
new file mode 100644
index 000000000000..1ec96978ab18
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.index.d
@@ -0,0 +1,226 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+struct {
+ string str;
+ string substr;
+ int haspos;
+ int position;
+} command[int];
+
+int i;
+
+BEGIN
+{
+ command[i].str = "foobarbaz";
+ command[i].substr = "barbaz";
+ i++;
+
+ command[i].str = "foofoofoo";
+ command[i].substr = "foo";
+ i++;
+
+ command[i].str = "boofoofoo";
+ command[i].substr = "foo";
+ i++;
+
+ command[i].str = "foobarbaz";
+ command[i].substr = "barbazzy";
+ i++;
+
+ command[i].str = "foobar";
+ command[i].substr = "foobar";
+ i++;
+
+ command[i].str = "foobar";
+ command[i].substr = "foobarbaz";
+ i++;
+
+ command[i].str = "";
+ command[i].substr = "foobar";
+ i++;
+
+ command[i].str = "foobar";
+ command[i].substr = "";
+ i++;
+
+ command[i].str = "";
+ command[i].substr = "";
+ i++;
+
+ command[i].str = "foo";
+ command[i].substr = "";
+ i++;
+
+ end = j = k = 0;
+ printf("#!/usr/bin/perl\n\nBEGIN {\n");
+}
+
+tick-1ms
+/j < i && end == 0/
+{
+ command[i + k].str = command[j].str;
+ command[i + k].substr = command[j].substr;
+ command[i + k].haspos = 1;
+ command[i + k].position = -400;
+ k++;
+
+ command[i + k].str = command[j].str;
+ command[i + k].substr = command[j].substr;
+ command[i + k].haspos = 1;
+ command[i + k].position = -1;
+ k++;
+
+ command[i + k].str = command[j].str;
+ command[i + k].substr = command[j].substr;
+ command[i + k].haspos = 1;
+ command[i + k].position = 0;
+ k++;
+
+ command[i + k].str = command[j].str;
+ command[i + k].substr = command[j].substr;
+ command[i + k].haspos = 1;
+ command[i + k].position = strlen(command[j].str) / 2;
+ k++;
+
+ command[i + k].str = command[j].str;
+ command[i + k].substr = command[j].substr;
+ command[i + k].haspos = 1;
+ command[i + k].position = strlen(command[j].str);
+ k++;
+
+ command[i + k].str = command[j].str;
+ command[i + k].substr = command[j].substr;
+ command[i + k].haspos = 1;
+ command[i + k].position = strlen(command[j].str) + 1;
+ k++;
+
+ command[i + k].str = command[j].str;
+ command[i + k].substr = command[j].substr;
+ command[i + k].haspos = 1;
+ command[i + k].position = strlen(command[j].str) + 2;
+ k++;
+
+ command[i + k].str = command[j].str;
+ command[i + k].substr = command[j].substr;
+ command[i + k].haspos = 1;
+ command[i + k].position = 400;
+ k++;
+
+ j++;
+}
+
+tick-1ms
+/j == i && end == 0/
+{
+ end = k;
+ i = 0;
+}
+
+tick-1ms
+/end != 0 && i < end && !command[i].haspos/
+{
+ this->result = index(command[i].str, command[i].substr);
+
+ printf("\tif (index(\"%s\", \"%s\") != %d) {\n",
+ command[i].str, command[i].substr, this->result);
+ printf("\t\tprintf(\"perl => index(\\\"%s\\\", \\\"%s\\\") = ",
+ command[i].str, command[i].substr);
+ printf("%%d\\n\",\n\t\t index(\"%s\", \"%s\"));\n",
+ command[i].str, command[i].substr);
+ printf("\t\tprintf(\" D => index(\\\"%s\\\", \\\"%s\\\") = ",
+ command[i].str, command[i].substr);
+ printf("%d\\n\");\n", this->result);
+ printf("\t\t$failed++;\n");
+ printf("\t}\n\n");
+}
+
+tick-1ms
+/end != 0 && i < end && !command[i].haspos/
+{
+ this->result = rindex(command[i].str, command[i].substr);
+
+ printf("\tif (rindex(\"%s\", \"%s\") != %d) {\n",
+ command[i].str, command[i].substr, this->result);
+ printf("\t\tprintf(\"perl => rindex(\\\"%s\\\", \\\"%s\\\") = ",
+ command[i].str, command[i].substr);
+ printf("%%d\\n\",\n\t\t rindex(\"%s\", \"%s\"));\n",
+ command[i].str, command[i].substr);
+ printf("\t\tprintf(\" D => rindex(\\\"%s\\\", \\\"%s\\\") = ",
+ command[i].str, command[i].substr);
+ printf("%d\\n\");\n", this->result);
+ printf("\t\t$failed++;\n");
+ printf("\t}\n\n");
+}
+
+tick-1ms
+/end != 0 && i < end && command[i].haspos/
+{
+ this->result = index(command[i].str,
+ command[i].substr, command[i].position);
+
+ printf("\tif (index(\"%s\", \"%s\", %d) != %d) {\n", command[i].str,
+ command[i].substr, command[i].position, this->result);
+ printf("\t\tprintf(\"perl => index(\\\"%s\\\", \\\"%s\\\", %d) = ",
+ command[i].str, command[i].substr, command[i].position);
+ printf("%%d\\n\",\n\t\t index(\"%s\", \"%s\", %d));\n",
+ command[i].str, command[i].substr, command[i].position);
+ printf("\t\tprintf(\" D => index(\\\"%s\\\", \\\"%s\\\", %d) = ",
+ command[i].str, command[i].substr, command[i].position);
+ printf("%d\\n\");\n", this->result);
+ printf("\t\t$failed++;\n");
+ printf("\t}\n\n");
+}
+
+tick-1ms
+/end != 0 && i < end && command[i].haspos/
+{
+ this->result = rindex(command[i].str,
+ command[i].substr, command[i].position);
+
+ printf("\tif (rindex(\"%s\", \"%s\", %d) != %d) {\n", command[i].str,
+ command[i].substr, command[i].position, this->result);
+ printf("\t\tprintf(\"perl => rindex(\\\"%s\\\", \\\"%s\\\", %d) = ",
+ command[i].str, command[i].substr, command[i].position);
+ printf("%%d\\n\",\n\t\t rindex(\"%s\", \"%s\", %d));\n",
+ command[i].str, command[i].substr, command[i].position);
+ printf("\t\tprintf(\" D => rindex(\\\"%s\\\", \\\"%s\\\", %d) = ",
+ command[i].str, command[i].substr, command[i].position);
+ printf("%d\\n\");\n", this->result);
+ printf("\t\t$failed++;\n");
+ printf("\t}\n\n");
+}
+
+tick-1ms
+/end != 0 && ++i == end/
+{
+ printf("\texit($failed);\n}\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.index.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.index.d.out
new file mode 100644
index 000000000000..276576c26f7c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.index.d.out
@@ -0,0 +1,1126 @@
+#!/usr/perl5/bin/perl
+
+BEGIN {
+ if (index("foobarbaz", "barbaz") != 3) {
+ printf("perl => index(\"foobarbaz\", \"barbaz\") = %d\n",
+ index("foobarbaz", "barbaz"));
+ printf(" D => index(\"foobarbaz\", \"barbaz\") = 3\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbaz") != 3) {
+ printf("perl => rindex(\"foobarbaz\", \"barbaz\") = %d\n",
+ rindex("foobarbaz", "barbaz"));
+ printf(" D => rindex(\"foobarbaz\", \"barbaz\") = 3\n");
+ $failed++;
+ }
+
+ if (index("foofoofoo", "foo") != 0) {
+ printf("perl => index(\"foofoofoo\", \"foo\") = %d\n",
+ index("foofoofoo", "foo"));
+ printf(" D => index(\"foofoofoo\", \"foo\") = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foofoofoo", "foo") != 6) {
+ printf("perl => rindex(\"foofoofoo\", \"foo\") = %d\n",
+ rindex("foofoofoo", "foo"));
+ printf(" D => rindex(\"foofoofoo\", \"foo\") = 6\n");
+ $failed++;
+ }
+
+ if (index("boofoofoo", "foo") != 3) {
+ printf("perl => index(\"boofoofoo\", \"foo\") = %d\n",
+ index("boofoofoo", "foo"));
+ printf(" D => index(\"boofoofoo\", \"foo\") = 3\n");
+ $failed++;
+ }
+
+ if (rindex("boofoofoo", "foo") != 6) {
+ printf("perl => rindex(\"boofoofoo\", \"foo\") = %d\n",
+ rindex("boofoofoo", "foo"));
+ printf(" D => rindex(\"boofoofoo\", \"foo\") = 6\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbazzy") != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbazzy\") = %d\n",
+ index("foobarbaz", "barbazzy"));
+ printf(" D => index(\"foobarbaz\", \"barbazzy\") = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbazzy") != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbazzy\") = %d\n",
+ rindex("foobarbaz", "barbazzy"));
+ printf(" D => rindex(\"foobarbaz\", \"barbazzy\") = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobar") != 0) {
+ printf("perl => index(\"foobar\", \"foobar\") = %d\n",
+ index("foobar", "foobar"));
+ printf(" D => index(\"foobar\", \"foobar\") = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobar") != 0) {
+ printf("perl => rindex(\"foobar\", \"foobar\") = %d\n",
+ rindex("foobar", "foobar"));
+ printf(" D => rindex(\"foobar\", \"foobar\") = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobarbaz") != -1) {
+ printf("perl => index(\"foobar\", \"foobarbaz\") = %d\n",
+ index("foobar", "foobarbaz"));
+ printf(" D => index(\"foobar\", \"foobarbaz\") = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobarbaz") != -1) {
+ printf("perl => rindex(\"foobar\", \"foobarbaz\") = %d\n",
+ rindex("foobar", "foobarbaz"));
+ printf(" D => rindex(\"foobar\", \"foobarbaz\") = -1\n");
+ $failed++;
+ }
+
+ if (index("", "foobar") != -1) {
+ printf("perl => index(\"\", \"foobar\") = %d\n",
+ index("", "foobar"));
+ printf(" D => index(\"\", \"foobar\") = -1\n");
+ $failed++;
+ }
+
+ if (rindex("", "foobar") != -1) {
+ printf("perl => rindex(\"\", \"foobar\") = %d\n",
+ rindex("", "foobar"));
+ printf(" D => rindex(\"\", \"foobar\") = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "") != 0) {
+ printf("perl => index(\"foobar\", \"\") = %d\n",
+ index("foobar", ""));
+ printf(" D => index(\"foobar\", \"\") = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "") != 6) {
+ printf("perl => rindex(\"foobar\", \"\") = %d\n",
+ rindex("foobar", ""));
+ printf(" D => rindex(\"foobar\", \"\") = 6\n");
+ $failed++;
+ }
+
+ if (index("", "") != 0) {
+ printf("perl => index(\"\", \"\") = %d\n",
+ index("", ""));
+ printf(" D => index(\"\", \"\") = 0\n");
+ $failed++;
+ }
+
+ if (rindex("", "") != 0) {
+ printf("perl => rindex(\"\", \"\") = %d\n",
+ rindex("", ""));
+ printf(" D => rindex(\"\", \"\") = 0\n");
+ $failed++;
+ }
+
+ if (index("foo", "") != 0) {
+ printf("perl => index(\"foo\", \"\") = %d\n",
+ index("foo", ""));
+ printf(" D => index(\"foo\", \"\") = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foo", "") != 3) {
+ printf("perl => rindex(\"foo\", \"\") = %d\n",
+ rindex("foo", ""));
+ printf(" D => rindex(\"foo\", \"\") = 3\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbaz", -400) != 3) {
+ printf("perl => index(\"foobarbaz\", \"barbaz\", -400) = %d\n",
+ index("foobarbaz", "barbaz", -400));
+ printf(" D => index(\"foobarbaz\", \"barbaz\", -400) = 3\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbaz", -400) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbaz\", -400) = %d\n",
+ rindex("foobarbaz", "barbaz", -400));
+ printf(" D => rindex(\"foobarbaz\", \"barbaz\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbaz", -1) != 3) {
+ printf("perl => index(\"foobarbaz\", \"barbaz\", -1) = %d\n",
+ index("foobarbaz", "barbaz", -1));
+ printf(" D => index(\"foobarbaz\", \"barbaz\", -1) = 3\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbaz", -1) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbaz\", -1) = %d\n",
+ rindex("foobarbaz", "barbaz", -1));
+ printf(" D => rindex(\"foobarbaz\", \"barbaz\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbaz", 0) != 3) {
+ printf("perl => index(\"foobarbaz\", \"barbaz\", 0) = %d\n",
+ index("foobarbaz", "barbaz", 0));
+ printf(" D => index(\"foobarbaz\", \"barbaz\", 0) = 3\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbaz", 0) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbaz\", 0) = %d\n",
+ rindex("foobarbaz", "barbaz", 0));
+ printf(" D => rindex(\"foobarbaz\", \"barbaz\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbaz", 4) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbaz\", 4) = %d\n",
+ index("foobarbaz", "barbaz", 4));
+ printf(" D => index(\"foobarbaz\", \"barbaz\", 4) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbaz", 4) != 3) {
+ printf("perl => rindex(\"foobarbaz\", \"barbaz\", 4) = %d\n",
+ rindex("foobarbaz", "barbaz", 4));
+ printf(" D => rindex(\"foobarbaz\", \"barbaz\", 4) = 3\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbaz", 9) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbaz\", 9) = %d\n",
+ index("foobarbaz", "barbaz", 9));
+ printf(" D => index(\"foobarbaz\", \"barbaz\", 9) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbaz", 9) != 3) {
+ printf("perl => rindex(\"foobarbaz\", \"barbaz\", 9) = %d\n",
+ rindex("foobarbaz", "barbaz", 9));
+ printf(" D => rindex(\"foobarbaz\", \"barbaz\", 9) = 3\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbaz", 10) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbaz\", 10) = %d\n",
+ index("foobarbaz", "barbaz", 10));
+ printf(" D => index(\"foobarbaz\", \"barbaz\", 10) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbaz", 10) != 3) {
+ printf("perl => rindex(\"foobarbaz\", \"barbaz\", 10) = %d\n",
+ rindex("foobarbaz", "barbaz", 10));
+ printf(" D => rindex(\"foobarbaz\", \"barbaz\", 10) = 3\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbaz", 11) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbaz\", 11) = %d\n",
+ index("foobarbaz", "barbaz", 11));
+ printf(" D => index(\"foobarbaz\", \"barbaz\", 11) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbaz", 11) != 3) {
+ printf("perl => rindex(\"foobarbaz\", \"barbaz\", 11) = %d\n",
+ rindex("foobarbaz", "barbaz", 11));
+ printf(" D => rindex(\"foobarbaz\", \"barbaz\", 11) = 3\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbaz", 400) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbaz\", 400) = %d\n",
+ index("foobarbaz", "barbaz", 400));
+ printf(" D => index(\"foobarbaz\", \"barbaz\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbaz", 400) != 3) {
+ printf("perl => rindex(\"foobarbaz\", \"barbaz\", 400) = %d\n",
+ rindex("foobarbaz", "barbaz", 400));
+ printf(" D => rindex(\"foobarbaz\", \"barbaz\", 400) = 3\n");
+ $failed++;
+ }
+
+ if (index("foofoofoo", "foo", -400) != 0) {
+ printf("perl => index(\"foofoofoo\", \"foo\", -400) = %d\n",
+ index("foofoofoo", "foo", -400));
+ printf(" D => index(\"foofoofoo\", \"foo\", -400) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foofoofoo", "foo", -400) != -1) {
+ printf("perl => rindex(\"foofoofoo\", \"foo\", -400) = %d\n",
+ rindex("foofoofoo", "foo", -400));
+ printf(" D => rindex(\"foofoofoo\", \"foo\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (index("foofoofoo", "foo", -1) != 0) {
+ printf("perl => index(\"foofoofoo\", \"foo\", -1) = %d\n",
+ index("foofoofoo", "foo", -1));
+ printf(" D => index(\"foofoofoo\", \"foo\", -1) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foofoofoo", "foo", -1) != -1) {
+ printf("perl => rindex(\"foofoofoo\", \"foo\", -1) = %d\n",
+ rindex("foofoofoo", "foo", -1));
+ printf(" D => rindex(\"foofoofoo\", \"foo\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (index("foofoofoo", "foo", 0) != 0) {
+ printf("perl => index(\"foofoofoo\", \"foo\", 0) = %d\n",
+ index("foofoofoo", "foo", 0));
+ printf(" D => index(\"foofoofoo\", \"foo\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foofoofoo", "foo", 0) != 0) {
+ printf("perl => rindex(\"foofoofoo\", \"foo\", 0) = %d\n",
+ rindex("foofoofoo", "foo", 0));
+ printf(" D => rindex(\"foofoofoo\", \"foo\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (index("foofoofoo", "foo", 4) != 6) {
+ printf("perl => index(\"foofoofoo\", \"foo\", 4) = %d\n",
+ index("foofoofoo", "foo", 4));
+ printf(" D => index(\"foofoofoo\", \"foo\", 4) = 6\n");
+ $failed++;
+ }
+
+ if (rindex("foofoofoo", "foo", 4) != 3) {
+ printf("perl => rindex(\"foofoofoo\", \"foo\", 4) = %d\n",
+ rindex("foofoofoo", "foo", 4));
+ printf(" D => rindex(\"foofoofoo\", \"foo\", 4) = 3\n");
+ $failed++;
+ }
+
+ if (index("foofoofoo", "foo", 9) != -1) {
+ printf("perl => index(\"foofoofoo\", \"foo\", 9) = %d\n",
+ index("foofoofoo", "foo", 9));
+ printf(" D => index(\"foofoofoo\", \"foo\", 9) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foofoofoo", "foo", 9) != 6) {
+ printf("perl => rindex(\"foofoofoo\", \"foo\", 9) = %d\n",
+ rindex("foofoofoo", "foo", 9));
+ printf(" D => rindex(\"foofoofoo\", \"foo\", 9) = 6\n");
+ $failed++;
+ }
+
+ if (index("foofoofoo", "foo", 10) != -1) {
+ printf("perl => index(\"foofoofoo\", \"foo\", 10) = %d\n",
+ index("foofoofoo", "foo", 10));
+ printf(" D => index(\"foofoofoo\", \"foo\", 10) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foofoofoo", "foo", 10) != 6) {
+ printf("perl => rindex(\"foofoofoo\", \"foo\", 10) = %d\n",
+ rindex("foofoofoo", "foo", 10));
+ printf(" D => rindex(\"foofoofoo\", \"foo\", 10) = 6\n");
+ $failed++;
+ }
+
+ if (index("foofoofoo", "foo", 11) != -1) {
+ printf("perl => index(\"foofoofoo\", \"foo\", 11) = %d\n",
+ index("foofoofoo", "foo", 11));
+ printf(" D => index(\"foofoofoo\", \"foo\", 11) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foofoofoo", "foo", 11) != 6) {
+ printf("perl => rindex(\"foofoofoo\", \"foo\", 11) = %d\n",
+ rindex("foofoofoo", "foo", 11));
+ printf(" D => rindex(\"foofoofoo\", \"foo\", 11) = 6\n");
+ $failed++;
+ }
+
+ if (index("foofoofoo", "foo", 400) != -1) {
+ printf("perl => index(\"foofoofoo\", \"foo\", 400) = %d\n",
+ index("foofoofoo", "foo", 400));
+ printf(" D => index(\"foofoofoo\", \"foo\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foofoofoo", "foo", 400) != 6) {
+ printf("perl => rindex(\"foofoofoo\", \"foo\", 400) = %d\n",
+ rindex("foofoofoo", "foo", 400));
+ printf(" D => rindex(\"foofoofoo\", \"foo\", 400) = 6\n");
+ $failed++;
+ }
+
+ if (index("boofoofoo", "foo", -400) != 3) {
+ printf("perl => index(\"boofoofoo\", \"foo\", -400) = %d\n",
+ index("boofoofoo", "foo", -400));
+ printf(" D => index(\"boofoofoo\", \"foo\", -400) = 3\n");
+ $failed++;
+ }
+
+ if (rindex("boofoofoo", "foo", -400) != -1) {
+ printf("perl => rindex(\"boofoofoo\", \"foo\", -400) = %d\n",
+ rindex("boofoofoo", "foo", -400));
+ printf(" D => rindex(\"boofoofoo\", \"foo\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (index("boofoofoo", "foo", -1) != 3) {
+ printf("perl => index(\"boofoofoo\", \"foo\", -1) = %d\n",
+ index("boofoofoo", "foo", -1));
+ printf(" D => index(\"boofoofoo\", \"foo\", -1) = 3\n");
+ $failed++;
+ }
+
+ if (rindex("boofoofoo", "foo", -1) != -1) {
+ printf("perl => rindex(\"boofoofoo\", \"foo\", -1) = %d\n",
+ rindex("boofoofoo", "foo", -1));
+ printf(" D => rindex(\"boofoofoo\", \"foo\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (index("boofoofoo", "foo", 0) != 3) {
+ printf("perl => index(\"boofoofoo\", \"foo\", 0) = %d\n",
+ index("boofoofoo", "foo", 0));
+ printf(" D => index(\"boofoofoo\", \"foo\", 0) = 3\n");
+ $failed++;
+ }
+
+ if (rindex("boofoofoo", "foo", 0) != -1) {
+ printf("perl => rindex(\"boofoofoo\", \"foo\", 0) = %d\n",
+ rindex("boofoofoo", "foo", 0));
+ printf(" D => rindex(\"boofoofoo\", \"foo\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (index("boofoofoo", "foo", 4) != 6) {
+ printf("perl => index(\"boofoofoo\", \"foo\", 4) = %d\n",
+ index("boofoofoo", "foo", 4));
+ printf(" D => index(\"boofoofoo\", \"foo\", 4) = 6\n");
+ $failed++;
+ }
+
+ if (rindex("boofoofoo", "foo", 4) != 3) {
+ printf("perl => rindex(\"boofoofoo\", \"foo\", 4) = %d\n",
+ rindex("boofoofoo", "foo", 4));
+ printf(" D => rindex(\"boofoofoo\", \"foo\", 4) = 3\n");
+ $failed++;
+ }
+
+ if (index("boofoofoo", "foo", 9) != -1) {
+ printf("perl => index(\"boofoofoo\", \"foo\", 9) = %d\n",
+ index("boofoofoo", "foo", 9));
+ printf(" D => index(\"boofoofoo\", \"foo\", 9) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("boofoofoo", "foo", 9) != 6) {
+ printf("perl => rindex(\"boofoofoo\", \"foo\", 9) = %d\n",
+ rindex("boofoofoo", "foo", 9));
+ printf(" D => rindex(\"boofoofoo\", \"foo\", 9) = 6\n");
+ $failed++;
+ }
+
+ if (index("boofoofoo", "foo", 10) != -1) {
+ printf("perl => index(\"boofoofoo\", \"foo\", 10) = %d\n",
+ index("boofoofoo", "foo", 10));
+ printf(" D => index(\"boofoofoo\", \"foo\", 10) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("boofoofoo", "foo", 10) != 6) {
+ printf("perl => rindex(\"boofoofoo\", \"foo\", 10) = %d\n",
+ rindex("boofoofoo", "foo", 10));
+ printf(" D => rindex(\"boofoofoo\", \"foo\", 10) = 6\n");
+ $failed++;
+ }
+
+ if (index("boofoofoo", "foo", 11) != -1) {
+ printf("perl => index(\"boofoofoo\", \"foo\", 11) = %d\n",
+ index("boofoofoo", "foo", 11));
+ printf(" D => index(\"boofoofoo\", \"foo\", 11) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("boofoofoo", "foo", 11) != 6) {
+ printf("perl => rindex(\"boofoofoo\", \"foo\", 11) = %d\n",
+ rindex("boofoofoo", "foo", 11));
+ printf(" D => rindex(\"boofoofoo\", \"foo\", 11) = 6\n");
+ $failed++;
+ }
+
+ if (index("boofoofoo", "foo", 400) != -1) {
+ printf("perl => index(\"boofoofoo\", \"foo\", 400) = %d\n",
+ index("boofoofoo", "foo", 400));
+ printf(" D => index(\"boofoofoo\", \"foo\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("boofoofoo", "foo", 400) != 6) {
+ printf("perl => rindex(\"boofoofoo\", \"foo\", 400) = %d\n",
+ rindex("boofoofoo", "foo", 400));
+ printf(" D => rindex(\"boofoofoo\", \"foo\", 400) = 6\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbazzy", -400) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbazzy\", -400) = %d\n",
+ index("foobarbaz", "barbazzy", -400));
+ printf(" D => index(\"foobarbaz\", \"barbazzy\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbazzy", -400) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbazzy\", -400) = %d\n",
+ rindex("foobarbaz", "barbazzy", -400));
+ printf(" D => rindex(\"foobarbaz\", \"barbazzy\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbazzy", -1) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbazzy\", -1) = %d\n",
+ index("foobarbaz", "barbazzy", -1));
+ printf(" D => index(\"foobarbaz\", \"barbazzy\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbazzy", -1) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbazzy\", -1) = %d\n",
+ rindex("foobarbaz", "barbazzy", -1));
+ printf(" D => rindex(\"foobarbaz\", \"barbazzy\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbazzy", 0) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbazzy\", 0) = %d\n",
+ index("foobarbaz", "barbazzy", 0));
+ printf(" D => index(\"foobarbaz\", \"barbazzy\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbazzy", 0) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbazzy\", 0) = %d\n",
+ rindex("foobarbaz", "barbazzy", 0));
+ printf(" D => rindex(\"foobarbaz\", \"barbazzy\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbazzy", 4) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbazzy\", 4) = %d\n",
+ index("foobarbaz", "barbazzy", 4));
+ printf(" D => index(\"foobarbaz\", \"barbazzy\", 4) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbazzy", 4) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbazzy\", 4) = %d\n",
+ rindex("foobarbaz", "barbazzy", 4));
+ printf(" D => rindex(\"foobarbaz\", \"barbazzy\", 4) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbazzy", 9) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbazzy\", 9) = %d\n",
+ index("foobarbaz", "barbazzy", 9));
+ printf(" D => index(\"foobarbaz\", \"barbazzy\", 9) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbazzy", 9) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbazzy\", 9) = %d\n",
+ rindex("foobarbaz", "barbazzy", 9));
+ printf(" D => rindex(\"foobarbaz\", \"barbazzy\", 9) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbazzy", 10) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbazzy\", 10) = %d\n",
+ index("foobarbaz", "barbazzy", 10));
+ printf(" D => index(\"foobarbaz\", \"barbazzy\", 10) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbazzy", 10) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbazzy\", 10) = %d\n",
+ rindex("foobarbaz", "barbazzy", 10));
+ printf(" D => rindex(\"foobarbaz\", \"barbazzy\", 10) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbazzy", 11) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbazzy\", 11) = %d\n",
+ index("foobarbaz", "barbazzy", 11));
+ printf(" D => index(\"foobarbaz\", \"barbazzy\", 11) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbazzy", 11) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbazzy\", 11) = %d\n",
+ rindex("foobarbaz", "barbazzy", 11));
+ printf(" D => rindex(\"foobarbaz\", \"barbazzy\", 11) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobarbaz", "barbazzy", 400) != -1) {
+ printf("perl => index(\"foobarbaz\", \"barbazzy\", 400) = %d\n",
+ index("foobarbaz", "barbazzy", 400));
+ printf(" D => index(\"foobarbaz\", \"barbazzy\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobarbaz", "barbazzy", 400) != -1) {
+ printf("perl => rindex(\"foobarbaz\", \"barbazzy\", 400) = %d\n",
+ rindex("foobarbaz", "barbazzy", 400));
+ printf(" D => rindex(\"foobarbaz\", \"barbazzy\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobar", -400) != 0) {
+ printf("perl => index(\"foobar\", \"foobar\", -400) = %d\n",
+ index("foobar", "foobar", -400));
+ printf(" D => index(\"foobar\", \"foobar\", -400) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobar", -400) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobar\", -400) = %d\n",
+ rindex("foobar", "foobar", -400));
+ printf(" D => rindex(\"foobar\", \"foobar\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobar", -1) != 0) {
+ printf("perl => index(\"foobar\", \"foobar\", -1) = %d\n",
+ index("foobar", "foobar", -1));
+ printf(" D => index(\"foobar\", \"foobar\", -1) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobar", -1) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobar\", -1) = %d\n",
+ rindex("foobar", "foobar", -1));
+ printf(" D => rindex(\"foobar\", \"foobar\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobar", 0) != 0) {
+ printf("perl => index(\"foobar\", \"foobar\", 0) = %d\n",
+ index("foobar", "foobar", 0));
+ printf(" D => index(\"foobar\", \"foobar\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobar", 0) != 0) {
+ printf("perl => rindex(\"foobar\", \"foobar\", 0) = %d\n",
+ rindex("foobar", "foobar", 0));
+ printf(" D => rindex(\"foobar\", \"foobar\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobar", 3) != -1) {
+ printf("perl => index(\"foobar\", \"foobar\", 3) = %d\n",
+ index("foobar", "foobar", 3));
+ printf(" D => index(\"foobar\", \"foobar\", 3) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobar", 3) != 0) {
+ printf("perl => rindex(\"foobar\", \"foobar\", 3) = %d\n",
+ rindex("foobar", "foobar", 3));
+ printf(" D => rindex(\"foobar\", \"foobar\", 3) = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobar", 6) != -1) {
+ printf("perl => index(\"foobar\", \"foobar\", 6) = %d\n",
+ index("foobar", "foobar", 6));
+ printf(" D => index(\"foobar\", \"foobar\", 6) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobar", 6) != 0) {
+ printf("perl => rindex(\"foobar\", \"foobar\", 6) = %d\n",
+ rindex("foobar", "foobar", 6));
+ printf(" D => rindex(\"foobar\", \"foobar\", 6) = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobar", 7) != -1) {
+ printf("perl => index(\"foobar\", \"foobar\", 7) = %d\n",
+ index("foobar", "foobar", 7));
+ printf(" D => index(\"foobar\", \"foobar\", 7) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobar", 7) != 0) {
+ printf("perl => rindex(\"foobar\", \"foobar\", 7) = %d\n",
+ rindex("foobar", "foobar", 7));
+ printf(" D => rindex(\"foobar\", \"foobar\", 7) = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobar", 8) != -1) {
+ printf("perl => index(\"foobar\", \"foobar\", 8) = %d\n",
+ index("foobar", "foobar", 8));
+ printf(" D => index(\"foobar\", \"foobar\", 8) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobar", 8) != 0) {
+ printf("perl => rindex(\"foobar\", \"foobar\", 8) = %d\n",
+ rindex("foobar", "foobar", 8));
+ printf(" D => rindex(\"foobar\", \"foobar\", 8) = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobar", 400) != -1) {
+ printf("perl => index(\"foobar\", \"foobar\", 400) = %d\n",
+ index("foobar", "foobar", 400));
+ printf(" D => index(\"foobar\", \"foobar\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobar", 400) != 0) {
+ printf("perl => rindex(\"foobar\", \"foobar\", 400) = %d\n",
+ rindex("foobar", "foobar", 400));
+ printf(" D => rindex(\"foobar\", \"foobar\", 400) = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobarbaz", -400) != -1) {
+ printf("perl => index(\"foobar\", \"foobarbaz\", -400) = %d\n",
+ index("foobar", "foobarbaz", -400));
+ printf(" D => index(\"foobar\", \"foobarbaz\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobarbaz", -400) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobarbaz\", -400) = %d\n",
+ rindex("foobar", "foobarbaz", -400));
+ printf(" D => rindex(\"foobar\", \"foobarbaz\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobarbaz", -1) != -1) {
+ printf("perl => index(\"foobar\", \"foobarbaz\", -1) = %d\n",
+ index("foobar", "foobarbaz", -1));
+ printf(" D => index(\"foobar\", \"foobarbaz\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobarbaz", -1) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobarbaz\", -1) = %d\n",
+ rindex("foobar", "foobarbaz", -1));
+ printf(" D => rindex(\"foobar\", \"foobarbaz\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobarbaz", 0) != -1) {
+ printf("perl => index(\"foobar\", \"foobarbaz\", 0) = %d\n",
+ index("foobar", "foobarbaz", 0));
+ printf(" D => index(\"foobar\", \"foobarbaz\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobarbaz", 0) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobarbaz\", 0) = %d\n",
+ rindex("foobar", "foobarbaz", 0));
+ printf(" D => rindex(\"foobar\", \"foobarbaz\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobarbaz", 3) != -1) {
+ printf("perl => index(\"foobar\", \"foobarbaz\", 3) = %d\n",
+ index("foobar", "foobarbaz", 3));
+ printf(" D => index(\"foobar\", \"foobarbaz\", 3) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobarbaz", 3) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobarbaz\", 3) = %d\n",
+ rindex("foobar", "foobarbaz", 3));
+ printf(" D => rindex(\"foobar\", \"foobarbaz\", 3) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobarbaz", 6) != -1) {
+ printf("perl => index(\"foobar\", \"foobarbaz\", 6) = %d\n",
+ index("foobar", "foobarbaz", 6));
+ printf(" D => index(\"foobar\", \"foobarbaz\", 6) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobarbaz", 6) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobarbaz\", 6) = %d\n",
+ rindex("foobar", "foobarbaz", 6));
+ printf(" D => rindex(\"foobar\", \"foobarbaz\", 6) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobarbaz", 7) != -1) {
+ printf("perl => index(\"foobar\", \"foobarbaz\", 7) = %d\n",
+ index("foobar", "foobarbaz", 7));
+ printf(" D => index(\"foobar\", \"foobarbaz\", 7) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobarbaz", 7) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobarbaz\", 7) = %d\n",
+ rindex("foobar", "foobarbaz", 7));
+ printf(" D => rindex(\"foobar\", \"foobarbaz\", 7) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobarbaz", 8) != -1) {
+ printf("perl => index(\"foobar\", \"foobarbaz\", 8) = %d\n",
+ index("foobar", "foobarbaz", 8));
+ printf(" D => index(\"foobar\", \"foobarbaz\", 8) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobarbaz", 8) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobarbaz\", 8) = %d\n",
+ rindex("foobar", "foobarbaz", 8));
+ printf(" D => rindex(\"foobar\", \"foobarbaz\", 8) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "foobarbaz", 400) != -1) {
+ printf("perl => index(\"foobar\", \"foobarbaz\", 400) = %d\n",
+ index("foobar", "foobarbaz", 400));
+ printf(" D => index(\"foobar\", \"foobarbaz\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "foobarbaz", 400) != -1) {
+ printf("perl => rindex(\"foobar\", \"foobarbaz\", 400) = %d\n",
+ rindex("foobar", "foobarbaz", 400));
+ printf(" D => rindex(\"foobar\", \"foobarbaz\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (index("", "foobar", -400) != -1) {
+ printf("perl => index(\"\", \"foobar\", -400) = %d\n",
+ index("", "foobar", -400));
+ printf(" D => index(\"\", \"foobar\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("", "foobar", -400) != -1) {
+ printf("perl => rindex(\"\", \"foobar\", -400) = %d\n",
+ rindex("", "foobar", -400));
+ printf(" D => rindex(\"\", \"foobar\", -400) = -1\n");
+ $failed++;
+ }
+
+ if (index("", "foobar", -1) != -1) {
+ printf("perl => index(\"\", \"foobar\", -1) = %d\n",
+ index("", "foobar", -1));
+ printf(" D => index(\"\", \"foobar\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("", "foobar", -1) != -1) {
+ printf("perl => rindex(\"\", \"foobar\", -1) = %d\n",
+ rindex("", "foobar", -1));
+ printf(" D => rindex(\"\", \"foobar\", -1) = -1\n");
+ $failed++;
+ }
+
+ if (index("", "foobar", 0) != -1) {
+ printf("perl => index(\"\", \"foobar\", 0) = %d\n",
+ index("", "foobar", 0));
+ printf(" D => index(\"\", \"foobar\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("", "foobar", 0) != -1) {
+ printf("perl => rindex(\"\", \"foobar\", 0) = %d\n",
+ rindex("", "foobar", 0));
+ printf(" D => rindex(\"\", \"foobar\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (index("", "foobar", 0) != -1) {
+ printf("perl => index(\"\", \"foobar\", 0) = %d\n",
+ index("", "foobar", 0));
+ printf(" D => index(\"\", \"foobar\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("", "foobar", 0) != -1) {
+ printf("perl => rindex(\"\", \"foobar\", 0) = %d\n",
+ rindex("", "foobar", 0));
+ printf(" D => rindex(\"\", \"foobar\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (index("", "foobar", 0) != -1) {
+ printf("perl => index(\"\", \"foobar\", 0) = %d\n",
+ index("", "foobar", 0));
+ printf(" D => index(\"\", \"foobar\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("", "foobar", 0) != -1) {
+ printf("perl => rindex(\"\", \"foobar\", 0) = %d\n",
+ rindex("", "foobar", 0));
+ printf(" D => rindex(\"\", \"foobar\", 0) = -1\n");
+ $failed++;
+ }
+
+ if (index("", "foobar", 1) != -1) {
+ printf("perl => index(\"\", \"foobar\", 1) = %d\n",
+ index("", "foobar", 1));
+ printf(" D => index(\"\", \"foobar\", 1) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("", "foobar", 1) != -1) {
+ printf("perl => rindex(\"\", \"foobar\", 1) = %d\n",
+ rindex("", "foobar", 1));
+ printf(" D => rindex(\"\", \"foobar\", 1) = -1\n");
+ $failed++;
+ }
+
+ if (index("", "foobar", 2) != -1) {
+ printf("perl => index(\"\", \"foobar\", 2) = %d\n",
+ index("", "foobar", 2));
+ printf(" D => index(\"\", \"foobar\", 2) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("", "foobar", 2) != -1) {
+ printf("perl => rindex(\"\", \"foobar\", 2) = %d\n",
+ rindex("", "foobar", 2));
+ printf(" D => rindex(\"\", \"foobar\", 2) = -1\n");
+ $failed++;
+ }
+
+ if (index("", "foobar", 400) != -1) {
+ printf("perl => index(\"\", \"foobar\", 400) = %d\n",
+ index("", "foobar", 400));
+ printf(" D => index(\"\", \"foobar\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (rindex("", "foobar", 400) != -1) {
+ printf("perl => rindex(\"\", \"foobar\", 400) = %d\n",
+ rindex("", "foobar", 400));
+ printf(" D => rindex(\"\", \"foobar\", 400) = -1\n");
+ $failed++;
+ }
+
+ if (index("foobar", "", -400) != 0) {
+ printf("perl => index(\"foobar\", \"\", -400) = %d\n",
+ index("foobar", "", -400));
+ printf(" D => index(\"foobar\", \"\", -400) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "", -400) != 0) {
+ printf("perl => rindex(\"foobar\", \"\", -400) = %d\n",
+ rindex("foobar", "", -400));
+ printf(" D => rindex(\"foobar\", \"\", -400) = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "", -1) != 0) {
+ printf("perl => index(\"foobar\", \"\", -1) = %d\n",
+ index("foobar", "", -1));
+ printf(" D => index(\"foobar\", \"\", -1) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "", -1) != 0) {
+ printf("perl => rindex(\"foobar\", \"\", -1) = %d\n",
+ rindex("foobar", "", -1));
+ printf(" D => rindex(\"foobar\", \"\", -1) = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "", 0) != 0) {
+ printf("perl => index(\"foobar\", \"\", 0) = %d\n",
+ index("foobar", "", 0));
+ printf(" D => index(\"foobar\", \"\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "", 0) != 0) {
+ printf("perl => rindex(\"foobar\", \"\", 0) = %d\n",
+ rindex("foobar", "", 0));
+ printf(" D => rindex(\"foobar\", \"\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (index("foobar", "", 3) != 3) {
+ printf("perl => index(\"foobar\", \"\", 3) = %d\n",
+ index("foobar", "", 3));
+ printf(" D => index(\"foobar\", \"\", 3) = 3\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "", 3) != 3) {
+ printf("perl => rindex(\"foobar\", \"\", 3) = %d\n",
+ rindex("foobar", "", 3));
+ printf(" D => rindex(\"foobar\", \"\", 3) = 3\n");
+ $failed++;
+ }
+
+ if (index("foobar", "", 6) != 6) {
+ printf("perl => index(\"foobar\", \"\", 6) = %d\n",
+ index("foobar", "", 6));
+ printf(" D => index(\"foobar\", \"\", 6) = 6\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "", 6) != 6) {
+ printf("perl => rindex(\"foobar\", \"\", 6) = %d\n",
+ rindex("foobar", "", 6));
+ printf(" D => rindex(\"foobar\", \"\", 6) = 6\n");
+ $failed++;
+ }
+
+ if (index("foobar", "", 7) != 6) {
+ printf("perl => index(\"foobar\", \"\", 7) = %d\n",
+ index("foobar", "", 7));
+ printf(" D => index(\"foobar\", \"\", 7) = 6\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "", 7) != 6) {
+ printf("perl => rindex(\"foobar\", \"\", 7) = %d\n",
+ rindex("foobar", "", 7));
+ printf(" D => rindex(\"foobar\", \"\", 7) = 6\n");
+ $failed++;
+ }
+
+ if (index("foobar", "", 8) != 6) {
+ printf("perl => index(\"foobar\", \"\", 8) = %d\n",
+ index("foobar", "", 8));
+ printf(" D => index(\"foobar\", \"\", 8) = 6\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "", 8) != 6) {
+ printf("perl => rindex(\"foobar\", \"\", 8) = %d\n",
+ rindex("foobar", "", 8));
+ printf(" D => rindex(\"foobar\", \"\", 8) = 6\n");
+ $failed++;
+ }
+
+ if (index("foobar", "", 400) != 6) {
+ printf("perl => index(\"foobar\", \"\", 400) = %d\n",
+ index("foobar", "", 400));
+ printf(" D => index(\"foobar\", \"\", 400) = 6\n");
+ $failed++;
+ }
+
+ if (rindex("foobar", "", 400) != 6) {
+ printf("perl => rindex(\"foobar\", \"\", 400) = %d\n",
+ rindex("foobar", "", 400));
+ printf(" D => rindex(\"foobar\", \"\", 400) = 6\n");
+ $failed++;
+ }
+
+ if (index("", "", -400) != 0) {
+ printf("perl => index(\"\", \"\", -400) = %d\n",
+ index("", "", -400));
+ printf(" D => index(\"\", \"\", -400) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("", "", -400) != 0) {
+ printf("perl => rindex(\"\", \"\", -400) = %d\n",
+ rindex("", "", -400));
+ printf(" D => rindex(\"\", \"\", -400) = 0\n");
+ $failed++;
+ }
+
+ if (index("", "", -1) != 0) {
+ printf("perl => index(\"\", \"\", -1) = %d\n",
+ index("", "", -1));
+ printf(" D => index(\"\", \"\", -1) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("", "", -1) != 0) {
+ printf("perl => rindex(\"\", \"\", -1) = %d\n",
+ rindex("", "", -1));
+ printf(" D => rindex(\"\", \"\", -1) = 0\n");
+ $failed++;
+ }
+
+ if (index("", "", 0) != 0) {
+ printf("perl => index(\"\", \"\", 0) = %d\n",
+ index("", "", 0));
+ printf(" D => index(\"\", \"\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("", "", 0) != 0) {
+ printf("perl => rindex(\"\", \"\", 0) = %d\n",
+ rindex("", "", 0));
+ printf(" D => rindex(\"\", \"\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (index("", "", 0) != 0) {
+ printf("perl => index(\"\", \"\", 0) = %d\n",
+ index("", "", 0));
+ printf(" D => index(\"\", \"\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("", "", 0) != 0) {
+ printf("perl => rindex(\"\", \"\", 0) = %d\n",
+ rindex("", "", 0));
+ printf(" D => rindex(\"\", \"\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (index("", "", 0) != 0) {
+ printf("perl => index(\"\", \"\", 0) = %d\n",
+ index("", "", 0));
+ printf(" D => index(\"\", \"\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("", "", 0) != 0) {
+ printf("perl => rindex(\"\", \"\", 0) = %d\n",
+ rindex("", "", 0));
+ printf(" D => rindex(\"\", \"\", 0) = 0\n");
+ $failed++;
+ }
+
+ if (index("", "", 1) != 0) {
+ printf("perl => index(\"\", \"\", 1) = %d\n",
+ index("", "", 1));
+ printf(" D => index(\"\", \"\", 1) = 0\n");
+ $failed++;
+ }
+
+ if (rindex("", "", 1) != 0) {
+ printf("perl => rindex(\"\", \"\", 1) = %d\n",
+ rindex("", "", 1));
+ printf(" D => rindex(\"\", \"\", 1) = 0\n");
+ $failed++;
+ }
+
+ exit($failed);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa.d
new file mode 100644
index 000000000000..fbc56203d5e6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa.d
@@ -0,0 +1,58 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+in_addr_t *ip4a;
+in_addr_t *ip4b;
+in_addr_t *ip4c;
+in_addr_t *ip4d;
+
+BEGIN
+{
+ this->buf4a = alloca(sizeof (in_addr_t));
+ this->buf4b = alloca(sizeof (in_addr_t));
+ this->buf4c = alloca(sizeof (in_addr_t));
+ this->buf4d = alloca(sizeof (in_addr_t));
+ ip4a = this->buf4a;
+ ip4b = this->buf4b;
+ ip4c = this->buf4c;
+ ip4d = this->buf4d;
+
+ *ip4a = htonl(0xc0a80117);
+ *ip4b = htonl(0x7f000001);
+ *ip4c = htonl(0xffffffff);
+ *ip4d = htonl(0x00000000);
+
+ printf("%s\n", inet_ntoa(ip4a));
+ printf("%s\n", inet_ntoa(ip4b));
+ printf("%s\n", inet_ntoa(ip4c));
+ printf("%s\n", inet_ntoa(ip4d));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa.d.out
new file mode 100644
index 000000000000..ab535e78c117
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa.d.out
@@ -0,0 +1,5 @@
+192.168.1.23
+127.0.0.1
+255.255.255.255
+0.0.0.0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa6.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa6.d
new file mode 100644
index 000000000000..40b3849da278
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa6.d
@@ -0,0 +1,95 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+struct in6_addr *ip6a;
+struct in6_addr *ip6b;
+struct in6_addr *ip6c;
+struct in6_addr *ip6d;
+struct in6_addr *ip6e;
+struct in6_addr *ip6f;
+struct in6_addr *ip6g;
+
+BEGIN
+{
+ this->buf6a = alloca(sizeof (struct in6_addr));
+ this->buf6b = alloca(sizeof (struct in6_addr));
+ this->buf6c = alloca(sizeof (struct in6_addr));
+ this->buf6d = alloca(sizeof (struct in6_addr));
+ this->buf6e = alloca(sizeof (struct in6_addr));
+ this->buf6f = alloca(sizeof (struct in6_addr));
+ this->buf6g = alloca(sizeof (struct in6_addr));
+ ip6a = this->buf6a;
+ ip6b = this->buf6b;
+ ip6c = this->buf6c;
+ ip6d = this->buf6d;
+ ip6e = this->buf6e;
+ ip6f = this->buf6f;
+ ip6g = this->buf6g;
+
+ ip6a->__u6_addr.__u6_addr8[0] = 0xfe;
+ ip6a->__u6_addr.__u6_addr8[1] = 0x80;
+ ip6a->__u6_addr.__u6_addr8[8] = 0x02;
+ ip6a->__u6_addr.__u6_addr8[9] = 0x14;
+ ip6a->__u6_addr.__u6_addr8[10] = 0x4f;
+ ip6a->__u6_addr.__u6_addr8[11] = 0xff;
+ ip6a->__u6_addr.__u6_addr8[12] = 0xfe;
+ ip6a->__u6_addr.__u6_addr8[13] = 0x0b;
+ ip6a->__u6_addr.__u6_addr8[14] = 0x76;
+ ip6a->__u6_addr.__u6_addr8[15] = 0xc8;
+ ip6b->__u6_addr.__u6_addr8[0] = 0x10;
+ ip6b->__u6_addr.__u6_addr8[1] = 0x80;
+ ip6b->__u6_addr.__u6_addr8[10] = 0x08;
+ ip6b->__u6_addr.__u6_addr8[11] = 0x08;
+ ip6b->__u6_addr.__u6_addr8[13] = 0x20;
+ ip6b->__u6_addr.__u6_addr8[13] = 0x0c;
+ ip6b->__u6_addr.__u6_addr8[14] = 0x41;
+ ip6b->__u6_addr.__u6_addr8[15] = 0x7a;
+ ip6c->__u6_addr.__u6_addr8[15] = 0x01;
+ ip6e->__u6_addr.__u6_addr8[12] = 0x7f;
+ ip6e->__u6_addr.__u6_addr8[15] = 0x01;
+ ip6f->__u6_addr.__u6_addr8[10] = 0xff;
+ ip6f->__u6_addr.__u6_addr8[11] = 0xff;
+ ip6f->__u6_addr.__u6_addr8[12] = 0x7f;
+ ip6f->__u6_addr.__u6_addr8[15] = 0x01;
+ ip6g->__u6_addr.__u6_addr8[10] = 0xff;
+ ip6g->__u6_addr.__u6_addr8[11] = 0xfe;
+ ip6g->__u6_addr.__u6_addr8[12] = 0x7f;
+ ip6g->__u6_addr.__u6_addr8[15] = 0x01;
+
+ printf("%s\n", inet_ntoa6(ip6a));
+ printf("%s\n", inet_ntoa6(ip6b));
+ printf("%s\n", inet_ntoa6(ip6c));
+ printf("%s\n", inet_ntoa6(ip6d));
+ printf("%s\n", inet_ntoa6(ip6e));
+ printf("%s\n", inet_ntoa6(ip6f));
+ printf("%s\n", inet_ntoa6(ip6g));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa6.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa6.d.out
new file mode 100644
index 000000000000..d87c1f6141d3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntoa6.d.out
@@ -0,0 +1,8 @@
+fe80::214:4fff:fe0b:76c8
+1080::808:c:417a
+::1
+::
+127.0.0.1
+127.0.0.1
+::fffe:7f00:1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntop.d
new file mode 100644
index 000000000000..37f928708904
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntop.d
@@ -0,0 +1,135 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+in_addr_t *ip4a;
+in_addr_t *ip4b;
+in_addr_t *ip4c;
+in_addr_t *ip4d;
+struct in6_addr *ip6a;
+struct in6_addr *ip6b;
+struct in6_addr *ip6c;
+struct in6_addr *ip6d;
+struct in6_addr *ip6e;
+struct in6_addr *ip6f;
+struct in6_addr *ip6g;
+struct in6_addr *ip6h;
+
+BEGIN
+{
+ this->buf4a = alloca(sizeof (in_addr_t));
+ this->buf4b = alloca(sizeof (in_addr_t));
+ this->buf4c = alloca(sizeof (in_addr_t));
+ this->buf4d = alloca(sizeof (in_addr_t));
+ this->buf6a = alloca(sizeof (struct in6_addr));
+ this->buf6b = alloca(sizeof (struct in6_addr));
+ this->buf6c = alloca(sizeof (struct in6_addr));
+ this->buf6d = alloca(sizeof (struct in6_addr));
+ this->buf6e = alloca(sizeof (struct in6_addr));
+ this->buf6f = alloca(sizeof (struct in6_addr));
+ this->buf6g = alloca(sizeof (struct in6_addr));
+ this->buf6h = alloca(sizeof (struct in6_addr));
+ ip4a = this->buf4a;
+ ip4b = this->buf4b;
+ ip4c = this->buf4c;
+ ip4d = this->buf4d;
+ ip6a = this->buf6a;
+ ip6b = this->buf6b;
+ ip6c = this->buf6c;
+ ip6d = this->buf6d;
+ ip6e = this->buf6e;
+ ip6f = this->buf6f;
+ ip6g = this->buf6g;
+ ip6h = this->buf6h;
+
+ *ip4a = htonl(0xc0a80117);
+ *ip4b = htonl(0x7f000001);
+ *ip4c = htonl(0xffffffff);
+ *ip4d = htonl(0x00000000);
+ ip6a->__u6_addr.__u6_addr8[0] = 0xfe;
+ ip6a->__u6_addr.__u6_addr8[1] = 0x80;
+ ip6a->__u6_addr.__u6_addr8[8] = 0x02;
+ ip6a->__u6_addr.__u6_addr8[9] = 0x14;
+ ip6a->__u6_addr.__u6_addr8[10] = 0x4f;
+ ip6a->__u6_addr.__u6_addr8[11] = 0xff;
+ ip6a->__u6_addr.__u6_addr8[12] = 0xfe;
+ ip6a->__u6_addr.__u6_addr8[13] = 0x0b;
+ ip6a->__u6_addr.__u6_addr8[14] = 0x76;
+ ip6a->__u6_addr.__u6_addr8[15] = 0xc8;
+ ip6b->__u6_addr.__u6_addr8[0] = 0x10;
+ ip6b->__u6_addr.__u6_addr8[1] = 0x80;
+ ip6b->__u6_addr.__u6_addr8[10] = 0x08;
+ ip6b->__u6_addr.__u6_addr8[11] = 0x08;
+ ip6b->__u6_addr.__u6_addr8[13] = 0x20;
+ ip6b->__u6_addr.__u6_addr8[13] = 0x0c;
+ ip6b->__u6_addr.__u6_addr8[14] = 0x41;
+ ip6b->__u6_addr.__u6_addr8[15] = 0x7a;
+ ip6c->__u6_addr.__u6_addr8[15] = 0x01;
+ ip6e->__u6_addr.__u6_addr8[12] = 0x7f;
+ ip6e->__u6_addr.__u6_addr8[15] = 0x01;
+ ip6f->__u6_addr.__u6_addr8[10] = 0xff;
+ ip6f->__u6_addr.__u6_addr8[11] = 0xff;
+ ip6f->__u6_addr.__u6_addr8[12] = 0x7f;
+ ip6f->__u6_addr.__u6_addr8[15] = 0x01;
+ ip6g->__u6_addr.__u6_addr8[10] = 0xff;
+ ip6g->__u6_addr.__u6_addr8[11] = 0xfe;
+ ip6g->__u6_addr.__u6_addr8[12] = 0x7f;
+ ip6g->__u6_addr.__u6_addr8[15] = 0x01;
+ ip6h->__u6_addr.__u6_addr8[0] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[1] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[2] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[3] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[4] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[5] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[6] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[7] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[8] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[9] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[10] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[11] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[12] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[13] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[14] = 0xff;
+ ip6h->__u6_addr.__u6_addr8[15] = 0xff;
+
+ printf("%s\n", inet_ntop(AF_INET, ip4a));
+ printf("%s\n", inet_ntop(AF_INET, ip4b));
+ printf("%s\n", inet_ntop(AF_INET, ip4c));
+ printf("%s\n", inet_ntop(AF_INET, ip4d));
+ printf("%s\n", inet_ntop(AF_INET6, ip6a));
+ printf("%s\n", inet_ntop(AF_INET6, ip6b));
+ printf("%s\n", inet_ntop(AF_INET6, ip6c));
+ printf("%s\n", inet_ntop(AF_INET6, ip6d));
+ printf("%s\n", inet_ntop(AF_INET6, ip6e));
+ printf("%s\n", inet_ntop(AF_INET6, ip6f));
+ printf("%s\n", inet_ntop(AF_INET6, ip6g));
+ printf("%s\n", inet_ntop(AF_INET6, ip6h));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntop.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntop.d.out
new file mode 100644
index 000000000000..7c8311c2b8ef
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.inet_ntop.d.out
@@ -0,0 +1,13 @@
+192.168.1.23
+127.0.0.1
+255.255.255.255
+0.0.0.0
+fe80::214:4fff:fe0b:76c8
+1080::808:c:417a
+::1
+::
+::127.0.0.1
+::ffff:127.0.0.1
+::fffe:7f00:1
+ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostr.d
new file mode 100644
index 000000000000..03e295a74d5b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostr.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("%s\n", lltostr(0));
+ printf("%s\n", lltostr(1));
+ printf("%s\n", lltostr(-1));
+ printf("%s\n", lltostr(123456789));
+ printf("%s\n", lltostr(-123456789));
+ printf("%s\n", lltostr(1LL << 62));
+ printf("%s\n", lltostr(-(1LL << 62)));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostr.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostr.d.out
new file mode 100644
index 000000000000..e007c648aa65
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostr.d.out
@@ -0,0 +1,8 @@
+0
+1
+-1
+123456789
+-123456789
+4611686018427387904
+-4611686018427387904
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostrbase.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostrbase.d
new file mode 100644
index 000000000000..1afe37dc689d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostrbase.d
@@ -0,0 +1,80 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+int64_t val[int];
+
+BEGIN
+{
+ base = -2;
+ i = 0;
+ val[i++] = -10;
+ val[i++] = -1;
+ val[i++] = 0;
+ val[i++] = 10;
+ val[i++] = 100;
+ val[i++] = 1000;
+ val[i++] = (1LL << 62);
+ maxval = i;
+ i = 0;
+}
+
+tick-1ms
+/i < maxval/
+{
+ printf("base %2d of %20d: ", base, val[i]);
+}
+
+tick-1ms
+/i < maxval/
+{
+ printf(" %s\n", lltostr(val[i], base));
+}
+
+ERROR
+{
+ printf(" <error>\n");
+}
+
+tick-1ms
+/i < maxval/
+{
+ i++;
+}
+
+tick-1ms
+/i == maxval/
+{
+ i = 0;
+ base++;
+}
+
+tick-1ms
+/base > 40/
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostrbase.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostrbase.d.out
new file mode 100644
index 000000000000..94e22577123a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.lltostrbase.d.out
@@ -0,0 +1,302 @@
+base -2 of -10: <error>
+base -2 of -1: <error>
+base -2 of 0: <error>
+base -2 of 10: <error>
+base -2 of 100: <error>
+base -2 of 1000: <error>
+base -2 of 4611686018427387904: <error>
+base -1 of -10: <error>
+base -1 of -1: <error>
+base -1 of 0: <error>
+base -1 of 10: <error>
+base -1 of 100: <error>
+base -1 of 1000: <error>
+base -1 of 4611686018427387904: <error>
+base 0 of -10: <error>
+base 0 of -1: <error>
+base 0 of 0: <error>
+base 0 of 10: <error>
+base 0 of 100: <error>
+base 0 of 1000: <error>
+base 0 of 4611686018427387904: <error>
+base 1 of -10: <error>
+base 1 of -1: <error>
+base 1 of 0: <error>
+base 1 of 10: <error>
+base 1 of 100: <error>
+base 1 of 1000: <error>
+base 1 of 4611686018427387904: <error>
+base 2 of -10: 1111111111111111111111111111111111111111111111111111111111110110
+base 2 of -1: 1111111111111111111111111111111111111111111111111111111111111111
+base 2 of 0: 0
+base 2 of 10: 1010
+base 2 of 100: 1100100
+base 2 of 1000: 1111101000
+base 2 of 4611686018427387904: 100000000000000000000000000000000000000000000000000000000000000
+base 3 of -10: 11112220022122120101211020120210210211120
+base 3 of -1: 11112220022122120101211020120210210211220
+base 3 of 0: 0
+base 3 of 10: 101
+base 3 of 100: 10201
+base 3 of 1000: 1101001
+base 3 of 4611686018427387904: 1010201120122220002201001122110012110111
+base 4 of -10: 33333333333333333333333333333312
+base 4 of -1: 33333333333333333333333333333333
+base 4 of 0: 0
+base 4 of 10: 22
+base 4 of 100: 1210
+base 4 of 1000: 33220
+base 4 of 4611686018427387904: 10000000000000000000000000000000
+base 5 of -10: 2214220303114400424121122411
+base 5 of -1: 2214220303114400424121122430
+base 5 of 0: 0
+base 5 of 10: 20
+base 5 of 100: 400
+base 5 of 1000: 13000
+base 5 of 4611686018427387904: 302141200402211214402403104
+base 6 of -10: 3520522010102100444244410
+base 6 of -1: 3520522010102100444244423
+base 6 of 0: 0
+base 6 of 10: 14
+base 6 of 100: 244
+base 6 of 1000: 4344
+base 6 of 4611686018427387904: 550120301313313111041104
+base 7 of -10: 45012021522523134134556
+base 7 of -1: 45012021522523134134601
+base 7 of 0: 0
+base 7 of 10: 13
+base 7 of 100: 202
+base 7 of 1000: 2626
+base 7 of 4611686018427387904: 11154003640456024361134
+base 8 of -10: 01777777777777777777766
+base 8 of -1: 01777777777777777777777
+base 8 of 0: 0
+base 8 of 10: 012
+base 8 of 100: 0144
+base 8 of 1000: 01750
+base 8 of 4611686018427387904: 0400000000000000000000
+base 9 of -10: 145808576354216723746
+base 9 of -1: 145808576354216723756
+base 9 of 0: 0
+base 9 of 10: 11
+base 9 of 100: 121
+base 9 of 1000: 1331
+base 9 of 4611686018427387904: 33646586081048405414
+base 10 of -10: -10
+base 10 of -1: -1
+base 10 of 0: 0
+base 10 of 10: 10
+base 10 of 100: 100
+base 10 of 1000: 1000
+base 10 of 4611686018427387904: 4611686018427387904
+base 11 of -10: 335500516a429071276
+base 11 of -1: 335500516a429071284
+base 11 of 0: 0
+base 11 of 10: a
+base 11 of 100: 91
+base 11 of 1000: 82a
+base 11 of 4611686018427387904: 9140013181078458a4
+base 12 of -10: 839365134a2a240706
+base 12 of -1: 839365134a2a240713
+base 12 of 0: 0
+base 12 of 10: a
+base 12 of 100: 84
+base 12 of 1000: 6b4
+base 12 of 4611686018427387904: 20b3a733a268670194
+base 13 of -10: 219505a9511a867b66
+base 13 of -1: 219505a9511a867b72
+base 13 of 0: 0
+base 13 of 10: a
+base 13 of 100: 79
+base 13 of 1000: 5bc
+base 13 of 4611686018427387904: 6c1349246a2881c84
+base 14 of -10: 8681049adb03db166
+base 14 of -1: 8681049adb03db171
+base 14 of 0: 0
+base 14 of 10: a
+base 14 of 100: 72
+base 14 of 1000: 516
+base 14 of 4611686018427387904: 219038263637dd3c4
+base 15 of -10: 2c1d56b648c6cd106
+base 15 of -1: 2c1d56b648c6cd110
+base 15 of 0: 0
+base 15 of 10: a
+base 15 of 100: 6a
+base 15 of 1000: 46a
+base 15 of 4611686018427387904: a7e8ce189a933404
+base 16 of -10: 0xfffffffffffffff6
+base 16 of -1: 0xffffffffffffffff
+base 16 of 0: 0x0
+base 16 of 10: 0xa
+base 16 of 100: 0x64
+base 16 of 1000: 0x3e8
+base 16 of 4611686018427387904: 0x4000000000000000
+base 17 of -10: 67979g60f5428008
+base 17 of -1: 67979g60f5428010
+base 17 of 0: 0
+base 17 of 10: a
+base 17 of 100: 5f
+base 17 of 1000: 37e
+base 17 of 4611686018427387904: 1a6a6ca03e10a88d
+base 18 of -10: 2d3fgb0b9cg4bd26
+base 18 of -1: 2d3fgb0b9cg4bd2f
+base 18 of 0: 0
+base 18 of 10: a
+base 18 of 100: 5a
+base 18 of 1000: 31a
+base 18 of 4611686018427387904: c588bdbfgd12ge4
+base 19 of -10: 141c8786h1ccaag7
+base 19 of -1: 141c8786h1ccaagg
+base 19 of 0: 0
+base 19 of 10: a
+base 19 of 100: 55
+base 19 of 1000: 2ec
+base 19 of 4611686018427387904: 5ecbb6fi9h7ggi9
+base 20 of -10: b53bjh07be4dj06
+base 20 of -1: b53bjh07be4dj0f
+base 20 of 0: 0
+base 20 of 10: a
+base 20 of 100: 50
+base 20 of 1000: 2a0
+base 20 of 4611686018427387904: 2g5hjj51hib39f4
+base 21 of -10: 5e8g4ggg7g56di6
+base 21 of -1: 5e8g4ggg7g56dif
+base 21 of 0: 0
+base 21 of 10: a
+base 21 of 100: 4g
+base 21 of 1000: 25d
+base 21 of 4611686018427387904: 18hjgjjjhebh8f4
+base 22 of -10: 2l4lf104353j8k6
+base 22 of -1: 2l4lf104353j8kf
+base 22 of 0: 0
+base 22 of 10: a
+base 22 of 100: 4c
+base 22 of 1000: 21a
+base 22 of 4611686018427387904: g6g95gc0hha7g4
+base 23 of -10: 1ddh88h2782i50j
+base 23 of -1: 1ddh88h2782i515
+base 23 of 0: 0
+base 23 of 10: a
+base 23 of 100: 48
+base 23 of 1000: 1kb
+base 23 of 4611686018427387904: 93a22467dc4chd
+base 24 of -10: l12ee5fn0ji1i6
+base 24 of -1: l12ee5fn0ji1if
+base 24 of 0: 0
+base 24 of 10: a
+base 24 of 100: 44
+base 24 of 1000: 1hg
+base 24 of 4611686018427387904: 566ffd9ni4mcag
+base 25 of -10: c9c336o0mlb7e6
+base 25 of -1: c9c336o0mlb7ef
+base 25 of 0: 0
+base 25 of 10: a
+base 25 of 100: 40
+base 25 of 1000: 1f0
+base 25 of 4611686018427387904: 32970kc6bo2kg4
+base 26 of -10: 7b7n2pcniokcg6
+base 26 of -1: 7b7n2pcniokcgf
+base 26 of 0: 0
+base 26 of 10: a
+base 26 of 100: 3m
+base 26 of 1000: 1cc
+base 26 of 4611686018427387904: 1m8c769io65344
+base 27 of -10: 4eo8hfam6fllmf
+base 27 of -1: 4eo8hfam6fllmo
+base 27 of 0: 0
+base 27 of 10: a
+base 27 of 100: 3j
+base 27 of 1000: 1a1
+base 27 of 4611686018427387904: 13jfho2j1hc5cd
+base 28 of -10: 2nc6j26l66rho6
+base 28 of -1: 2nc6j26l66rhof
+base 28 of 0: 0
+base 28 of 10: a
+base 28 of 100: 3g
+base 28 of 1000: 17k
+base 28 of 4611686018427387904: jo1ilfj8fkpd4
+base 29 of -10: 1n3rsh11f098re
+base 29 of -1: 1n3rsh11f098rn
+base 29 of 0: 0
+base 29 of 10: a
+base 29 of 100: 3d
+base 29 of 1000: 15e
+base 29 of 4611686018427387904: d0slim0b029e6
+base 30 of -10: 14l9lkmo30o406
+base 30 of -1: 14l9lkmo30o40f
+base 30 of 0: 0
+base 30 of 10: a
+base 30 of 100: 3a
+base 30 of 1000: 13a
+base 30 of 4611686018427387904: 8k9rrkl0ml104
+base 31 of -10: nd075ib45k866
+base 31 of -1: nd075ib45k86f
+base 31 of 0: 0
+base 31 of 10: a
+base 31 of 100: 37
+base 31 of 1000: 118
+base 31 of 4611686018427387904: 5qfh94i8okhh4
+base 32 of -10: fvvvvvvvvvvvm
+base 32 of -1: fvvvvvvvvvvvv
+base 32 of 0: 0
+base 32 of 10: a
+base 32 of 100: 34
+base 32 of 1000: v8
+base 32 of 4611686018427387904: 4000000000000
+base 33 of -10: b1w8p7j5q9r66
+base 33 of -1: b1w8p7j5q9r6f
+base 33 of 0: 0
+base 33 of 10: a
+base 33 of 100: 31
+base 33 of 1000: ua
+base 33 of 4611686018427387904: 2p826a4q6ivi4
+base 34 of -10: 7orp63sh4dph8
+base 34 of -1: 7orp63sh4dphh
+base 34 of 0: 0
+base 34 of 10: a
+base 34 of 100: 2w
+base 34 of 1000: te
+base 34 of 4611686018427387904: 1vnvr0wl9ketu
+base 35 of -10: 5g24a25twkwf6
+base 35 of -1: 5g24a25twkwff
+base 35 of 0: 0
+base 35 of 10: a
+base 35 of 100: 2u
+base 35 of 1000: sk
+base 35 of 4611686018427387904: 1cqrb9a7gvgu4
+base 36 of -10: 3w5e11264sgs6
+base 36 of -1: 3w5e11264sgsf
+base 36 of 0: 0
+base 36 of 10: a
+base 36 of 100: 2s
+base 36 of 1000: rs
+base 36 of 4611686018427387904: z1ci99jj7474
+base 37 of -10: <error>
+base 37 of -1: <error>
+base 37 of 0: <error>
+base 37 of 10: <error>
+base 37 of 100: <error>
+base 37 of 1000: <error>
+base 37 of 4611686018427387904: <error>
+base 38 of -10: <error>
+base 38 of -1: <error>
+base 38 of 0: <error>
+base 38 of 10: <error>
+base 38 of 100: <error>
+base 38 of 1000: <error>
+base 38 of 4611686018427387904: <error>
+base 39 of -10: <error>
+base 39 of -1: <error>
+base 39 of 0: <error>
+base 39 of 10: <error>
+base 39 of 100: <error>
+base 39 of 1000: <error>
+base 39 of 4611686018427387904: <error>
+base 40 of -10: <error>
+base 40 of -1: <error>
+base 40 of 0: <error>
+base 40 of 10: <error>
+base 40 of 100: <error>
+base 40 of 1000: <error>
+base 40 of 4611686018427387904: <error>
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_owned.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_owned.d
new file mode 100644
index 000000000000..0f97aa1a951e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_owned.d
@@ -0,0 +1,62 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * mutex_owned() should return a non-zero value if the calling
+ * thread currently holds the mutex.
+ *
+ * SECTION: Actions and Subroutines/mutex_owned()
+ */
+
+#pragma D option quiet
+
+lockstat:::adaptive-acquire
+{
+ this->owned = mutex_owned((struct mtx *)arg0);
+ this->owner = mutex_owner((struct mtx *)arg0);
+}
+
+lockstat:::adaptive-acquire
+/!this->owned/
+{
+ printf("mutex_owned() returned 0, expected non-zero\n");
+ exit(1);
+}
+
+lockstat:::adaptive-acquire
+/this->owner != curthread/
+{
+ printf("current thread is not current owner of owned lock\n");
+ exit(1);
+}
+
+lockstat:::adaptive-acquire
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_owner.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_owner.d
new file mode 100644
index 000000000000..0784eda4d775
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_owner.d
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * mutex_owner() should return a pointer to the kernel thread holding
+ * the mutex.
+ *
+ * SECTION: Actions and Subroutines/mutex_owner()
+ *
+ * NOTES: This assertion can't be verified so we'll just call it.
+ */
+
+
+
+
+#pragma D option quiet
+
+struct thread *ptr;
+
+BEGIN
+{
+ i = 0;
+}
+
+lockstat:::adaptive-acquire
+{
+
+ ptr = mutex_owner((struct mtx *)arg0);
+ i++;
+}
+
+tick-1
+/i > 5/
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_type_adaptive.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_type_adaptive.d
new file mode 100644
index 000000000000..f953d2407374
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.mutex_type_adaptive.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * mutex_type_adaptive() should return a non-zero value if the
+ * mutex is an adaptive one.
+ *
+ * SECTION: Actions and Subroutines/mutex_type_adaptive()
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+ ret = -99;
+}
+
+lockstat:::adaptive-acquire
+{
+ ret = mutex_type_adaptive((struct mtx *)arg0);
+ i++;
+}
+
+tick-1
+/ret == 1/
+{
+ exit(0);
+}
+
+tick-1
+/i == 100 && ret == 0/
+{
+ printf("mutex_type_adaptive returned 0, expected non-zero\n");
+ exit(1);
+}
+
+tick-1
+/i == 100 && ret == -99/
+{
+ printf("No adaptive_mutexs called in the time this test was run.\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.progenyof.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.progenyof.d
new file mode 100644
index 000000000000..02911580e50e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.progenyof.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * progenyof() should return non-zero if the pid passed is in the
+ # progeny of the calling process.
+ *
+ * SECTION: Actions and Subroutines/progenyof()
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ res_1 = -1;
+ res_2 = -1;
+ res_3 = -1;
+
+ res_1 = progenyof($ppid); /* this will always be true */
+ res_2 = progenyof($ppid + 1); /* this will always be false */
+ res_3 = progenyof(1); /* this will always be true */
+}
+
+
+tick-1
+/res_1 > 0 && res_2 == 0 && res_3 > 0/
+{
+ exit(0);
+}
+
+tick-1
+/res_1 <= 0 || res_2 != 0 || res_3 <= 0/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.rand.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.rand.d
new file mode 100644
index 000000000000..51f4491177d2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.rand.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test rand()
+ *
+ * SECTION: Actions and Subroutines/rand()
+ */
+
+
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-1
+/i != 10/
+{
+ i++;
+ trace(rand());
+}
+
+tick-1
+/i == 10/
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strchr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strchr.d
new file mode 100644
index 000000000000..8dc8f89ba225
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strchr.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ str = "fooeyfooeyfoo";
+ this->success = 0;
+
+ c = 'f';
+ printf("strchr(\"%s\", '%c') = \"%s\"\n", str, c, strchr(str, c));
+ printf("strrchr(\"%s\", '%c') = \"%s\"\n", str, c, strrchr(str, c));
+
+ c = 'y';
+ printf("strchr(\"%s\", '%c') = \"%s\"\n", str, c, strchr(str, c));
+ printf("strrchr(\"%s\", '%c') = \"%s\"\n", str, c, strrchr(str, c));
+
+ printf("strrchr(\"%s\", '%c') = \"%s\"\n", strchr(str, c), c,
+ strrchr(strchr(str, c), c));
+
+ this->success = 1;
+}
+
+BEGIN
+/!this->success/
+{
+ exit(1);
+}
+
+BEGIN
+/strchr(str, 'a') != NULL/
+{
+ exit(2);
+}
+
+BEGIN
+/strrchr(str, 'a') != NULL/
+{
+ exit(3);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strchr.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strchr.d.out
new file mode 100644
index 000000000000..328b5318bc8e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strchr.d.out
@@ -0,0 +1,6 @@
+strchr("fooeyfooeyfoo", 'f') = "fooeyfooeyfoo"
+strrchr("fooeyfooeyfoo", 'f') = "foo"
+strchr("fooeyfooeyfoo", 'y') = "yfooeyfoo"
+strrchr("fooeyfooeyfoo", 'y') = "yfoo"
+strrchr("yfooeyfoo", 'y') = "yfoo"
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strjoin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strjoin.d
new file mode 100644
index 000000000000..0f23737d38f6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strjoin.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("%s\n", strjoin("foo", "baz"));
+ printf("%s\n", strjoin("foo", ""));
+ printf("%s\n", strjoin("", "baz"));
+ printf("%s\n", strjoin("", ""));
+ exit(0);
+}
+
+BEGIN
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strjoin.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strjoin.d.out
new file mode 100644
index 000000000000..657286944a75
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strjoin.d.out
@@ -0,0 +1,5 @@
+foobaz
+foo
+baz
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strstr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strstr.d
new file mode 100644
index 000000000000..0c81b7a892ab
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strstr.d
@@ -0,0 +1,89 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ str = "foobarbarbazbarbop";
+ this->success = 0;
+
+ c = str;
+ printf("strstr(\"%s\", \"%s\") = \"%s\"\n", str, c, strstr(str, c));
+
+ c = "baz";
+ printf("strstr(\"%s\", \"%s\") = \"%s\"\n", str, c, strstr(str, c));
+
+ c = "bar";
+ printf("strstr(\"%s\", \"%s\") = \"%s\"\n", str, c, strstr(str, c));
+
+ c = "bazbarbop";
+ printf("strstr(\"%s\", \"%s\") = \"%s\"\n", str, c, strstr(str, c));
+
+ c = "barba";
+ printf("strstr(\"%s\", \"%s\") = \"%s\"\n", str, c, strstr(str, c));
+
+ printf("strstr(\"%s\", \"%s\") = \"%s\"\n",
+ strstr(str, "baz"), strstr(str, "zba"),
+ strstr(strstr(str, "baz"), strstr(str, "zba")));
+
+ c = "";
+ printf("strstr(\"%s\", \"%s\") = \"%s\"\n", str, c, strstr(str, c));
+
+ str = "";
+ printf("strstr(\"%s\", \"%s\") = \"%s\"\n", str, c, strstr(str, c));
+
+ str = "f";
+ c = "f";
+ printf("strstr(\"%s\", \"%s\") = \"%s\"\n", str, c, strstr(str, c));
+
+ this->success = 1;
+}
+
+BEGIN
+/!this->success/
+{
+ exit(1);
+}
+
+BEGIN
+/strstr(str, "barbarf") != NULL/
+{
+ exit(2);
+}
+
+BEGIN
+/strstr(str, "foobarbarbazbarbopp") != NULL/
+{
+ exit(3);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strstr.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strstr.d.out
new file mode 100644
index 000000000000..f9121dbcfb8d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strstr.d.out
@@ -0,0 +1,10 @@
+strstr("foobarbarbazbarbop", "foobarbarbazbarbop") = "foobarbarbazbarbop"
+strstr("foobarbarbazbarbop", "baz") = "bazbarbop"
+strstr("foobarbarbazbarbop", "bar") = "barbarbazbarbop"
+strstr("foobarbarbazbarbop", "bazbarbop") = "bazbarbop"
+strstr("foobarbarbazbarbop", "barba") = "barbarbazbarbop"
+strstr("bazbarbop", "zbarbop") = "zbarbop"
+strstr("foobarbarbazbarbop", "") = "foobarbarbazbarbop"
+strstr("", "") = ""
+strstr("f", "f") = "f"
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok.d
new file mode 100644
index 000000000000..47092ba46ba1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok.d
@@ -0,0 +1,146 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ this->str = ",,,Carrots,,Barley,Oatmeal,,,Beans,";
+}
+
+BEGIN
+/(this->field = strtok(this->str, ",")) == NULL/
+{
+ exit(1);
+}
+
+BEGIN
+{
+ printf("%s\n", this->field);
+}
+
+BEGIN
+/(this->field = strtok(NULL, ",")) == NULL/
+{
+ exit(2);
+}
+
+BEGIN
+{
+ printf("%s\n", this->field);
+}
+
+BEGIN
+/(this->field = strtok(NULL, ",")) == NULL/
+{
+ exit(3);
+}
+
+BEGIN
+{
+ printf("%s\n", this->field);
+}
+
+BEGIN
+/(this->field = strtok(NULL, ",")) == NULL/
+{
+ exit(4);
+}
+
+BEGIN
+{
+ printf("%s\n", this->field);
+}
+
+BEGIN
+/(self->a = strtok(NULL, ",")) != NULL/
+{
+ printf("unexpected field: %s\n", this->field);
+ exit(5);
+}
+
+struct {
+ string s1;
+ string s2;
+ string result;
+} command[int];
+
+int i;
+
+BEGIN
+{
+ command[i].s1 = "";
+ command[i].s2 = "";
+ command[i].result = "";
+ i++;
+
+ command[i].s1 = "foo";
+ command[i].s2 = "";
+ command[i].result = command[i].s1;
+ i++;
+
+ command[i].s1 = "foobar";
+ command[i].s2 = "o";
+ command[i].result = "f";
+ i++;
+
+ command[i].s1 = "oobar";
+ command[i].s2 = "o";
+ command[i].result = "bar";
+ i++;
+
+ command[i].s1 = "foo";
+ command[i].s2 = "bar";
+ command[i].result = command[i].s1;
+ i++;
+
+ command[i].s1 = "";
+ command[i].s2 = "foo";
+ command[i].result = "";
+ i++;
+
+ end = i;
+ i = 0;
+}
+
+tick-1ms
+/i < end &&
+ (this->result = strtok(command[i].s1, command[i].s2)) != command[i].result/
+{
+ printf("strtok(\"%s\", \"%s\") = \"%s\", expected \"%s\"",
+ command[i].s1, command[i].s2,
+ this->result != NULL ? this->result : "<null>",
+ command[i].result != NULL ? command[i].result : "<null>");
+ exit(6 + i);
+}
+
+tick-1ms
+/++i == end/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok.d.out
new file mode 100644
index 000000000000..4bc37274b928
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok.d.out
@@ -0,0 +1,5 @@
+Carrots
+Barley
+Oatmeal
+Beans
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok_null.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok_null.d
new file mode 100644
index 000000000000..6de4f97d18fb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.strtok_null.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Test that a strtok(NULL, ...) without first calling strtok(string, ...)
+ * produces an error
+ */
+
+BEGIN
+{
+ trace(strtok(NULL, "!"));
+ exit(1);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substr.d
new file mode 100644
index 000000000000..edee6442e350
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substr.d
@@ -0,0 +1,231 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+#pragma D option strsize=32
+
+struct {
+ int index;
+ int length;
+ int nolen;
+ int alt;
+} command[int];
+
+int i;
+
+BEGIN
+{
+ str = "foobarbazbop";
+ str2 = "";
+ altstr = "CRAIG: Positioned them, I don't ";
+ altstr2 = "know... I'm fairly wide guy.";
+
+ command[i].index = 3;
+ command[i].nolen = 1;
+ i++;
+
+ command[i].index = 300;
+ command[i].nolen = 1;
+ i++;
+
+ command[i].index = -10;
+ command[i].nolen = 1;
+ i++;
+
+ command[i].index = 0;
+ command[i].nolen = 1;
+ i++;
+
+ command[i].index = 1;
+ command[i].nolen = 1;
+ i++;
+
+ command[i].index = strlen(str) - 1;
+ command[i].nolen = 1;
+ i++;
+
+ command[i].index = strlen(str);
+ command[i].nolen = 1;
+ i++;
+
+ command[i].index = strlen(str) + 1;
+ command[i].nolen = 1;
+ i++;
+
+ command[i].index = 8;
+ command[i].length = 20;
+ i++;
+
+ command[i].index = 4;
+ command[i].length = 4;
+ i++;
+
+ command[i].index = 5;
+ command[i].length = strlen(str) - command[i].index + 1;
+ i++;
+
+ command[i].index = 5;
+ command[i].length = strlen(str) - command[i].index + 2;
+ i++;
+
+ command[i].index = 400;
+ command[i].length = 20;
+ i++;
+
+ command[i].index = 400;
+ command[i].length = 0;
+ i++;
+
+ command[i].index = 400;
+ command[i].length = -1;
+ i++;
+
+ command[i].index = 3;
+ command[i].length = 0;
+ i++;
+
+ command[i].index = 3;
+ command[i].length = -1;
+ i++;
+
+ command[i].index = 3;
+ command[i].length = -4;
+ i++;
+
+ command[i].index = 3;
+ command[i].length = -20;
+ i++;
+
+ command[i].index = -10;
+ command[i].length = -5;
+ i++;
+
+ command[i].index = 0;
+ command[i].length = 400;
+ i++;
+
+ command[i].index = -1;
+ command[i].length = 400;
+ i++;
+
+ command[i].index = -1;
+ command[i].length = 0;
+ i++;
+
+ command[i].index = -1;
+ command[i].length = -1;
+ i++;
+
+ command[i].index = -2 * strlen(str);
+ command[i].length = 2 * strlen(str);
+ i++;
+
+ command[i].index = -2 * strlen(str);
+ command[i].length = strlen(str);
+ i++;
+
+ command[i].index = -2 * strlen(str);
+ command[i].length = strlen(str) + 1;
+ i++;
+
+ command[i].index = -1 * strlen(str);
+ command[i].length = strlen(str);
+ i++;
+
+ command[i].index = -1 * strlen(str);
+ command[i].length = strlen(str) - 1;
+ i++;
+
+ command[i].index = 100;
+ command[i].length = 10;
+ command[i].alt = 1;
+ i++;
+
+ command[i].index = 100;
+ command[i].nolen = 1;
+ command[i].alt = 1;
+ i++;
+
+ end = i;
+ i = 0;
+ printf("#!/usr/perl5/bin/perl\n\nBEGIN {\n");
+
+}
+
+tick-1ms
+/i < end && command[i].nolen/
+{
+ this->str = command[i].alt ? altstr : str;
+ this->str2 = command[i].alt ? altstr2 : str2;
+ this->result = substr(command[i].alt ?
+ "CRAIG: Positioned them, I don't know... I'm fairly wide guy." :
+ str, command[i].index);
+
+ printf("\tif (substr(\"%s%s\", %d) ne \"%s\") {\n",
+ this->str, this->str2, command[i].index, this->result);
+
+ printf("\t\tprintf(\"perl => substr(\\\"%s%s\\\", %d) = ",
+ this->str, this->str2, command[i].index);
+ printf("\\\"%%s\\\"\\n\",\n\t\t substr(\"%s%s\", %d));\n",
+ this->str, this->str2, command[i].index);
+ printf("\t\tprintf(\" D => substr(\\\"%s%s\\\", %d) = ",
+ this->str, this->str2, command[i].index);
+ printf("\\\"%%s\\\"\\n\",\n\t\t \"%s\");\n", this->result);
+ printf("\t\t$failed++;\n");
+ printf("\t}\n\n");
+}
+
+tick-1ms
+/i < end && !command[i].nolen/
+{
+ this->str = command[i].alt ? altstr : str;
+ this->str2 = command[i].alt ? altstr2 : str2;
+ this->result = substr(command[i].alt ?
+ "CRAIG: Positioned them, I don't know... I'm fairly wide guy." :
+ str, command[i].index, command[i].length);
+
+ printf("\tif (substr(\"%s%s\", %d, %d) ne \"%s\") {\n",
+ this->str, this->str2, command[i].index, command[i].length,
+ this->result);
+ printf("\t\tprintf(\"perl => substr(\\\"%s%s\\\", %d, %d) = ",
+ this->str, this->str2, command[i].index, command[i].length);
+ printf("\\\"%%s\\\"\\n\",\n\t\t substr(\"%s%s\", %d, %d));\n",
+ this->str, this->str2, command[i].index, command[i].length);
+ printf("\t\tprintf(\" D => substr(\\\"%s%s\\\", %d, %d) = ",
+ this->str, this->str2, command[i].index, command[i].length);
+ printf("\\\"%%s\\\"\\n\",\n\t\t \"%s\");\n", this->result);
+ printf("\t\t$failed++;\n");
+ printf("\t}\n\n");
+}
+
+tick-1ms
+/++i == end/
+{
+ printf("\texit($failed);\n}\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substr.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substr.d.out
new file mode 100644
index 000000000000..5b498ef36be9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substr.d.out
@@ -0,0 +1,254 @@
+#!/usr/perl5/bin/perl
+
+BEGIN {
+ if (substr("foobarbazbop", 3) ne "barbazbop") {
+ printf("perl => substr(\"foobarbazbop\", 3) = \"%s\"\n",
+ substr("foobarbazbop", 3));
+ printf(" D => substr(\"foobarbazbop\", 3) = \"%s\"\n",
+ "barbazbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 300) ne "") {
+ printf("perl => substr(\"foobarbazbop\", 300) = \"%s\"\n",
+ substr("foobarbazbop", 300));
+ printf(" D => substr(\"foobarbazbop\", 300) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -10) ne "obarbazbop") {
+ printf("perl => substr(\"foobarbazbop\", -10) = \"%s\"\n",
+ substr("foobarbazbop", -10));
+ printf(" D => substr(\"foobarbazbop\", -10) = \"%s\"\n",
+ "obarbazbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 0) ne "foobarbazbop") {
+ printf("perl => substr(\"foobarbazbop\", 0) = \"%s\"\n",
+ substr("foobarbazbop", 0));
+ printf(" D => substr(\"foobarbazbop\", 0) = \"%s\"\n",
+ "foobarbazbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 1) ne "oobarbazbop") {
+ printf("perl => substr(\"foobarbazbop\", 1) = \"%s\"\n",
+ substr("foobarbazbop", 1));
+ printf(" D => substr(\"foobarbazbop\", 1) = \"%s\"\n",
+ "oobarbazbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 11) ne "p") {
+ printf("perl => substr(\"foobarbazbop\", 11) = \"%s\"\n",
+ substr("foobarbazbop", 11));
+ printf(" D => substr(\"foobarbazbop\", 11) = \"%s\"\n",
+ "p");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 12) ne "") {
+ printf("perl => substr(\"foobarbazbop\", 12) = \"%s\"\n",
+ substr("foobarbazbop", 12));
+ printf(" D => substr(\"foobarbazbop\", 12) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 13) ne "") {
+ printf("perl => substr(\"foobarbazbop\", 13) = \"%s\"\n",
+ substr("foobarbazbop", 13));
+ printf(" D => substr(\"foobarbazbop\", 13) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 8, 20) ne "zbop") {
+ printf("perl => substr(\"foobarbazbop\", 8, 20) = \"%s\"\n",
+ substr("foobarbazbop", 8, 20));
+ printf(" D => substr(\"foobarbazbop\", 8, 20) = \"%s\"\n",
+ "zbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 4, 4) ne "arba") {
+ printf("perl => substr(\"foobarbazbop\", 4, 4) = \"%s\"\n",
+ substr("foobarbazbop", 4, 4));
+ printf(" D => substr(\"foobarbazbop\", 4, 4) = \"%s\"\n",
+ "arba");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 5, 8) ne "rbazbop") {
+ printf("perl => substr(\"foobarbazbop\", 5, 8) = \"%s\"\n",
+ substr("foobarbazbop", 5, 8));
+ printf(" D => substr(\"foobarbazbop\", 5, 8) = \"%s\"\n",
+ "rbazbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 5, 9) ne "rbazbop") {
+ printf("perl => substr(\"foobarbazbop\", 5, 9) = \"%s\"\n",
+ substr("foobarbazbop", 5, 9));
+ printf(" D => substr(\"foobarbazbop\", 5, 9) = \"%s\"\n",
+ "rbazbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 400, 20) ne "") {
+ printf("perl => substr(\"foobarbazbop\", 400, 20) = \"%s\"\n",
+ substr("foobarbazbop", 400, 20));
+ printf(" D => substr(\"foobarbazbop\", 400, 20) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 400, 0) ne "") {
+ printf("perl => substr(\"foobarbazbop\", 400, 0) = \"%s\"\n",
+ substr("foobarbazbop", 400, 0));
+ printf(" D => substr(\"foobarbazbop\", 400, 0) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 400, -1) ne "") {
+ printf("perl => substr(\"foobarbazbop\", 400, -1) = \"%s\"\n",
+ substr("foobarbazbop", 400, -1));
+ printf(" D => substr(\"foobarbazbop\", 400, -1) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 3, 0) ne "") {
+ printf("perl => substr(\"foobarbazbop\", 3, 0) = \"%s\"\n",
+ substr("foobarbazbop", 3, 0));
+ printf(" D => substr(\"foobarbazbop\", 3, 0) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 3, -1) ne "barbazbo") {
+ printf("perl => substr(\"foobarbazbop\", 3, -1) = \"%s\"\n",
+ substr("foobarbazbop", 3, -1));
+ printf(" D => substr(\"foobarbazbop\", 3, -1) = \"%s\"\n",
+ "barbazbo");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 3, -4) ne "barba") {
+ printf("perl => substr(\"foobarbazbop\", 3, -4) = \"%s\"\n",
+ substr("foobarbazbop", 3, -4));
+ printf(" D => substr(\"foobarbazbop\", 3, -4) = \"%s\"\n",
+ "barba");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 3, -20) ne "") {
+ printf("perl => substr(\"foobarbazbop\", 3, -20) = \"%s\"\n",
+ substr("foobarbazbop", 3, -20));
+ printf(" D => substr(\"foobarbazbop\", 3, -20) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -10, -5) ne "obarb") {
+ printf("perl => substr(\"foobarbazbop\", -10, -5) = \"%s\"\n",
+ substr("foobarbazbop", -10, -5));
+ printf(" D => substr(\"foobarbazbop\", -10, -5) = \"%s\"\n",
+ "obarb");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", 0, 400) ne "foobarbazbop") {
+ printf("perl => substr(\"foobarbazbop\", 0, 400) = \"%s\"\n",
+ substr("foobarbazbop", 0, 400));
+ printf(" D => substr(\"foobarbazbop\", 0, 400) = \"%s\"\n",
+ "foobarbazbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -1, 400) ne "p") {
+ printf("perl => substr(\"foobarbazbop\", -1, 400) = \"%s\"\n",
+ substr("foobarbazbop", -1, 400));
+ printf(" D => substr(\"foobarbazbop\", -1, 400) = \"%s\"\n",
+ "p");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -1, 0) ne "") {
+ printf("perl => substr(\"foobarbazbop\", -1, 0) = \"%s\"\n",
+ substr("foobarbazbop", -1, 0));
+ printf(" D => substr(\"foobarbazbop\", -1, 0) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -1, -1) ne "") {
+ printf("perl => substr(\"foobarbazbop\", -1, -1) = \"%s\"\n",
+ substr("foobarbazbop", -1, -1));
+ printf(" D => substr(\"foobarbazbop\", -1, -1) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -24, 24) ne "foobarbazbop") {
+ printf("perl => substr(\"foobarbazbop\", -24, 24) = \"%s\"\n",
+ substr("foobarbazbop", -24, 24));
+ printf(" D => substr(\"foobarbazbop\", -24, 24) = \"%s\"\n",
+ "foobarbazbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -24, 12) ne "") {
+ printf("perl => substr(\"foobarbazbop\", -24, 12) = \"%s\"\n",
+ substr("foobarbazbop", -24, 12));
+ printf(" D => substr(\"foobarbazbop\", -24, 12) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -24, 13) ne "f") {
+ printf("perl => substr(\"foobarbazbop\", -24, 13) = \"%s\"\n",
+ substr("foobarbazbop", -24, 13));
+ printf(" D => substr(\"foobarbazbop\", -24, 13) = \"%s\"\n",
+ "f");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -12, 12) ne "foobarbazbop") {
+ printf("perl => substr(\"foobarbazbop\", -12, 12) = \"%s\"\n",
+ substr("foobarbazbop", -12, 12));
+ printf(" D => substr(\"foobarbazbop\", -12, 12) = \"%s\"\n",
+ "foobarbazbop");
+ $failed++;
+ }
+
+ if (substr("foobarbazbop", -12, 11) ne "foobarbazbo") {
+ printf("perl => substr(\"foobarbazbop\", -12, 11) = \"%s\"\n",
+ substr("foobarbazbop", -12, 11));
+ printf(" D => substr(\"foobarbazbop\", -12, 11) = \"%s\"\n",
+ "foobarbazbo");
+ $failed++;
+ }
+
+ if (substr("CRAIG: Positioned them, I don't know... I'm fairly wide guy.", 100, 10) ne "") {
+ printf("perl => substr(\"CRAIG: Positioned them, I don't know... I'm fairly wide guy.\", 100, 10) = \"%s\"\n",
+ substr("CRAIG: Positioned them, I don't know... I'm fairly wide guy.", 100, 10));
+ printf(" D => substr(\"CRAIG: Positioned them, I don't know... I'm fairly wide guy.\", 100, 10) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ if (substr("CRAIG: Positioned them, I don't know... I'm fairly wide guy.", 100) ne "") {
+ printf("perl => substr(\"CRAIG: Positioned them, I don't know... I'm fairly wide guy.\", 100) = \"%s\"\n",
+ substr("CRAIG: Positioned them, I don't know... I'm fairly wide guy.", 100));
+ printf(" D => substr(\"CRAIG: Positioned them, I don't know... I'm fairly wide guy.\", 100) = \"%s\"\n",
+ "");
+ $failed++;
+ }
+
+ exit($failed);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substrminate.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substrminate.d
new file mode 100644
index 000000000000..2c025410d443
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substrminate.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+#pragma D option aggsortkey
+
+/*
+ * This is to check that we're correctly null-terminating the result of the
+ * substr() subroutine.
+ */
+
+tick-1ms
+/i++ > 1000/
+{
+ exit(0);
+}
+
+tick-1ms
+{
+ @[substr((i & 1) ? "Bryan is smart" : "he's not a dummy", 0,
+ (i & 1) ? 8 : 18)] = count();
+}
+
+END
+{
+ printa("%s\n", @);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substrminate.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substrminate.d.out
new file mode 100644
index 000000000000..26c19aa2c5a3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.substrminate.d.out
@@ -0,0 +1,3 @@
+Bryan is
+he's not a dummy
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.system.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.system.d
new file mode 100644
index 000000000000..63a850133b3f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.system.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+#pragma D option destructive
+
+BEGIN
+{
+ this->a = 9;
+ this->b = -2;
+
+ system("echo %s %d %d", "foo", this->a, this->b);
+ system("ping -q -c 1 localhost 2>/dev/null | grep -v '^round-trip '");
+ system("echo %d", ++this->a);
+ system("ping -q -c 1 localhost 2>/dev/null | grep -v '^round-trip '");
+ system("echo %d", ++this->a);
+ system("ping -q -c 1 localhost 2>/dev/null | grep -v '^round-trip '");
+ system("echo %d", ++this->a);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.system.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.system.d.out
new file mode 100644
index 000000000000..fa61a5110615
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.system.d.out
@@ -0,0 +1,17 @@
+foo 9 -2
+PING localhost (127.0.0.1): 56 data bytes
+
+--- localhost ping statistics ---
+1 packets transmitted, 1 packets received, 0.0% packet loss
+10
+PING localhost (127.0.0.1): 56 data bytes
+
+--- localhost ping statistics ---
+1 packets transmitted, 1 packets received, 0.0% packet loss
+11
+PING localhost (127.0.0.1): 56 data bytes
+
+--- localhost ping statistics ---
+1 packets transmitted, 1 packets received, 0.0% packet loss
+12
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.tolower.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.tolower.d
new file mode 100644
index 000000000000..2539630e9d66
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.tolower.d
@@ -0,0 +1,66 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+
+ input[i] = "ahi";
+ expected[i++] = "ahi";
+
+ input[i] = "MaHi!";
+ expected[i++] = "mahi!";
+
+ input[i] = " Nase-5";
+ expected[i++] = " nase-5";
+
+ input[i] = "!@#$%";
+ expected[i++] = "!@#$%";
+
+ i = 0;
+}
+
+tick-1ms
+/input[i] != NULL && (this->out = tolower(input[i])) != expected[i]/
+{
+ printf("expected tolower(\"%s\") to be \"%s\"; found \"%s\"\n",
+ input[i], expected[i], this->out);
+ exit(1);
+}
+
+tick-1ms
+/input[i] != NULL/
+{
+ printf("tolower(\"%s\") is \"%s\", as expected\n",
+ input[i], expected[i]);
+}
+
+tick-1ms
+/input[i++] == NULL/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.toupper.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.toupper.d
new file mode 100644
index 000000000000..fd803f2ef0af
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/funcs/tst.toupper.d
@@ -0,0 +1,66 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+
+ input[i] = "ahi";
+ expected[i++] = "AHI";
+
+ input[i] = "MaHi!";
+ expected[i++] = "MAHI!";
+
+ input[i] = " dace-9";
+ expected[i++] = " DACE-9";
+
+ input[i] = "!@#$%";
+ expected[i++] = "!@#$%";
+
+ i = 0;
+}
+
+tick-1ms
+/input[i] != NULL && (this->out = toupper(input[i])) != expected[i]/
+{
+ printf("expected toupper(\"%s\") to be \"%s\"; found \"%s\"\n",
+ input[i], expected[i], this->out);
+ exit(1);
+}
+
+tick-1ms
+/input[i] != NULL/
+{
+ printf("toupper(\"%s\") is \"%s\", as expected\n",
+ input[i], expected[i]);
+}
+
+tick-1ms
+/input[i++] == NULL/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/err.D_ADDROF_LVAL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/err.D_ADDROF_LVAL.d
new file mode 100644
index 000000000000..8f5d694ae51b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/err.D_ADDROF_LVAL.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * & can not be applied to a non-lvalue
+ *
+ * SECTION: Pointers and Arrays/Pointers and Addresses
+ *
+ */
+
+BEGIN
+{
+ trace(&1);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/err.D_EMPTY.empty.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/err.D_EMPTY.empty.d
new file mode 100644
index 000000000000..929ccc69ce84
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/err.D_EMPTY.empty.d
@@ -0,0 +1,34 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test the "empty translation unit" error path.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/tst.clauses.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/tst.clauses.d
new file mode 100644
index 000000000000..a9930292eff3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/tst.clauses.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test the kinds of probe definition clause grammar rules.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations;
+ * Program Structure/Actions
+ */
+
+
+BEGIN
+{}
+
+BEGIN
+/1/
+{}
+
+tick-1
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/tst.stmts.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/tst.stmts.d
new file mode 100644
index 000000000000..03a015ad3229
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/grammar/tst.stmts.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test the various kinds of D probe description statement
+ * rules in the grammar.
+ *
+ * SECTION: Program Structure/Probe Descriptions
+ *
+ */
+
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-1
+/i != 20/
+{
+ i++;
+ x = 0;
+ stack();
+ @a = count();
+ @b = max(x);
+ @c[x] = count();
+ @d[x] = max(x);
+}
+
+tick-1
+/i = 20/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/include/tst.includefirst.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/include/tst.includefirst.ksh
new file mode 100644
index 000000000000..b8240d64367c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/include/tst.includefirst.ksh
@@ -0,0 +1,76 @@
+#
+# 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 (c) 2011, Joyent Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This test verifies that we only use the first entry of a file with a given
+# name in the library path
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+firstinc=${TMPDIR:-/tmp}/firstinc.$$
+secondinc=${TMPDIR:-/tmp}/secondinc.$$
+expexit=23
+
+setup_include()
+{
+ mkdir $firstinc
+ mkdir $secondinc
+ cat > $firstinc/lib.d <<EOF
+inline int foobar = $expexit;
+#pragma D binding "1.0" foobar
+EOF
+ cat > $secondinc/lib.d <<EOF
+inline int foobar = 42;
+#pragma D binding "1.0" foobar
+EOF
+}
+
+clean()
+{
+ rm -rf $firstinc
+ rm -rf $secondinc
+}
+
+fail()
+{
+ echo "$@"
+ clean
+ exit 1
+}
+
+setup_include
+
+dtrace -L$firstinc -L$secondinc -e -n 'BEGIN{ exit(foobar) }'
+[[ $? != 0 ]] && fail "Failed to compile with same file in include path twice"
+dtrace -L$firstinc -L$secondinc -n 'BEGIN{ exit(foobar) }'
+status=$?
+[[ $status != $expexit ]] && fail "Exited with unexpected status code: $status"
+clean
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_DECL_IDRED.redef1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_DECL_IDRED.redef1.d
new file mode 100644
index 000000000000..39f2996ad277
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_DECL_IDRED.redef1.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Test handling of an inline definition that overrides a previous
+ * definition of an inline definition.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ *
+ * NOTES:
+ *
+ */
+
+inline int foo = timestamp;
+inline int foo = 8;
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_DECL_IDRED.redef2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_DECL_IDRED.redef2.d
new file mode 100644
index 000000000000..1df590802866
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_DECL_IDRED.redef2.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Test handling of an inline definition that overrides a previous
+ * definition of a dtrace built-in function.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ *
+ * NOTES:
+ *
+ */
+
+inline int rand = 7;
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_IDENT_UNDEF.recur.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_IDENT_UNDEF.recur.d
new file mode 100644
index 000000000000..95522d0eb60a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_IDENT_UNDEF.recur.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * D program to test recursive inline definitions. This script should
+ * properly detect that foo is undefined on the right-hand side and fail.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ *
+ * NOTES:
+ *
+ */
+
+inline int foo = foo + 3;
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.baddef1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.baddef1.d
new file mode 100644
index 000000000000..1ac1b459d511
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.baddef1.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Attempt to create an invalid inline definition by creating an
+ * inline of a function type. This should fail to compile.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ *
+ * NOTES:
+ *
+ */
+
+inline dtrace_trap_func_t i = "i am a dtrace trap function";
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.baddef2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.baddef2.d
new file mode 100644
index 000000000000..9a246b4b123e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.baddef2.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Attempt to create an invalid inline definition by creating an
+ * inline of incompatible types. This should fail to compile.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ *
+ * NOTES:
+ *
+ */
+
+inline int i = "i am a string";
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.badxlate.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.badxlate.d
new file mode 100644
index 000000000000..d67bdaf4e977
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/err.D_OP_INCOMPAT.badxlate.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Test an invalid inline definition of a translator. An inlined translation
+ * must have the same type as the translator output.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ *
+ * NOTES:
+ *
+ */
+
+inline struct vnode *invalid = xlate<psinfo_t>(curthread->td_proc);
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineDataAssign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineDataAssign.d
new file mode 100644
index 000000000000..c7ab62fd9ce6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineDataAssign.d
@@ -0,0 +1,68 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Declare different types of inline data types.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ *
+ * NOTES: The commented lines defining floats and doubles should be uncommented
+ * once the functionality is provided.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+inline char new_char = 'c';
+inline short new_short = 10;
+inline int new_int = 100;
+inline long new_long = 1234567890;
+inline long long new_long_long = 1234512345;
+inline int8_t new_int8 = 'p';
+inline int16_t new_int16 = 20;
+inline int32_t new_int32 = 200;
+inline int64_t new_int64 = 2000000;
+inline intptr_t new_intptr = 0x12345;
+inline uint8_t new_uint8 = 'q';
+inline uint16_t new_uint16 = 30;
+inline uint32_t new_uint32 = 300;
+inline uint64_t new_uint64 = 3000000;
+inline uintptr_t new_uintptr = 0x67890;
+/* inline float new_float = 1.23456;
+inline double new_double = 2.34567890;
+inline long double new_long_double = 3.567890123;
+*/
+
+inline int * pointer = &`kmem_flags;
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineExpression.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineExpression.d
new file mode 100644
index 000000000000..d67d3f27d0fe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineExpression.d
@@ -0,0 +1,80 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ *
+ * Test different inline assignments by various expressions.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ *
+ * NOTES: The commented lines for the floats and doubles should be uncommented
+ * once the functionality is implemented.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+inline char new_char = 'c' + 2;
+inline short new_short = 10 * new_char;
+inline int new_int = 100 + new_short;
+inline long new_long = 1234567890;
+inline long long new_long_long = 1234512345 * new_long;
+inline int8_t new_int8 = 'p';
+inline int16_t new_int16 = 20 / new_int8;
+inline int32_t new_int32 = 200;
+inline int64_t new_int64 = 2000000 * (-new_int16);
+inline intptr_t new_intptr = 0x12345 - 129;
+inline uint8_t new_uint8 = 'q';
+inline uint16_t new_uint16 = 30 - new_uint8;
+inline uint32_t new_uint32 = 300 - 0;
+inline uint64_t new_uint64 = 3000000;
+inline uintptr_t new_uintptr = 0x67890 / new_uint64;
+
+/* inline float new_float = 1.23456;
+inline double new_double = 2.34567890;
+inline long double new_long_double = 3.567890123;
+*/
+
+inline int * pointer = &`kmem_flags;
+inline int result = 3 > 2 ? 3 : 2;
+
+BEGIN
+{
+ printf("new_char: %c\nnew_short: %d\nnew_int: %d\nnew_long: %d\n",
+ new_char, new_short, new_int, new_long);
+ printf("new_long_long: %d\nnew_int8: %d\nnew_int16: %d\n",
+ new_long_long, new_int8, new_int16);
+ printf("new_int32: %d\nnew_int64: %d\n", new_int32, new_int64);
+ printf("new_intptr: %d\nnew_uint8: %d\nnew_uint16: %d\n",
+ new_intptr, new_uint8, new_uint16);
+ printf("new_uint32:%d\nnew_uint64: %d\nnew_uintptr:%d\nresult:%d",
+ new_uint32, new_uint64, new_uintptr, result);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineKinds.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineKinds.d
new file mode 100644
index 000000000000..7f188fb0d575
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineKinds.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Test the code generation and results of the various kinds of inlines.
+ * In particular, we test constant and expression-based scalar inlines,
+ * associative array inlines, and inlines using translators.
+ */
+
+#pragma D option quiet
+
+inline int i0 = 100 + 23; /* constant-folded integer constant */
+inline string i1 = probename; /* string variable reference */
+inline int i2 = pid != 0; /* expression involving a variable */
+
+struct s {
+ int s_x;
+};
+
+translator struct s < int T > {
+ s_x = T + 1;
+};
+
+inline struct s i3 = xlate < struct s > (i0); /* translator */
+inline int i4[int x, int y] = x + y; /* associative array */
+inline int i5[int x] = (xlate < struct s > (x)).s_x; /* array by xlate */
+
+BEGIN
+{
+ printf("i0 = %d\n", i0);
+ printf("i1 = %s\n", i1);
+ printf("i2 = %d\n", i2);
+
+ printf("i3.s_x = %d\n", i3.s_x);
+ printf("i4[10, 20] = %d\n", i4[10, 20]);
+ printf("i5[123] = %d\n", i5[123]);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineKinds.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineKinds.d.out
new file mode 100644
index 000000000000..c9a603b24ef0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineKinds.d.out
@@ -0,0 +1,7 @@
+i0 = 123
+i1 = BEGIN
+i2 = 1
+i3.s_x = 124
+i4[10, 20] = 30
+i5[123] = 124
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineTypedef.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineTypedef.d
new file mode 100644
index 000000000000..a6247659afa8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineTypedef.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Create inline names from aliases created using typedef.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ *
+ * NOTES:
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+typedef char new_char;
+inline new_char char_var = 'c';
+
+typedef int * pointer;
+inline pointer p = &`kmem_flags;
+
+BEGIN
+{
+ printf("char_var: %c\npointer p: %d", char_var, *p);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineWritableAssign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineWritableAssign.d
new file mode 100644
index 000000000000..a7842a334da3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/inline/tst.InlineWritableAssign.d
@@ -0,0 +1,66 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Create inline names from aliases created using typedef.
+ *
+ * SECTION: Type and Constant Definitions/Inlines
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+struct record {
+ char c;
+ int i;
+};
+
+struct record rec1;
+inline struct record rec2 = rec1;
+
+union var {
+ char c;
+ int i;
+};
+
+union var un1;
+inline union var un2 = un1;
+
+
+BEGIN
+{
+ rec1.c = 'c';
+ rec1.i = 10;
+
+ un1.c = 'd';
+
+ printf("rec1.c: %c\nrec1.i:%d\nun1.c: %c\n", rec1.c, rec1.i, un1.c);
+ printf("rec2.c: %c\nrec2.i:%d\nun2.c: %c\n", rec2.c, rec2.i, un2.c);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.c
new file mode 100644
index 000000000000..9b878a21b91d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.c
@@ -0,0 +1,101 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/ioctl.h>
+
+#include <assert.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+static sigjmp_buf env;
+
+static void
+interrupt(int sig)
+{
+ siglongjmp(env, sig);
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *file = "/dev/null";
+ int i, n, fds[10];
+ struct sigaction act;
+
+ if (argc > 1) {
+ (void) fprintf(stderr, "Usage: %s\n", argv[0]);
+ return (EXIT_FAILURE);
+ }
+
+ act.sa_handler = interrupt;
+ act.sa_flags = 0;
+
+ (void) sigemptyset(&act.sa_mask);
+ (void) sigaction(SIGUSR1, &act, NULL);
+
+ closefrom(0);
+ n = 0;
+
+ /*
+ * With all of our file descriptors closed, wait here spinning in bogus
+ * ioctl() calls until DTrace hits us with a SIGUSR1 to start the test.
+ */
+ if (sigsetjmp(env, 1) == 0) {
+ for (;;)
+ (void) ioctl(-1, 0, NULL);
+ }
+
+ /*
+ * To test the fds[] array, we open /dev/null (a file with reliable
+ * pathname and properties) using various flags and seek offsets.
+ */
+ fds[n++] = open(file, O_RDONLY);
+ fds[n++] = open(file, O_WRONLY);
+ fds[n++] = open(file, O_RDWR);
+
+ fds[n++] = open(file, O_RDWR | O_APPEND | O_CREAT |
+ O_NOCTTY | O_NONBLOCK | O_NDELAY | O_SYNC | O_TRUNC | 0666);
+
+ fds[n++] = open(file, O_RDWR);
+ (void) lseek(fds[n - 1], 123, SEEK_SET);
+
+ /*
+ * Once we have all the file descriptors in the state we want to test,
+ * issue a bogus ioctl() on each fd with cmd 0 and arg NULL to whack
+ * our DTrace script into recording the content of the fds[] array.
+ */
+ for (i = 0; i < n; i++)
+ (void) ioctl(fds[i], 0, NULL);
+
+ assert(n <= sizeof (fds) / sizeof (fds[0]));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.d
new file mode 100644
index 000000000000..86851421788c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option destructive
+#pragma D option quiet
+
+syscall::ioctl:entry
+/pid == $1 && arg0 == -1u/
+{
+ raise(SIGUSR1); /* kick tst.fds.c out of its busy-wait loop */
+}
+
+syscall::ioctl:entry
+/pid == $1 && arg0 != -1u && arg1 == 0 && arg2 == NULL/
+{
+ printf("fds[%d] fi_name = %s\n", arg0, fds[arg0].fi_name);
+ printf("fds[%d] fi_dirname = %s\n", arg0, fds[arg0].fi_dirname);
+ printf("fds[%d] fi_pathname = %s\n", arg0, fds[arg0].fi_pathname);
+ printf("fds[%d] fi_fs = %s\n", arg0, fds[arg0].fi_fs);
+ printf("fds[%d] fi_mount = %s\n", arg0, fds[arg0].fi_mount);
+ printf("fds[%d] fi_offset = %d\n", arg0, fds[arg0].fi_offset);
+ printf("fds[%d] fi_oflags = 0x%x\n", arg0, fds[arg0].fi_oflags);
+}
+
+proc:::exit
+/pid == $1/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.d.out
new file mode 100644
index 000000000000..9d268268570d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/io/tst.fds.d.out
@@ -0,0 +1,36 @@
+fds[0] fi_name = mm@0:null
+fds[0] fi_dirname = /devices/pseudo
+fds[0] fi_pathname = /devices/pseudo/mm@0:null
+fds[0] fi_fs = specfs
+fds[0] fi_mount = /devices
+fds[0] fi_offset = 0
+fds[0] fi_oflags = 0x0
+fds[1] fi_name = mm@0:null
+fds[1] fi_dirname = /devices/pseudo
+fds[1] fi_pathname = /devices/pseudo/mm@0:null
+fds[1] fi_fs = specfs
+fds[1] fi_mount = /devices
+fds[1] fi_offset = 0
+fds[1] fi_oflags = 0x1
+fds[2] fi_name = mm@0:null
+fds[2] fi_dirname = /devices/pseudo
+fds[2] fi_pathname = /devices/pseudo/mm@0:null
+fds[2] fi_fs = specfs
+fds[2] fi_mount = /devices
+fds[2] fi_offset = 0
+fds[2] fi_oflags = 0x2
+fds[3] fi_name = mm@0:null
+fds[3] fi_dirname = /devices/pseudo
+fds[3] fi_pathname = /devices/pseudo/mm@0:null
+fds[3] fi_fs = specfs
+fds[3] fi_mount = /devices
+fds[3] fi_offset = 0
+fds[3] fi_oflags = 0xebda
+fds[4] fi_name = mm@0:null
+fds[4] fi_dirname = /devices/pseudo
+fds[4] fi_pathname = /devices/pseudo/mm@0:null
+fds[4] fi_fs = specfs
+fds[4] fi_mount = /devices
+fds[4] fi_offset = 123
+fds[4] fi_oflags = 0x2
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/get.ipv4remote.pl b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/get.ipv4remote.pl
new file mode 100755
index 000000000000..c07e46bbd976
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/get.ipv4remote.pl
@@ -0,0 +1,107 @@
+#!/usr/bin/env perl
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#
+# get.ipv4remote.pl [port] [proto]
+#
+# Find an IPv4 reachable remote host using both ifconfig(1M) and ping(1M).
+# If a port is specified, return a host that is also listening on this
+# port. If the port is specified, the protocol can also be specified and
+# defaults to tcp. Print the local address and the remote address, or an
+# error message if no suitable remote host was found. Exit status is 0 if
+# a host was found.
+#
+
+use strict;
+use IO::Socket;
+
+my $MAXHOSTS = 32; # max hosts to port scan
+my $TIMEOUT = 3; # connection timeout
+my $port = @ARGV >= 1 ? $ARGV[0] : 0;
+my $proto = @ARGV == 2 ? $ARGV[1] : "tcp";
+
+#
+# Determine local IP address
+#
+my $local = "";
+my $remote = "";
+my %Broadcast;
+my $up;
+open IFCONFIG, '/sbin/ifconfig -a |' or die "Couldn't run ifconfig: $!\n";
+while (<IFCONFIG>) {
+ next if /^lo/;
+
+ # "UP" is always printed first (see print_flags() in ifconfig.c):
+ $up = 1 if /^[a-z].*<UP,/;
+ $up = 0 if /^[a-z].*<,/;
+
+ # assume output is "inet X ... broadcast Z":
+ if (/inet (\S+) .* broadcast (\S+)/) {
+ my ($addr, $bcast) = ($1, $2);
+ $Broadcast{$addr} = $bcast;
+ $local = $addr if $up and $local eq "";
+ $up = 0;
+ }
+}
+close IFCONFIG;
+die "Could not determine local IP address" if $local eq "";
+
+#
+# Find the first remote host that responds to an icmp echo,
+# which isn't a local address.
+#
+open PING, "/sbin/ping -n -s 56 -c $MAXHOSTS $Broadcast{$local} |" or
+ die "Couldn't run ping: $!\n";
+while (<PING>) {
+ if (/bytes from (.*): / and not defined $Broadcast{$1}) {
+ my $addr = $1;
+
+ if ($port != 0) {
+ #
+ # Test TCP
+ #
+ my $socket = IO::Socket::INET->new(
+ Type => SOCK_STREAM,
+ Proto => $proto,
+ PeerAddr => $addr,
+ PeerPort => $port,
+ Timeout => $TIMEOUT,
+ );
+ next unless $socket;
+ close $socket;
+ }
+
+ $remote = $addr;
+ last;
+ }
+}
+close PING;
+die "Can't find a remote host for testing: No suitable response from " .
+ "$Broadcast{$local}\n" if $remote eq "";
+
+print "$local $remote\n";
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/get.ipv6remote.pl b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/get.ipv6remote.pl
new file mode 100755
index 000000000000..fbfcdfdab35f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/get.ipv6remote.pl
@@ -0,0 +1,97 @@
+#!/usr/bin/env perl
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#
+# get.ipv6remote.pl
+#
+# Find an IPv6 reachable remote host using both ifconfig(1M) and ping(1M).
+# Print the local address and the remote address, or print nothing if either
+# no IPv6 interfaces or remote hosts were found. (Remote IPv6 testing is
+# considered optional, and so not finding another IPv6 host is not an error
+# state we need to log.) Exit status is 0 if a host was found.
+#
+
+use strict;
+use IO::Socket;
+
+my $MAXHOSTS = 32; # max hosts to scan
+my $TIMEOUT = 3; # connection timeout
+my $MULTICAST = "FF02::1"; # IPv6 multicast address
+
+#
+# Determine local IP address
+#
+my $local = "";
+my $remote = "";
+my $interf = "";
+my %Local;
+my %Addr;
+my $up;
+open IFCONFIG, '/sbin/ifconfig -a inet6 |'
+ or die "Couldn't run ifconfig: $!\n";
+while (<IFCONFIG>) {
+ next if /^lo/;
+
+ # "UP" is always printed first (see print_flags() in ifconfig.c):
+ $up = 1 if /^[a-z].*<UP,/;
+ $up = 0 if /^[a-z].*<,/;
+
+ if (m:(\S+\d+)\: :) {
+ $interf = $1;
+ }
+
+ # assume output is "inet6 ...":
+ if (m:inet6 (\S+) :) {
+ my $addr = $1;
+ $Local{$addr} = 1;
+ $Addr{$interf} = $addr;
+ $up = 0;
+ $interf = "";
+ }
+}
+close IFCONFIG;
+
+#
+# Find the first remote host that responds to an icmp echo,
+# which isn't a local address. Try each IPv6-enabled interface.
+#
+foreach $interf (split(' ', `ifconfig -l -u inet6`)) {
+ next if $interf =~ /lo[0-9]+/;
+ open PING, "/sbin/ping6 -n -s 56 -c $MAXHOSTS $MULTICAST\%$interf |" or next;
+ while (<PING>) {
+ if (/bytes from (.*), / and not defined $Local{$1}) {
+ $remote = $1;
+ $local = $Addr{$interf};
+ last;
+ }
+ }
+}
+close PING;
+exit 2 if $remote eq "";
+
+print "$local $remote\n";
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh
new file mode 100755
index 000000000000..88a619edf589
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh
@@ -0,0 +1,71 @@
+#!/usr/bin/env ksh
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#
+# Test ip:::{send,receive} of IPv4 ICMP to a local address.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. The lo0 interface missing or not up.
+# 3. Unrelated ICMP on lo0 traced by accident.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+local=127.0.0.1
+
+$dtrace -c "/sbin/ping -q -c 1 -t 3 $local" -qs /dev/stdin <<EOF | sort -n | \
+ grep -v -e '^round-trip ' -e '^--- '
+ip:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_ICMP/
+{
+ printf("2 ip:::send (");
+ printf("args[2]: %d %d, ", args[2]->ip_ver, args[2]->ip_plength);
+ printf("args[4]: %d %d %d %d %d)\n",
+ args[4]->ipv4_ver, args[4]->ipv4_length, args[4]->ipv4_flags,
+ args[4]->ipv4_offset, args[4]->ipv4_ttl);
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_ICMP/
+{
+ printf("3 ip:::receive (");
+ printf("args[2]: %d %d, ", args[2]->ip_ver, args[2]->ip_plength);
+ printf("args[4]: %d %d %d %d %d)\n",
+ args[4]->ipv4_ver, args[4]->ipv4_length, args[4]->ipv4_flags,
+ args[4]->ipv4_offset, args[4]->ipv4_ttl);
+}
+EOF
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh.out
new file mode 100644
index 000000000000..c62b0c8e2557
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh.out
@@ -0,0 +1,8 @@
+
+
+PING 127.0.0.1 (127.0.0.1): 56 data bytes
+1 packets transmitted, 1 packets received, 0.0% packet loss
+2 ip:::send (args[2]: 4 64, args[4]: 4 84 0 0 64)
+2 ip:::send (args[2]: 4 64, args[4]: 4 84 0 0 64)
+3 ip:::receive (args[2]: 4 64, args[4]: 4 84 0 0 64)
+3 ip:::receive (args[2]: 4 64, args[4]: 4 84 0 0 64)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localsctp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localsctp.ksh
new file mode 100755
index 000000000000..1b151578afef
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localsctp.ksh
@@ -0,0 +1,153 @@
+#!/usr/bin/env ksh
+#
+# 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test {ip,sctp}:::{send,receive} of IPv4 SCTP to local host.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. The lo0 interface missing or not up.
+# 3. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test performs a SCTP association and checks that at least the
+# following packet counts were traced:
+#
+# 7 x ip:::send (4 during the setup, 3 during the teardown)
+# 7 x sctp:::send (4 during the setup, 3 during the teardown)
+# 7 x ip:::receive (4 during the setup, 3 during the teardown)
+# 7 x sctp:::receive (4 during the setup, 3 during the teardown)
+
+# The actual count tested is 7 each way, since we are tracing both
+# source and destination events.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+local=127.0.0.1
+DIR=/var/tmp/dtest.$$
+
+sctpport=1024
+bound=5000
+
+mkdir $DIR
+cd $DIR
+
+cat > client.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Type => SOCK_STREAM,
+ Proto => "sctp",
+ LocalAddr => "$local",
+ PeerAddr => "$local",
+ PeerPort => \$ARGV[0],
+ Timeout => 3);
+ die "Could not connect to host $local port \$ARGV[0] \$@" unless \$s;
+ close \$s;
+ sleep(\$ARGV[1]);
+EOPERL
+
+while [ $sctpport -lt $bound ]; do
+ perl client.pl $sctpport 0 2>&- || break
+ sctpport=$(($sctpport + 1))
+done
+if [ $sctpport -eq $bound ]; then
+ echo "couldn't find an available SCTP port"
+ exit 1
+fi
+
+cat > server.pl <<-EOPERL
+ use IO::Socket;
+ my \$l = IO::Socket::INET->new(
+ Type => SOCK_STREAM,
+ Proto => "sctp",
+ LocalAddr => "$local",
+ LocalPort => $sctpport,
+ Listen => 1,
+ Reuse => 1);
+ die "Could not listen on $local port $sctpport \$@" unless \$l;
+ my \$c = \$l->accept();
+ close \$l;
+ while (<\$c>) {};
+ close \$c;
+EOPERL
+
+perl server.pl &
+
+$dtrace -c "perl client.pl $sctpport 2" -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = sctpsend = ipreceive = sctpreceive = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_SCTP/
+{
+ ipsend++;
+}
+
+sctp:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/
+{
+ sctpsend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_SCTP/
+{
+ ipreceive++;
+}
+
+sctp:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/
+{
+ sctpreceive++;
+}
+
+END
+{
+ printf("Minimum SCTP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 7 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 7 ? "yes" : "no");
+ printf("sctp:::send - %s\n", sctpsend >= 7 ? "yes" : "no");
+ printf("sctp:::receive - %s\n", sctpreceive >= 7 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localsctp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localsctp.ksh.out
new file mode 100644
index 000000000000..8c708770971b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localsctp.ksh.out
@@ -0,0 +1,7 @@
+Minimum SCTP events seen
+
+ip:::send - yes
+ip:::receive - yes
+sctp:::send - yes
+sctp:::receive - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh
new file mode 100755
index 000000000000..42e1372c9c81
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh
@@ -0,0 +1,135 @@
+#!/usr/bin/env ksh
+#
+# 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test {ip,tcp}:::{send,receive} of IPv4 TCP to local host.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. The lo0 interface missing or not up.
+# 3. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test performs a TCP connection and checks that at least the
+# following packet counts were traced:
+#
+# 7 x ip:::send (3 during the setup, 4 during the teardown)
+# 7 x tcp:::send (3 during the setup, 4 during the teardown)
+# 7 x ip:::receive (3 during the setup, 4 during the teardown)
+# 7 x tcp:::receive (3 during the setup, 4 during the teardown)
+
+# The actual count tested is 7 each way, since we are tracing both
+# source and destination events.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+local=127.0.0.1
+DIR=/var/tmp/dtest.$$
+
+tcpport=1024
+bound=5000
+while [ $tcpport -lt $bound ]; do
+ nc -z $local $tcpport >/dev/null || break
+ tcpport=$(($tcpport + 1))
+done
+if [ $tcpport -eq $bound ]; then
+ echo "couldn't find an available TCP port"
+ exit 1
+fi
+
+mkdir $DIR
+cd $DIR
+
+# nc will exit when the connection is closed.
+nc -l $local $tcpport &
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Proto => "tcp",
+ PeerAddr => "$local",
+ PeerPort => $tcpport,
+ Timeout => 3);
+ die "Could not connect to host $local port $tcpport" unless \$s;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = tcpsend = ipreceive = tcpreceive = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_TCP/
+{
+ ipsend++;
+}
+
+tcp:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/
+{
+ tcpsend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_TCP/
+{
+ ipreceive++;
+}
+
+tcp:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/
+{
+ tcpreceive++;
+}
+
+END
+{
+ printf("Minimum TCP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 7 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 7 ? "yes" : "no");
+ printf("tcp:::send - %s\n", tcpsend >= 7 ? "yes" : "no");
+ printf("tcp:::receive - %s\n", tcpreceive >= 7 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh.out
new file mode 100644
index 000000000000..2a85b98b6b7d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh.out
@@ -0,0 +1,7 @@
+Minimum TCP events seen
+
+ip:::send - yes
+ip:::receive - yes
+tcp:::send - yes
+tcp:::receive - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh
new file mode 100755
index 000000000000..196448b66027
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh
@@ -0,0 +1,124 @@
+#!/usr/bin/env ksh
+#
+# 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test {ip,udp}:::{send,receive} of IPv4 UDP to a local address.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. No physical network interface is plumbed and up.
+# 3. No other hosts on this subnet are reachable and listening on rpcbind.
+# 4. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test sends a UDP message using perl and checks that at least the
+# following counts were traced:
+#
+# 1 x ip:::send (UDP sent to UDP port 33434)
+# 1 x udp:::send (UDP sent to UDP port 33434)
+# 1 x ip:::receive (UDP received)
+# 1 x udp:::receive (UDP received)
+#
+# A udp:::receive event is expected even if the received UDP packet
+# elicits an ICMP PORT_UNREACHABLE message since there is no UDP
+# socket for receiving the packet.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+local=127.0.0.1
+port=33434
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Proto => "udp",
+ PeerAddr => "$local",
+ PeerPort => $port);
+ die "Could not create UDP socket $local port $port" unless \$s;
+ send \$s, "Hello", 0;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = udpsend = ipreceive = udpreceive = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_UDP/
+{
+ ipsend++;
+}
+
+udp:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/
+{
+ udpsend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_UDP/
+{
+ ipreceive++;
+}
+
+udp:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/
+{
+ udpreceive++;
+}
+
+END
+{
+ printf("Minimum UDP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 1 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 1 ? "yes" : "no");
+ printf("udp:::send - %s\n", udpsend >= 1 ? "yes" : "no");
+ printf("udp:::receive - %s\n", udpreceive >= 1 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh.out
new file mode 100644
index 000000000000..d94aa3104dad
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh.out
@@ -0,0 +1,7 @@
+Minimum UDP events seen
+
+ip:::send - yes
+ip:::receive - yes
+udp:::send - yes
+udp:::receive - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudplite.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudplite.ksh
new file mode 100755
index 000000000000..902d278a8388
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudplite.ksh
@@ -0,0 +1,125 @@
+#!/usr/bin/env ksh
+#
+# 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test {ip,udplite}:::{send,receive} of IPv4 UDP-Lite to a local address.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. No physical network interface is plumbed and up.
+# 3. No other hosts on this subnet are reachable and listening on rpcbind.
+# 4. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test sends a UDP-Lite message using perl and checks that at least the
+# following counts were traced:
+#
+# 1 x ip:::send (UDPLite sent to UDP-Lite port 33434)
+# 1 x udplite:::send (UDPLite sent to UDP-Lite port 33434)
+# 1 x ip:::receive (UDP-Lite received)
+# 1 x udplite:::receive (UDP-Lite received)
+#
+# A udplite:::receive event is expected even if the received UDP-Lite packet
+# elicits an ICMP PORT_UNREACHABLE message since there is no UDP-Lite
+# socket for receiving the packet.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+local=127.0.0.1
+port=33434
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Type => SOCK_DGRAM,
+ Proto => "udplite",
+ PeerAddr => "$local",
+ PeerPort => $port);
+ die "Could not create UDP-Lite socket $local port $port" unless \$s;
+ send \$s, "Hello", 0;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = udplitesend = ipreceive = udplitereceive = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_UDPLITE/
+{
+ ipsend++;
+}
+
+udplite:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/
+{
+ udplitesend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_UDPLITE/
+{
+ ipreceive++;
+}
+
+udplite:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/
+{
+ udplitereceive++;
+}
+
+END
+{
+ printf("Minimum UDP-Lite events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 1 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 1 ? "yes" : "no");
+ printf("udplite:::send - %s\n", udplitesend >= 1 ? "yes" : "no");
+ printf("udplite:::receive - %s\n", udplitereceive >= 1 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudplite.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudplite.ksh.out
new file mode 100644
index 000000000000..b5970ffa57fb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4localudplite.ksh.out
@@ -0,0 +1,7 @@
+Minimum UDP-Lite events seen
+
+ip:::send - yes
+ip:::receive - yes
+udplite:::send - yes
+udplite:::receive - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh
new file mode 100755
index 000000000000..7b456aa61f46
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh
@@ -0,0 +1,81 @@
+#!/usr/bin/env ksh93
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#
+# Test ip:::{send,receive} of IPv4 ICMP to a remote host.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. No physical network interface is plumbed and up.
+# 3. No other hosts on this subnet are reachable.
+# 4. An unrelated ICMP between these hosts was traced by accident.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+getaddr=./get.ipv4remote.pl
+
+if [[ ! -x $getaddr ]]; then
+ print -u2 "could not find or execute sub program: $getaddr"
+ exit 3
+fi
+$getaddr | read source dest
+if (( $? != 0 )); then
+ exit 4
+fi
+
+$dtrace -c "/sbin/ping $dest 3" -qs /dev/stdin <<EOF | \
+ grep -v 'is alive' | sort -n
+ip:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->ipv4_protocol == IPPROTO_ICMP/
+{
+ printf("1 ip:::send (");
+ printf("args[2]: %d %d, ", args[2]->ip_ver, args[2]->ip_plength);
+ printf("args[4]: %d %d %d %d %d)\n",
+ args[4]->ipv4_ver, args[4]->ipv4_length, args[4]->ipv4_flags,
+ args[4]->ipv4_offset, args[4]->ipv4_ttl);
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" &&
+ args[4]->ipv4_protocol == IPPROTO_ICMP/
+{
+ printf("2 ip:::receive (");
+ printf("args[2]: %d %d, ", args[2]->ip_ver, args[2]->ip_plength);
+ printf("args[4]: %d %d %d %d %d)\n",
+ args[4]->ipv4_ver, args[4]->ipv4_length, args[4]->ipv4_flags,
+ args[4]->ipv4_offset, args[4]->ipv4_ttl);
+}
+EOF
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh.out
new file mode 100644
index 000000000000..b5915f8db477
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh.out
@@ -0,0 +1,3 @@
+
+1 ip:::send (args[2]: 4 64, args[4]: 4 84 0 0 255)
+2 ip:::receive (args[2]: 4 64, args[4]: 4 84 4 0 255)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotesctp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotesctp.ksh
new file mode 100755
index 000000000000..60dabf7a8b94
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotesctp.ksh
@@ -0,0 +1,130 @@
+#!/usr/bin/env ksh93
+#
+# 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test {sctp,ip}:::{send,receive} of IPv4 SCTP to a remote host.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. No physical network interface is plumbed and up.
+# 3. No other hosts on this subnet are reachable and listening on ssh.
+# 4. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test performs an SCTP association and checks that at least the
+# following packet counts were traced:
+#
+# 4 x ip:::send (2 during setup, 2 during teardown)
+# 4 x sctp:::send (2 during connection setup, 2 during connection teardown)
+# 3 x ip:::receive (2 during setup, 1 during teardown)
+# 3 x sctp:::receive (2 during setup, 1 during teardown)
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+getaddr=./get.ipv4remote.pl
+sctpport=80
+DIR=/var/tmp/dtest.$$
+
+if [[ ! -x $getaddr ]]; then
+ print -u2 "could not find or execute sub program: $getaddr"
+ exit 3
+fi
+$getaddr $sctpport sctp | read source dest
+if (( $? != 0 )); then
+ exit 4
+fi
+
+mkdir $DIR
+cd $DIR
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Type => SOCK_STREAM,
+ Proto => "sctp",
+ LocalAddr => "$source",
+ PeerAddr => "$dest",
+ PeerPort => $sctpport,
+ Timeout => 3);
+ die "Could not connect to host $dest port $sctpport \$@" unless \$s;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = sctpsend = ipreceive = sctpreceive = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->ipv4_protocol == IPPROTO_SCTP/
+{
+ ipsend++;
+}
+
+sctp:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest"/
+{
+ sctpsend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" &&
+ args[4]->ipv4_protocol == IPPROTO_SCTP/
+{
+ ipreceive++;
+}
+
+sctp:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source"/
+{
+ sctpreceive++;
+}
+
+END
+{
+ printf("Minimum SCTP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 4 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 3 ? "yes" : "no");
+ printf("sctp:::send - %s\n", sctpsend >= 4 ? "yes" : "no");
+ printf("sctp:::receive - %s\n", sctpreceive >= 3 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotesctp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotesctp.ksh.out
new file mode 100644
index 000000000000..8c708770971b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotesctp.ksh.out
@@ -0,0 +1,7 @@
+Minimum SCTP events seen
+
+ip:::send - yes
+ip:::receive - yes
+sctp:::send - yes
+sctp:::receive - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh
new file mode 100755
index 000000000000..6eda63f90c1d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh
@@ -0,0 +1,131 @@
+#!/usr/bin/env ksh93
+#
+# 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test {tcp,ip}:::{send,receive} of IPv4 TCP to a remote host.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. No physical network interface is plumbed and up.
+# 3. No other hosts on this subnet are reachable and listening on ssh.
+# 4. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test performs a TCP connection and checks that at least the
+# following packet counts were traced:
+#
+# 4 x ip:::send (2 during connection setup, 2 during connection teardown)
+# 4 x tcp:::send (2 during connection setup, 2 during connection teardown)
+# 5 x ip:::receive (1 during connection setup, the response, 1 window update,
+# 1 banner line, 2 during connection teardown)
+# 5 x tcp:::receive (1 during connection setup, the response, 1 window update,
+# 1 banner line, 2 during connection teardown)
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+getaddr=./get.ipv4remote.pl
+tcpport=22
+DIR=/var/tmp/dtest.$$
+
+if [[ ! -x $getaddr ]]; then
+ print -u2 "could not find or execute sub program: $getaddr"
+ exit 3
+fi
+$getaddr $tcpport | read source dest
+if (( $? != 0 )); then
+ exit 4
+fi
+
+mkdir $DIR
+cd $DIR
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Proto => "tcp",
+ PeerAddr => "$dest",
+ PeerPort => $tcpport,
+ Timeout => 3);
+ die "Could not connect to host $dest port $tcpport" unless \$s;
+ readline \$s;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = tcpsend = ipreceive = tcpreceive = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->ipv4_protocol == IPPROTO_TCP/
+{
+ ipsend++;
+}
+
+tcp:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest"/
+{
+ tcpsend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" &&
+ args[4]->ipv4_protocol == IPPROTO_TCP/
+{
+ ipreceive++;
+}
+
+tcp:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source"/
+{
+ tcpreceive++;
+}
+
+END
+{
+ printf("Minimum TCP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 4 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 5 ? "yes" : "no");
+ printf("tcp:::send - %s\n", tcpsend >= 4 ? "yes" : "no");
+ printf("tcp:::receive - %s\n", tcpreceive >= 5 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh.out
new file mode 100644
index 000000000000..2a85b98b6b7d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh.out
@@ -0,0 +1,7 @@
+Minimum TCP events seen
+
+ip:::send - yes
+ip:::receive - yes
+tcp:::send - yes
+tcp:::receive - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh
new file mode 100755
index 000000000000..e16034c95c4d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh
@@ -0,0 +1,112 @@
+#!/usr/bin/env ksh93
+#
+# 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test {udp,ip}:::{send,receive} of IPv4 UDP to a remote host.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. No physical network interface is plumbed and up.
+# 3. No other hosts on this subnet are reachable and listening on rpcbind.
+# 4. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test sends a UDP message using perl and checks that at least the
+# following counts were traced:
+#
+# 1 x ip:::send (UDP sent to ping's base UDP port)
+# 1 x udp:::send (UDP sent to ping's base UDP port)
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+getaddr=./get.ipv4remote.pl
+port=33434
+DIR=/var/tmp/dtest.$$
+
+if [[ ! -x $getaddr ]]; then
+ print -u2 "could not find or execute sub program: $getaddr"
+ exit 3
+fi
+$getaddr | read source dest
+if (( $? != 0 )); then
+ exit 4
+fi
+
+mkdir $DIR
+cd $DIR
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Proto => "udp",
+ PeerAddr => "$dest",
+ PeerPort => $port);
+ die "Could not create UDP socket $dest port $port" unless \$s;
+ send \$s, "Hello", 0;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = udpsend = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->ipv4_protocol == IPPROTO_UDP/
+{
+ ipsend++;
+}
+
+udp:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest"/
+{
+ udpsend++;
+}
+
+END
+{
+ printf("Minimum UDP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 1 ? "yes" : "no");
+ printf("udp:::send - %s\n", udpsend >= 1 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh.out
new file mode 100644
index 000000000000..bdbbe1fd6562
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh.out
@@ -0,0 +1,5 @@
+Minimum UDP events seen
+
+ip:::send - yes
+udp:::send - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudplite.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudplite.ksh
new file mode 100755
index 000000000000..8837112d5d78
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudplite.ksh
@@ -0,0 +1,113 @@
+#!/usr/bin/env ksh93
+#
+# 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test {udplite,ip}:::{send,receive} of IPv4 UDP-Lite to a remote host.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. No physical network interface is plumbed and up.
+# 3. No other hosts on this subnet are reachable and listening on rpcbind.
+# 4. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test sends a UDP-Lite message using perl and checks that at least the
+# following counts were traced:
+#
+# 1 x ip:::send (UDP-Lite sent to UDP-Lite port 33434)
+# 1 x udplite:::send (UDP-Lite sent to UDP-Lite port 33434)
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+getaddr=./get.ipv4remote.pl
+port=33434
+DIR=/var/tmp/dtest.$$
+
+if [[ ! -x $getaddr ]]; then
+ print -u2 "could not find or execute sub program: $getaddr"
+ exit 3
+fi
+$getaddr | read source dest
+if (( $? != 0 )); then
+ exit 4
+fi
+
+mkdir $DIR
+cd $DIR
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Type => SOCK_DGRAM,
+ Proto => "udplite",
+ PeerAddr => "$dest",
+ PeerPort => $port);
+ die "Could not create UDP-Lite socket $dest port $port" unless \$s;
+ send \$s, "Hello", 0;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = udplitesend = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->ipv4_protocol == IPPROTO_UDPLITE/
+{
+ ipsend++;
+}
+
+udplite:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest"/
+{
+ udplitesend++;
+}
+
+END
+{
+ printf("Minimum UDPLite events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 1 ? "yes" : "no");
+ printf("udplite:::send - %s\n", udplitesend >= 1 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudplite.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudplite.ksh.out
new file mode 100644
index 000000000000..66e39e736e23
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudplite.ksh.out
@@ -0,0 +1,5 @@
+Minimum UDP-Lite events seen
+
+ip:::send - yes
+udplite:::send - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6localicmp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6localicmp.ksh
new file mode 100755
index 000000000000..96ec03be1ba3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6localicmp.ksh
@@ -0,0 +1,83 @@
+#!/usr/bin/env ksh
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#
+# Test ip:::{send,receive} of IPv6 ICMP to a local address. This creates a
+# temporary lo0/inet6 interface if one doesn't already exist.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. Unrelated ICMPv6 on lo0 traced by accident.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+local=::1
+
+if ! ifconfig lo0 inet6 > /dev/null 2>&1; then
+ if ! ifconfig lo0 inet6 plumb up; then
+ print -u2 "could not plumb lo0 inet6 for testing"
+ exit 3
+ fi
+ removeinet6=1
+else
+ removeinet6=0
+fi
+
+$dtrace -c "/sbin/ping6 -q -c 1 -t 3 $local" -qs /dev/stdin <<EOF | sort -n | \
+ grep -v -e '^round-trip ' -e '^--- '
+ip:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[5]->ipv6_nexthdr == IPPROTO_ICMPV6/
+{
+ printf("2 ip:::send (");
+ printf("args[2]: %d %d, ", args[2]->ip_ver, args[2]->ip_plength);
+ printf("args[5]: %d %d %d)\n",
+ args[5]->ipv6_ver, args[5]->ipv6_tclass, args[5]->ipv6_plen);
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[5]->ipv6_nexthdr == IPPROTO_ICMPV6/
+{
+ printf("3 ip:::receive (");
+ printf("args[2]: %d %d, ", args[2]->ip_ver, args[2]->ip_plength);
+ printf("args[5]: %d %d %d)\n",
+ args[5]->ipv6_ver, args[5]->ipv6_tclass, args[5]->ipv6_plen);
+}
+EOF
+
+if (( removeinet6 )); then
+ ifconfig lo0 inet6 unplumb
+fi
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6localicmp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6localicmp.ksh.out
new file mode 100644
index 000000000000..2e94ff35de88
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6localicmp.ksh.out
@@ -0,0 +1,8 @@
+
+
+PING6(56=40+8+8 bytes) ::1 --> ::1
+1 packets transmitted, 1 packets received, 0.0% packet loss
+2 ip:::send (args[2]: 6 16, args[5]: 6 0 16)
+2 ip:::send (args[2]: 6 16, args[5]: 6 0 16)
+3 ip:::receive (args[2]: 6 16, args[5]: 6 0 16)
+3 ip:::receive (args[2]: 6 16, args[5]: 6 0 16)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6remoteicmp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6remoteicmp.ksh
new file mode 100755
index 000000000000..303a1e455680
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6remoteicmp.ksh
@@ -0,0 +1,88 @@
+#!/usr/bin/env ksh93
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#
+# Test ip:::{send,receive} of IPv6 ICMP to a remote host. This test is
+# skipped if there are no physical interfaces configured with IPv6, or no
+# other IPv6 hosts are reachable.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. An unrelated ICMPv6 between these hosts was traced by accident.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+getaddr=./get.ipv6remote.pl
+
+if [[ ! -x $getaddr ]]; then
+ print -u2 "could not find or execute sub program: $getaddr"
+ exit 3
+fi
+$getaddr | read source dest
+if (( $? != 0 )); then
+ print -nu2 "Could not find a local IPv6 interface and a remote IPv6 "
+ print -u2 "host. Aborting test.\n"
+ print -nu2 "For this test to continue, a \"ping -ns -A inet6 FF02::1\" "
+ print -u2 "must respond with a\nremote IPv6 host."
+ exit 3
+fi
+
+#
+# Shake loose any ICMPv6 Neighbor advertisement messages before tracing.
+#
+/sbin/ping $dest 3 > /dev/null 2>&1
+
+$dtrace -c "/sbin/ping $dest 3" -qs /dev/stdin <<EOF | \
+ grep -v 'is alive' | sort -n
+ip:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[5]->ipv6_nexthdr == IPPROTO_ICMPV6/
+{
+ printf("1 ip:::send (");
+ printf("args[2]: %d %d, ", args[2]->ip_ver, args[2]->ip_plength);
+ printf("args[5]: %d %d %d)\n",
+ args[5]->ipv6_ver, args[5]->ipv6_tclass, args[5]->ipv6_plen);
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" &&
+ args[5]->ipv6_nexthdr == IPPROTO_ICMPV6/
+{
+ printf("2 ip:::receive (");
+ printf("args[2]: %d %d, ", args[2]->ip_ver, args[2]->ip_plength);
+ printf("args[5]: %d %d %d)\n",
+ args[5]->ipv6_ver, args[5]->ipv6_tclass, args[5]->ipv6_plen);
+}
+EOF
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6remoteicmp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6remoteicmp.ksh.out
new file mode 100644
index 000000000000..1ddcd07b367e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.ipv6remoteicmp.ksh.out
@@ -0,0 +1,3 @@
+
+1 ip:::send (args[2]: 6 64, args[5]: 6 0 64)
+2 ip:::receive (args[2]: 6 64, args[5]: 6 0 64)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localsctpstate.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localsctpstate.ksh
new file mode 100755
index 000000000000..959342fb4090
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localsctpstate.ksh
@@ -0,0 +1,175 @@
+#!/usr/bin/env ksh
+#
+# 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test sctp:::state-change and sctp:::{send,receive} by connecting to
+# the local discard service.
+# A number of state transition events along with SCTP send and
+# receive events for the message should result.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. The lo0 interface missing or not up.
+# 3. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test performs a SCTP connection and checks that at least the
+# following packet counts were traced:
+#
+# 7 x ip:::send (4 during the setup, 3 during the teardown)
+# 7 x sctp:::send (4 during the setup, 3 during the teardown)
+# 7 x ip:::receive (4 during the setup, 3 during the teardown)
+# 7 x sctp:::receive (4 during the setup, 3 during the teardown)
+#
+# The actual count tested is 7 each way, since we are tracing both
+# source and destination events.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+local=127.0.0.1
+DIR=/var/tmp/dtest.$$
+
+sctpport=1024
+bound=5000
+
+mkdir $DIR
+cd $DIR
+
+cat > client.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Type => SOCK_STREAM,
+ Proto => "sctp",
+ LocalAddr => "$local",
+ PeerAddr => "$local",
+ PeerPort => \$ARGV[0],
+ Timeout => 3);
+ die "Could not connect to host $local port \$ARGV[0] \$@" unless \$s;
+ close \$s;
+ sleep(\$ARGV[1]);
+EOPERL
+
+while [ $sctpport -lt $bound ]; do
+ perl client.pl $sctpport 0 2>&- || break
+ sctpport=$(($sctpport + 1))
+done
+if [ $sctpport -eq $bound ]; then
+ echo "couldn't find an available SCTP port"
+ exit 1
+fi
+
+cat > server.pl <<-EOPERL
+ use IO::Socket;
+ my \$l = IO::Socket::INET->new(
+ Type => SOCK_STREAM,
+ Proto => "sctp",
+ LocalAddr => "$local",
+ LocalPort => $sctpport,
+ Listen => 1,
+ Reuse => 1);
+ die "Could not listen on $local port $sctpport \$@" unless \$l;
+ my \$c = \$l->accept();
+ close \$l;
+ while (<\$c>) {};
+ close \$c;
+EOPERL
+
+perl server.pl &
+
+$dtrace -c "perl client.pl $sctpport 2" -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = sctpsend = ipreceive = sctpreceive = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_SCTP/
+{
+ ipsend++;
+}
+
+sctp:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ (args[4]->sctp_sport == $sctpport || args[4]->sctp_dport == $sctpport)/
+{
+ sctpsend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_SCTP/
+{
+ ipreceive++;
+}
+
+sctp:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ (args[4]->sctp_sport == $sctpport || args[4]->sctp_dport == $sctpport)/
+{
+ sctpreceive++;
+}
+
+sctp:::state-change
+{
+ state_event[args[3]->sctps_state]++;
+}
+
+END
+{
+ printf("Minimum SCTP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 7 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 7 ? "yes" : "no");
+ printf("sctp:::send - %s\n", sctpsend >= 7 ? "yes" : "no");
+ printf("sctp:::receive - %s\n", sctpreceive >= 7 ? "yes" : "no");
+ printf("sctp:::state-change to cookie-wait - %s\n",
+ state_event[SCTP_STATE_COOKIE_WAIT] >=1 ? "yes" : "no");
+ printf("sctp:::state-change to cookie-echoed - %s\n",
+ state_event[SCTP_STATE_COOKIE_ECHOED] >=1 ? "yes" : "no");
+ printf("sctp:::state-change to established - %s\n",
+ state_event[SCTP_STATE_ESTABLISHED] >= 2 ? "yes" : "no");
+ printf("sctp:::state-change to shutdown-sent - %s\n",
+ state_event[SCTP_STATE_SHUTDOWN_SENT] >= 1 ? "yes" : "no");
+ printf("sctp:::state-change to shutdown-received - %s\n",
+ state_event[SCTP_STATE_SHUTDOWN_RECEIVED] >= 1 ? "yes" : "no");
+ printf("sctp:::state-change to shutdown-ack-sent - %s\n",
+ state_event[SCTP_STATE_SHUTDOWN_ACK_SENT] >= 1 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localsctpstate.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localsctpstate.ksh.out
new file mode 100644
index 000000000000..340e0ee2780c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localsctpstate.ksh.out
@@ -0,0 +1,13 @@
+Minimum SCTP events seen
+
+ip:::send - yes
+ip:::receive - yes
+sctp:::send - yes
+sctp:::receive - yes
+sctp:::state-change to cookie-wait - yes
+sctp:::state-change to cookie-echoed - yes
+sctp:::state-change to established - yes
+sctp:::state-change to shutdown-sent - yes
+sctp:::state-change to shutdown-received - yes
+sctp:::state-change to shutdown-ack-sent - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh
new file mode 100755
index 000000000000..528157072117
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh
@@ -0,0 +1,190 @@
+#!/usr/bin/env ksh
+#
+# 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test tcp:::state-change and tcp:::{send,receive} by connecting to
+# the local ssh service and sending a test message. This should result
+# in a "Protocol mismatch" response and a close of the connection.
+# A number of state transition events along with tcp fusion send and
+# receive events for the message should result.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. The lo0 interface missing or not up.
+# 3. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test performs a TCP connection and checks that at least the
+# following packet counts were traced:
+#
+# 7 x ip:::send (3 during the setup, 4 during the teardown)
+# 7 x tcp:::send (3 during the setup, 4 during the teardown)
+# 7 x ip:::receive (3 during the setup, 4 during the teardown)
+# 7 x tcp:::receive (3 during the setup, 4 during the teardown)
+#
+# The actual count tested is 7 each way, since we are tracing both
+# source and destination events.
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+local=127.0.0.1
+DIR=/var/tmp/dtest.$$
+
+tcpport=1024
+bound=5000
+while [ $tcpport -lt $bound ]; do
+ nc -z $local $tcpport >/dev/null || break
+ tcpport=$(($tcpport + 1))
+done
+if [ $tcpport -eq $bound ]; then
+ echo "couldn't find an available TCP port"
+ exit 1
+fi
+
+mkdir $DIR
+cd $DIR
+
+# nc will exit when the connection is closed.
+nc -l $local $tcpport &
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Proto => "tcp",
+ PeerAddr => "$local",
+ PeerPort => $tcpport,
+ Timeout => 3);
+ die "Could not connect to host $local port $tcpport" unless \$s;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = tcpsend = ipreceive = tcpreceive = 0;
+ connreq = connest = connaccept = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_TCP/
+{
+ ipsend++;
+}
+
+tcp:::send
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ (args[4]->tcp_sport == $tcpport || args[4]->tcp_dport == $tcpport)/
+{
+ tcpsend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->ipv4_protocol == IPPROTO_TCP/
+{
+ ipreceive++;
+}
+
+tcp:::receive
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ (args[4]->tcp_sport == $tcpport || args[4]->tcp_dport == $tcpport)/
+{
+ tcpreceive++;
+}
+
+tcp:::state-change
+{
+ state_event[args[3]->tcps_state]++;
+}
+
+tcp:::connect-request
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->tcp_dport == $tcpport/
+{
+ connreq++;
+}
+
+tcp:::connect-established
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->tcp_sport == $tcpport/
+{
+ connest++;
+}
+
+tcp:::accept-established
+/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
+ args[4]->tcp_dport == $tcpport/
+{
+ connaccept++;
+}
+
+END
+{
+ printf("Minimum TCP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 7 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 7 ? "yes" : "no");
+ printf("tcp:::send - %s\n", tcpsend >= 7 ? "yes" : "no");
+ printf("tcp:::receive - %s\n", tcpreceive >= 7 ? "yes" : "no");
+ printf("tcp:::state-change to syn-sent - %s\n",
+ state_event[TCP_STATE_SYN_SENT] >=1 ? "yes" : "no");
+ printf("tcp:::state-change to syn-received - %s\n",
+ state_event[TCP_STATE_SYN_RECEIVED] >=1 ? "yes" : "no");
+ printf("tcp:::state-change to established - %s\n",
+ state_event[TCP_STATE_ESTABLISHED] >= 2 ? "yes" : "no");
+ printf("tcp:::state-change to fin-wait-1 - %s\n",
+ state_event[TCP_STATE_FIN_WAIT_1] >= 1 ? "yes" : "no");
+ printf("tcp:::state-change to close-wait - %s\n",
+ state_event[TCP_STATE_CLOSE_WAIT] >= 1 ? "yes" : "no");
+ printf("tcp:::state-change to fin-wait-2 - %s\n",
+ state_event[TCP_STATE_FIN_WAIT_2] >= 1 ? "yes" : "no");
+ printf("tcp:::state-change to last-ack - %s\n",
+ state_event[TCP_STATE_LAST_ACK] >= 1 ? "yes" : "no");
+ printf("tcp:::state-change to time-wait - %s\n",
+ state_event[TCP_STATE_TIME_WAIT] >= 1 ? "yes" : "no");
+ printf("tcp:::connect-request - %s\n",
+ connreq >=1 ? "yes" : "no");
+ printf("tcp:::connect-established - %s\n",
+ connest >=1 ? "yes" : "no");
+ printf("tcp:::accept-established - %s\n",
+ connaccept >=1 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh.out
new file mode 100644
index 000000000000..ea1c27e5020c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh.out
@@ -0,0 +1,18 @@
+Minimum TCP events seen
+
+ip:::send - yes
+ip:::receive - yes
+tcp:::send - yes
+tcp:::receive - yes
+tcp:::state-change to syn-sent - yes
+tcp:::state-change to syn-received - yes
+tcp:::state-change to established - yes
+tcp:::state-change to fin-wait-1 - yes
+tcp:::state-change to close-wait - yes
+tcp:::state-change to fin-wait-2 - yes
+tcp:::state-change to last-ack - yes
+tcp:::state-change to time-wait - yes
+tcp:::connect-request - yes
+tcp:::connect-established - yes
+tcp:::accept-established - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotesctpstate.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotesctpstate.ksh
new file mode 100755
index 000000000000..3209c04e042c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotesctpstate.ksh
@@ -0,0 +1,149 @@
+#!/usr/bin/env ksh93
+#
+# 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test sctp:::state-change and sctp:::{send,receive} by connecting to
+# the remote http service.
+# A number of state transition events along with sctp send and receive
+# events for the message should result.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. The lo0 interface missing or not up.
+# 3. The remote ssh service is not online.
+# 4. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test performs a SCTP association to the http service (port 80) and
+# checks that at least the following packet counts were traced:
+#
+# 4 x ip:::send (2 during setup, 2 during teardown)
+# 4 x sctp:::send (2 during setup, 2 during teardown)
+# 3 x ip:::receive (2 during setup, 1 during teardown)
+# 3 x sctp:::receive (2 during setup, 1 during teardown)
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+getaddr=./get.ipv4remote.pl
+sctpport=80
+DIR=/var/tmp/dtest.$$
+
+if [[ ! -x $getaddr ]]; then
+ print -u2 "could not find or execute sub program: $getaddr"
+ exit 3
+fi
+$getaddr $sctpport sctp | read source dest
+if (( $? != 0 )); then
+ exit 4
+fi
+
+mkdir $DIR
+cd $DIR
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Type => SOCK_STREAM,
+ Proto => "sctp",
+ LocalAddr => "$source",
+ PeerAddr => "$dest",
+ PeerPort => $sctpport,
+ Timeout => 3);
+ die "Could not connect to host $dest port $sctpport \$@" unless \$s;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = sctpsend = ipreceive = sctpreceive = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->ipv4_protocol == IPPROTO_SCTP/
+{
+ ipsend++;
+}
+
+sctp:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->sctp_dport == $sctpport/
+{
+ sctpsend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" &&
+ args[4]->ipv4_protocol == IPPROTO_SCTP/
+{
+ ipreceive++;
+}
+
+sctp:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" &&
+ args[4]->sctp_sport == $sctpport/
+{
+ sctpreceive++;
+}
+
+sctp:::state-change
+{
+ state_event[args[3]->sctps_state]++;
+}
+
+END
+{
+ printf("Minimum SCTP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 4 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 3 ? "yes" : "no");
+ printf("sctp:::send - %s\n", sctpsend >= 4 ? "yes" : "no");
+ printf("sctp:::receive - %s\n", sctpreceive >= 3 ? "yes" : "no");
+ printf("sctp:::state-change to cookie-wait - %s\n",
+ state_event[SCTP_STATE_COOKIE_WAIT] >=1 ? "yes" : "no");
+ printf("sctp:::state-change to cookie-echoed - %s\n",
+ state_event[SCTP_STATE_COOKIE_ECHOED] >= 1 ? "yes" : "no");
+ printf("sctp:::state-change to established - %s\n",
+ state_event[SCTP_STATE_ESTABLISHED] >= 1 ? "yes" : "no");
+ printf("sctp:::state-change to shutdown-sent - %s\n",
+ state_event[SCTP_STATE_SHUTDOWN-SENT] >= 1 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotesctpstate.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotesctpstate.ksh.out
new file mode 100644
index 000000000000..a39b14fcfcb3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotesctpstate.ksh.out
@@ -0,0 +1,12 @@
+Minimum SCTP events seen
+
+ip:::send - yes
+ip:::receive - yes
+SCTP:::send - yes
+sctp:::receive - yes
+sctp:::state-change to cookie-wait - yes
+sctp:::state-change to cookie-echoed - yes
+sctp:::state-change to established - yes
+sctp:::state-change to shutdown-sent - yes
+sctp:::state-change to closed - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh
new file mode 100755
index 000000000000..b8066131d2f1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh
@@ -0,0 +1,172 @@
+#!/usr/bin/env ksh93
+#
+# 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Test tcp:::state-change and tcp:::{send,receive} by connecting to
+# the remote ssh service and sending a test message. This should result
+# in a "Protocol mismatch" response and a close of the connection.
+# A number of state transition events along with tcp send and receive
+# events for the message should result.
+#
+# This may fail due to:
+#
+# 1. A change to the ip stack breaking expected probe behavior,
+# which is the reason we are testing.
+# 2. The lo0 interface missing or not up.
+# 3. The remote ssh service is not online.
+# 4. An unlikely race causes the unlocked global send/receive
+# variables to be corrupted.
+#
+# This test performs a TCP connection to the ssh service (port 22) and
+# checks that at least the following packet counts were traced:
+#
+# 4 x ip:::send (2 during connection setup, 2 during connection teardown)
+# 4 x tcp:::send (2 during connection setup, 2 during connection teardown)
+# 5 x ip:::receive (1 during connection setup, the response, 1 window update,
+# 1 banner line, 2 during connection teardown)
+# 5 x tcp:::receive (1 during connection setup, the response, 1 window update,
+# 1 banner line, 2 during connection teardown)
+#
+
+if (( $# != 1 )); then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+getaddr=./get.ipv4remote.pl
+tcpport=22
+DIR=/var/tmp/dtest.$$
+
+if [[ ! -x $getaddr ]]; then
+ print -u2 "could not find or execute sub program: $getaddr"
+ exit 3
+fi
+$getaddr $tcpport | read source dest
+if (( $? != 0 )); then
+ exit 4
+fi
+
+mkdir $DIR
+cd $DIR
+
+cat > test.pl <<-EOPERL
+ use IO::Socket;
+ my \$s = IO::Socket::INET->new(
+ Proto => "tcp",
+ PeerAddr => "$dest",
+ PeerPort => $tcpport,
+ Timeout => 3);
+ die "Could not connect to host $dest port $tcpport" unless \$s;
+ readline \$s;
+ close \$s;
+ sleep(2);
+EOPERL
+
+$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
+BEGIN
+{
+ ipsend = tcpsend = ipreceive = tcpreceive = 0;
+ connreq = connest = 0;
+}
+
+ip:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->ipv4_protocol == IPPROTO_TCP/
+{
+ ipsend++;
+}
+
+tcp:::send
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->tcp_dport == $tcpport/
+{
+ tcpsend++;
+}
+
+ip:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" &&
+ args[4]->ipv4_protocol == IPPROTO_TCP/
+{
+ ipreceive++;
+}
+
+tcp:::receive
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" &&
+ args[4]->tcp_sport == $tcpport/
+{
+ tcpreceive++;
+}
+
+tcp:::state-change
+{
+ state_event[args[3]->tcps_state]++;
+}
+
+tcp:::connect-request
+/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
+ args[4]->tcp_dport == $tcpport/
+{
+ connreq++;
+}
+
+tcp:::connect-established
+/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" &&
+ args[4]->tcp_sport == $tcpport/
+{
+ connest++;
+}
+
+END
+{
+ printf("Minimum TCP events seen\n\n");
+ printf("ip:::send - %s\n", ipsend >= 4 ? "yes" : "no");
+ printf("ip:::receive - %s\n", ipreceive >= 5 ? "yes" : "no");
+ printf("tcp:::send - %s\n", tcpsend >= 4 ? "yes" : "no");
+ printf("tcp:::receive - %s\n", tcpreceive >= 5 ? "yes" : "no");
+ printf("tcp:::state-change to syn-sent - %s\n",
+ state_event[TCP_STATE_SYN_SENT] >=1 ? "yes" : "no");
+ printf("tcp:::state-change to established - %s\n",
+ state_event[TCP_STATE_ESTABLISHED] >= 1 ? "yes" : "no");
+ printf("tcp:::state-change to fin-wait-1 - %s\n",
+ state_event[TCP_STATE_FIN_WAIT_1] >= 1 ? "yes" : "no");
+ printf("tcp:::state-change to fin-wait-2 - %s\n",
+ state_event[TCP_STATE_FIN_WAIT_2] >= 1 ? "yes" : "no");
+ printf("tcp:::state-change to time-wait - %s\n",
+ state_event[TCP_STATE_TIME_WAIT] >= 1 ? "yes" : "no");
+ printf("tcp:::connect-request - %s\n",
+ connreq >=1 ? "yes" : "no");
+ printf("tcp:::connect-established - %s\n",
+ connest >=1 ? "yes" : "no");
+}
+EODTRACE
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh.out
new file mode 100644
index 000000000000..27388fba65dc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh.out
@@ -0,0 +1,15 @@
+Minimum TCP events seen
+
+ip:::send - yes
+ip:::receive - yes
+tcp:::send - yes
+tcp:::receive - yes
+tcp:::state-change to syn-sent - yes
+tcp:::state-change to established - yes
+tcp:::state-change to fin-wait-1 - yes
+tcp:::state-change to close-wait - yes
+tcp:::state-change to fin-wait-2 - yes
+tcp:::state-change to time-wait - yes
+tcp:::connect-request - yes
+tcp:::connect-established - yes
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/manifest/test.jar-manifest b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/manifest/test.jar-manifest
new file mode 100644
index 000000000000..8f07fb2cf3b9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/manifest/test.jar-manifest
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Class-Path: /usr/share/lib/java/dtrace.jar
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestAbort.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestAbort.java
new file mode 100644
index 000000000000..310dd184a726
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestAbort.java
@@ -0,0 +1,158 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import org.opensolaris.os.dtrace.*;
+import java.util.NoSuchElementException;
+
+/**
+ * Regression for 6426129 abort() after close() throws
+ * NoSuchElementException.
+ */
+public class TestAbort {
+ static boolean aborted = false;
+
+ public static void
+ main(String[] args)
+ {
+ Consumer consumer = new LocalConsumer();
+
+ // Test for deadlock (bug 6419880)
+ try {
+ consumer.open();
+ consumer.compile("syscall:::entry { @[execname] = count(); } " +
+ "tick-101ms { printa(@); }");
+ consumer.enable();
+ consumer.go();
+ try {
+ Thread.currentThread().sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ consumer.close();
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ consumer = new LocalConsumer();
+
+ // Should be able to abort an unopened consumer
+ try {
+ aborted = false;
+ consumer.addConsumerListener(new ConsumerAdapter() {
+ public void consumerStopped(ConsumerEvent e) {
+ aborted = true;
+ }
+ });
+ consumer.abort();
+ consumer.open();
+ consumer.compile("syscall:::entry { @[execname] = count(); } " +
+ "tick-101ms { printa(@); }");
+ consumer.enable();
+ consumer.go();
+ try {
+ Thread.currentThread().sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ if (!aborted) {
+ throw new IllegalStateException("consumer not aborted");
+ }
+ consumer.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ consumer = new LocalConsumer();
+
+ // Should be safe to call abort() in any state
+ try {
+ consumer.abort();
+ consumer.open();
+ consumer.abort();
+ consumer.compile("syscall:::entry { @[execname] = count(); } " +
+ "tick-101ms { printa(@); }");
+ consumer.abort();
+ consumer.enable();
+ consumer.abort();
+ consumer.go();
+ consumer.abort();
+ consumer.close();
+ // Should be safe to call after close()
+ try {
+ consumer.abort();
+ } catch (NoSuchElementException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ consumer = new LocalConsumer();
+
+ // Tests that close() throws expected exception when called on
+ // synchronized consumer.
+ try {
+ consumer.open();
+ consumer.compile("syscall:::entry { @[execname] = count(); } " +
+ "tick-101ms { printa(@); }");
+ consumer.enable();
+ consumer.go();
+ try {
+ Thread.currentThread().sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ try {
+ synchronized (consumer) {
+ consumer.close();
+ }
+ } catch (IllegalThreadStateException e) {
+ try {
+ consumer.close();
+ System.out.println("Successful");
+ System.exit(0);
+ } catch (NoSuchElementException x) {
+ x.printStackTrace();
+ System.exit(1);
+ }
+ }
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ System.err.println("Failed");
+ System.exit(1);
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestBean.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestBean.java
new file mode 100644
index 000000000000..dd4a969d4355
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestBean.java
@@ -0,0 +1,706 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import org.opensolaris.os.dtrace.*;
+import java.util.*;
+import java.io.*;
+import java.beans.*;
+import java.lang.reflect.*;
+
+/**
+ * Regression test for serialization and XML encoding/decoding. Tests
+ * every Serializable class in the Java DTrace API by creating a dummy
+ * instance, writing it to a file, then reading it back in and comparing
+ * the string values of the object before and after, as well as
+ * verifying object equality before and after if the class overrides the
+ * equals() method.
+ */
+public class TestBean {
+ public static final String[] TESTS = new String[] {
+ "ExitRecord",
+ "AggregationRecord",
+ "Aggregation",
+ "Tuple",
+ "ScalarRecord",
+ "KernelStackRecord",
+ "LogDistribution",
+ "LinearDistribution",
+ "Option",
+ "ProcessState",
+ "ProbeDescription",
+ "PrintaRecord",
+ "PrintfRecord",
+ "ProbeData",
+ "Aggregate",
+ "UserStackRecord",
+ "AvgValue",
+ "CountValue",
+ "SumValue",
+ "MinValue",
+ "MaxValue",
+ "Error",
+ "Drop",
+ "InterfaceAttributes",
+ "ProgramInfo",
+ "ProbeInfo",
+ "Probe",
+ "Flow",
+ "KernelSymbolRecord",
+ "UserSymbolRecord",
+ "UserSymbolRecord$Value",
+ "Program",
+ "Program$File",
+ "StddevValue"
+ };
+
+ static File file;
+
+ static void
+ exit(int status)
+ {
+ System.out.flush();
+ System.err.flush();
+ System.exit(status);
+ }
+
+ public static XMLEncoder
+ getXMLEncoder(File file)
+ {
+ XMLEncoder encoder = null;
+ try {
+ OutputStream out = new BufferedOutputStream
+ (new FileOutputStream(file));
+ encoder = new XMLEncoder(out);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ return encoder;
+ }
+
+ public static XMLDecoder
+ getXMLDecoder(File file)
+ {
+ return getXMLDecoder(file, null);
+ }
+
+ public static XMLDecoder
+ getXMLDecoder(File file, ExceptionListener exceptionListener)
+ {
+ XMLDecoder decoder = null;
+ try {
+ InputStream in = new BufferedInputStream
+ (new FileInputStream(file));
+ decoder = new XMLDecoder(in, null, exceptionListener);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ return decoder;
+ }
+
+ public static ExitRecord
+ getExitRecord()
+ {
+ ExitRecord r = new ExitRecord(1);
+ return r;
+ }
+
+ public static AggregationRecord
+ getAggregationRecord()
+ {
+ Tuple tuple = getTuple();
+ AggregationValue value = new CountValue(7);
+ AggregationRecord r = new AggregationRecord(tuple, value);
+ return r;
+ }
+
+ public static Aggregation
+ getAggregation()
+ {
+ List < AggregationRecord > list =
+ new ArrayList < AggregationRecord > ();
+ AggregationRecord r;
+ r = getAggregationRecord();
+ list.add(r);
+
+ ValueRecord v1 = new ScalarRecord(new byte[] {(byte)1, (byte)2,
+ (byte)3}, 3);
+ ValueRecord v2 = new ScalarRecord("shebang!", 256);
+ Tuple tuple = new Tuple(v1, v2);
+ AggregationValue value = getLinearDistribution();
+ r = new AggregationRecord(tuple, value);
+ list.add(r);
+
+ Aggregation a = new Aggregation("counts", 2, list);
+ return a;
+ }
+
+ public static Tuple
+ getTuple()
+ {
+ ValueRecord r1 = new ScalarRecord("cat", 256);
+ ValueRecord r2 = new ScalarRecord(new Integer(9), 2);
+ ValueRecord r3 = new KernelStackRecord(
+ new StackFrame[] {
+ new StackFrame("has"),
+ new StackFrame("nine"),
+ new StackFrame("lives")},
+ new byte[] { (byte)0, (byte)1, (byte)2 });
+ ValueRecord r4 = new ScalarRecord(new byte[] {(byte)1, (byte)2,
+ (byte)3}, 3);
+
+ Tuple tuple = new Tuple(r1, r2, r3, r4);
+ return tuple;
+ }
+
+ public static ScalarRecord
+ getScalarRecord()
+ {
+ Object v = new byte[] {(byte)1, (byte)2, (byte)3};
+ ScalarRecord r = new ScalarRecord(v, 3);
+ return r;
+ }
+
+ public static KernelStackRecord
+ getKernelStackRecord()
+ {
+ StackFrame[] stackFrames = new StackFrame[] {
+ new StackFrame("Frame 1"),
+ new StackFrame("Frame 2"),
+ new StackFrame("Frame 3")
+ };
+ KernelStackRecord r = new KernelStackRecord(stackFrames,
+ new byte[] { (byte)0, (byte)1, (byte)2 });
+ return r;
+ }
+
+ public static LogDistribution
+ getLogDistribution()
+ {
+ List < Distribution.Bucket > buckets =
+ new ArrayList < Distribution.Bucket > ();
+ Distribution.Bucket bucket;
+ int n = 0;
+ long base = 0;
+ long i;
+ long sign;
+ long nextSign;
+ long power;
+ long nextPower;
+ long lowerBound;
+ long upperBound;
+ for (i = -62; i <= 62; ++i) {
+ if (i == 0) {
+ bucket = new Distribution.Bucket(-1, -1, n++);
+ buckets.add(bucket);
+ bucket = new Distribution.Bucket(0, 0, n++);
+ buckets.add(bucket);
+ bucket = new Distribution.Bucket(1, 1, n++);
+ buckets.add(bucket);
+ continue;
+ }
+ sign = ((i < 0) ? -1L : 1L);
+ power = (sign * i);
+ nextSign = (((i + 1) < 0) ? -1L : 1L);
+ nextPower = (nextSign * (i + 1));
+ lowerBound = sign * ((long) Math.pow(2L, power));
+ upperBound = (nextPower == 0 ? -2L :
+ (nextSign * ((long) Math.pow(2L, nextPower))) - 1);
+ if ((upperBound > 0) && ((upperBound * 2L) < 0)) {
+ upperBound = Long.MAX_VALUE;
+ }
+ bucket = new Distribution.Bucket(lowerBound, upperBound, n++);
+ buckets.add(bucket);
+ }
+ LogDistribution d = new LogDistribution(buckets);
+ return d;
+ }
+
+ public static LinearDistribution
+ getLinearDistribution()
+ {
+ List < Distribution.Bucket > buckets =
+ new ArrayList < Distribution.Bucket > ();
+ Distribution.Bucket bucket;
+ int n = 10; // number of buckets
+ int base = 1;
+ int step = 10;
+ bucket = new Distribution.Bucket(Long.MIN_VALUE, (base - 1), 0);
+ buckets.add(bucket);
+ for (int i = base; i < (n * step); i += step) {
+ bucket = new Distribution.Bucket(i, (i + (step - 1)),
+ ((i - 1) / step));
+ buckets.add(bucket);
+ }
+ bucket = new Distribution.Bucket((n * step) + 1, Long.MAX_VALUE, 0);
+ buckets.add(bucket);
+ LinearDistribution d = new LinearDistribution(base, step, buckets);
+ return d;
+ }
+
+ public static Option
+ getOption()
+ {
+ Option option = new Option("aggrate", "1s");
+ return option;
+ }
+
+ public static ProcessState
+ getProcessState()
+ {
+ ProcessState p = new ProcessState(123456, "UNDEAD",
+ 3, "SIGSTOP",
+ -2, "Process stopped on dime");
+ return p;
+ }
+
+ public static ProbeDescription
+ getProbeDescription()
+ {
+ ProbeDescription d = new ProbeDescription(256, "syscall", null,
+ "malloc", "entry");
+ return d;
+ }
+
+ public static PrintaRecord
+ getPrintaRecord()
+ {
+ List < Aggregation > aggregations = new ArrayList < Aggregation > ();
+ Aggregation a = getAggregation();
+ aggregations.add(a);
+ aggregations.add(a);
+ Map < Tuple, String > formattedOutput =
+ new HashMap < Tuple, String > ();
+ for (Tuple t : a.asMap().keySet()) {
+ formattedOutput.put(t, "cat");
+ }
+ List < Tuple > tuples = new ArrayList < Tuple > ();
+ for (Tuple t : a.asMap().keySet()) {
+ tuples.add(t);
+ }
+ Collections.sort(tuples);
+ PrintaRecord r = new PrintaRecord(1234567890L,
+ aggregations, formattedOutput, tuples,
+ "Yes, this is the formatted printa() output");
+ return r;
+ }
+
+ public static PrintfRecord
+ getPrintfRecord()
+ {
+ List < ValueRecord > list = new ArrayList < ValueRecord > ();
+ ValueRecord v1 = getScalarRecord();
+ ValueRecord v2 = new ScalarRecord(new Integer(7), 4);
+ list.add(v1);
+ list.add(v2);
+ PrintfRecord r = new PrintfRecord(list,
+ "long formatted string");
+ return r;
+ }
+
+ public static ProbeData
+ getProbeData()
+ {
+ List < Record > list = new ArrayList < Record > ();
+ list.add(getPrintaRecord());
+ list.add(getPrintfRecord());
+ list.add(getScalarRecord());
+ list.add(getUserSymbolRecord());
+ list.add(getUserStackRecord());
+ list.add(getExitRecord());
+ ProbeData d = new ProbeData(7, 1, getProbeDescription(),
+ getFlow(), list);
+ return d;
+ }
+
+ public static Aggregate
+ getAggregate()
+ {
+ List < Aggregation > list = new ArrayList < Aggregation > ();
+ list.add(getAggregation());
+
+ List < AggregationRecord > reclist =
+ new ArrayList < AggregationRecord > ();
+ AggregationRecord r;
+ ValueRecord v1 = new ScalarRecord("cat", 256);
+ ValueRecord v2 = new ScalarRecord("dog", 256);
+ ValueRecord v3 = new ScalarRecord("mouse", 256);
+ ValueRecord v4 = new ScalarRecord("mouse", 256);
+ ValueRecord v5 = new ScalarRecord(new Byte((byte) 'C'), 1);
+ ValueRecord v6 = new ScalarRecord(new Short((short) 7), 2);
+ Tuple tuple = new Tuple(v1, v2, v3, v4, v5, v6);
+ AggregationValue value = getCountValue();
+ r = new AggregationRecord(tuple, value);
+ reclist.add(r);
+ list.add(new Aggregation("times", 1, reclist));
+
+ Aggregate a = new Aggregate(1234567890L, list);
+ return a;
+ }
+
+ public static UserStackRecord
+ getUserStackRecord()
+ {
+ StackFrame[] frames = new StackFrame[] {
+ new StackFrame("User Stack Frame 1"),
+ new StackFrame("User Stack Frame 2"),
+ new StackFrame("User Stack Frame 3")
+ };
+ UserStackRecord r = new UserStackRecord(123456, frames,
+ new byte[] { (byte)0, (byte)1, (byte)2 });
+ return r;
+ }
+
+ public static AvgValue
+ getAvgValue()
+ {
+ AvgValue v = new AvgValue(5, 20, 4);
+ return v;
+ }
+
+ public static CountValue
+ getCountValue()
+ {
+ CountValue v = new CountValue(9);
+ return v;
+ }
+
+ public static MinValue
+ getMinValue()
+ {
+ MinValue v = new MinValue(101);
+ return v;
+ }
+
+ public static MaxValue
+ getMaxValue()
+ {
+ MaxValue v = new MaxValue(101);
+ return v;
+ }
+
+ public static SumValue
+ getSumValue()
+ {
+ SumValue v = new SumValue(25);
+ return v;
+ }
+
+ public static org.opensolaris.os.dtrace.Error
+ getError()
+ {
+ ProbeDescription probe = getProbeDescription();
+ org.opensolaris.os.dtrace.Error e =
+ new org.opensolaris.os.dtrace.Error(probe, 8, 3,
+ 1, 20, "DTRACEFLT_BADALIGN", -1, "error on enabled probe ID 8 " +
+ "(ID " + probe.getID() + ": " + probe + "): Bad alignment " +
+ "(0x33ef) in action #1 at DIF offset 20");
+ return e;
+ }
+
+ public static Drop
+ getDrop()
+ {
+ Drop drop = new Drop(2, "SPECBUSY", 72, 1041,
+ "Guess we dropped stuff all over the place.");
+ return drop;
+ }
+
+ public static InterfaceAttributes
+ getInterfaceAttributes()
+ {
+ InterfaceAttributes a = new InterfaceAttributes(
+ InterfaceAttributes.Stability.UNSTABLE,
+ InterfaceAttributes.Stability.EVOLVING,
+ InterfaceAttributes.DependencyClass.ISA);
+ return a;
+ }
+
+ public static ProgramInfo
+ getProgramInfo()
+ {
+ ProgramInfo info = new ProgramInfo(getInterfaceAttributes(),
+ getInterfaceAttributes(), 256);
+ return info;
+ }
+
+ public static ProbeInfo
+ getProbeInfo()
+ {
+ ProbeInfo info = new ProbeInfo(getInterfaceAttributes(),
+ getInterfaceAttributes());
+ return info;
+ }
+
+ public static Probe
+ getProbe()
+ {
+ Probe p = new Probe(getProbeDescription(), getProbeInfo());
+ return p;
+ }
+
+ public static Flow
+ getFlow()
+ {
+ Flow f = new Flow(Flow.Kind.RETURN.name(), 3);
+ return f;
+ }
+
+ public static KernelSymbolRecord
+ getKernelSymbolRecord()
+ {
+ KernelSymbolRecord r = new KernelSymbolRecord("mod`func+0x4", -1L);
+ return r;
+ }
+
+ public static UserSymbolRecord
+ getUserSymbolRecord()
+ {
+ UserSymbolRecord r = new UserSymbolRecord(7, "mod`func+0x4", -1L);
+ return r;
+ }
+
+ public static UserSymbolRecord.Value
+ getUserSymbolRecord$Value()
+ {
+ UserSymbolRecord.Value v = new UserSymbolRecord.Value(7, -1L);
+ return v;
+ }
+
+ public static Program
+ getProgram()
+ {
+ final String PROGRAM = "syscall:::entry { @[execname] = count(); }";
+ Consumer consumer = new LocalConsumer();
+ Program p;
+ try {
+ consumer.open();
+ p = consumer.compile(PROGRAM);
+ consumer.close();
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ p = null;
+ }
+ return p;
+ }
+
+ public static Program.File
+ getProgram$File()
+ {
+ final String PROGRAM = "syscall:::entry { @[execname] = count(); }";
+ Consumer consumer = new LocalConsumer();
+ Program p;
+ try {
+ OutputStream out = new FileOutputStream(file);
+ out.write(PROGRAM.getBytes(), 0, PROGRAM.length());
+ out.flush();
+ out.close();
+ consumer.open();
+ p = consumer.compile(file);
+ consumer.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ p = null;
+ }
+ return Program.File.class.cast(p);
+ }
+
+ public static StddevValue
+ getStddevValue()
+ {
+ StddevValue v = new StddevValue(37, 114, 5, Integer.toString(9544));
+ return v;
+ }
+
+ @SuppressWarnings("unchecked")
+ static String
+ getString(Object o)
+ {
+ String s;
+ if (o instanceof ScalarRecord) {
+ o = ((ScalarRecord)o).getValue();
+ }
+
+ if (o instanceof byte[]) {
+ s = Arrays.toString((byte[])o);
+ } else if (o instanceof Object[]) {
+ s = Arrays.toString((Object[])o);
+ } else {
+ Class c = o.getClass();
+ try {
+ Method m = c.getDeclaredMethod("toLogString");
+ s = (String)m.invoke(o);
+ } catch (Exception e) {
+ s = o.toString();
+ }
+ }
+ return s;
+ }
+
+ static void
+ checkEquality(Object obj, Object newobj)
+ {
+ // If the class overrides equals(), make sure the re-created
+ // object still equals the original object
+ try {
+ Method eq = obj.getClass().getDeclaredMethod("equals",
+ Object.class);
+ Boolean ret = (Boolean) eq.invoke(obj, newobj);
+ if (ret != true) {
+ System.err.println("serialization failed: " +
+ obj.getClass().getName());
+ exit(1);
+ }
+ } catch (Exception e) {
+ // Does not override equals(), although a super-class might.
+ // A better test would check for any superclass other than
+ // Object.class.
+ }
+ }
+
+ static void
+ performSerializationTest(File file, String classname)
+ throws IOException, ClassNotFoundException
+ {
+ String methodName = "get" + classname;
+ Object obj = null;
+ Object newobj = null;
+ try {
+ Method method = TestBean.class.getDeclaredMethod(methodName);
+ obj = method.invoke(null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+
+ System.out.println(classname + ":");
+ String serialized = getString(obj);
+ System.out.println(" serialized: " + serialized);
+ FileOutputStream fos = new FileOutputStream(file);
+ ObjectOutputStream out = new ObjectOutputStream(fos);
+ out.writeObject(obj);
+ out.close();
+ FileInputStream fis = new FileInputStream(file);
+ ObjectInputStream in = new ObjectInputStream(fis);
+ newobj = in.readObject();
+ in.close();
+ String deserialized = getString(newobj);
+ System.out.println(" deserialized: " + deserialized);
+
+ if (!serialized.equals(deserialized)) {
+ System.err.println("serialization failed: " + classname);
+ exit(1);
+ }
+ checkEquality(obj, newobj);
+ }
+
+ static void
+ performBeanTest(File file, String classname)
+ {
+ String methodName = "get" + classname;
+ Object obj = null;
+ Object newobj = null;
+ try {
+ Method method = TestBean.class.getDeclaredMethod(methodName);
+ obj = method.invoke(null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+
+ Class c = obj.getClass();
+ if (c.getConstructors().length == 0) {
+ return;
+ }
+
+ System.out.println(classname + ":");
+ XMLEncoder encoder = getXMLEncoder(file);
+ String encoded = getString(obj);
+ System.out.println(" encoded: " + encoded);
+ encoder.writeObject(obj);
+ encoder.close();
+ XMLDecoder decoder = getXMLDecoder(file);
+ newobj = decoder.readObject();
+ String decoded = getString(newobj);
+ System.out.println(" decoded: " + decoded);
+ decoder.close();
+
+ if (!encoded.equals(decoded)) {
+ System.err.println("bean persistence failed: " + classname);
+ exit(1);
+ }
+ checkEquality(obj, newobj);
+ }
+
+ public static void
+ main(String[] args)
+ {
+ if ((args.length != 1) && (args.length != 2)) {
+ System.err.println("usage: java TestBean < filename > " +
+ "[ < classname > ]");
+ exit(1);
+ }
+
+ String filename = args[0];
+ String classname = null;
+ if (args.length >= 2) {
+ classname = args[1];
+ }
+
+ file = new File(filename);
+ try {
+ if (!file.canRead()) {
+ try {
+ file.createNewFile();
+ } catch (Exception e) {
+ System.err.println("failed to create " + filename);
+ exit(1);
+ }
+ }
+ } catch (SecurityException e) {
+ System.err.println("failed to open " + filename);
+ exit(1);
+ }
+
+ String[] tests = (classname == null ? TESTS:
+ new String[] { classname });
+ try {
+ for (int i = 0; i < tests.length; ++i) {
+ performSerializationTest(file, tests[i]);
+ performBeanTest(file, tests[i]);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ exit(1);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestClose.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestClose.java
new file mode 100644
index 000000000000..c7a9e89d0383
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestClose.java
@@ -0,0 +1,90 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import org.opensolaris.os.dtrace.*;
+
+/**
+ * Regression for bug 6419880 close() hangs running consumer.
+ */
+public class TestClose {
+ public static void
+ main(String[] args)
+ {
+ Consumer consumer = new LocalConsumer();
+
+ try {
+ consumer.open();
+ consumer.compile("syscall:::entry { @[execname] = count(); } " +
+ "tick-101ms { printa(@); }");
+ consumer.enable();
+ consumer.go();
+ try {
+ Thread.currentThread().sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ consumer.close();
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ consumer = new LocalConsumer();
+
+ try {
+ consumer.open();
+ consumer.compile("syscall:::entry { @[execname] = count(); } " +
+ "tick-101ms { printa(@); }");
+ consumer.enable();
+ consumer.go();
+ try {
+ Thread.currentThread().sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ try {
+ // Test new rule that close() is illegal while holding
+ // lock on consumer.
+ synchronized (consumer) {
+ consumer.close();
+ }
+ } catch (IllegalThreadStateException e) {
+ consumer.close();
+ System.out.println("Successful");
+ System.exit(0);
+ }
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ System.err.println("Failed");
+ System.exit(1);
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestDrop.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestDrop.java
new file mode 100644
index 000000000000..b5ace25bdbde
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestDrop.java
@@ -0,0 +1,169 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+import java.util.*;
+import java.util.concurrent.atomic.*;
+import org.opensolaris.os.dtrace.*;
+
+/**
+ * Regression test for 6521523 aggregation drops can hang the Java
+ * DTrace API.
+ */
+public class TestDrop {
+ static final String PROGRAM =
+ "fbt:genunix::entry { @[execname, pid] = count(); }";
+
+ static AtomicLong consumerThreadID = new AtomicLong();
+ static AtomicLong getAggregateThreadID = new AtomicLong();
+ static AtomicBoolean done = new AtomicBoolean();
+ static int seconds;
+
+ private static void
+ startTimer()
+ {
+ if (seconds <= 0) {
+ return;
+ }
+
+ final Timer timer = new Timer();
+ timer.schedule(new TimerTask() {
+ public void run() {
+ done.set(true);
+ timer.cancel();
+ }
+ }, seconds * 1000L);
+ }
+
+ private static void
+ sampleAggregate(Consumer consumer) throws DTraceException
+ {
+ while (consumer.isRunning() && !done.get()) {
+ try {
+ Thread.currentThread().sleep(50);
+ } catch (InterruptedException e) {
+ }
+
+ consumer.getAggregate(Collections. <String> emptySet());
+ }
+ }
+
+ private static void
+ startAggregateThread(final Consumer consumer)
+ {
+ Runnable aggregateSampler = new Runnable() {
+ public void run() {
+ Thread t = Thread.currentThread();
+ getAggregateThreadID.set(t.getId());
+ Throwable x = null;
+ try {
+ sampleAggregate(consumer);
+ } catch (Throwable e) {
+ x = e;
+ }
+
+ if (Thread.holdsLock(LocalConsumer.class)) {
+ if (x != null) {
+ x.printStackTrace();
+ }
+ System.out.println("Lock held");
+ System.exit(1);
+ } else {
+ System.out.println("Lock released");
+ consumer.close(); // blocks if lock held
+ }
+ }
+ };
+
+ Thread t = new Thread(aggregateSampler, "Aggregate Sampler");
+ t.start();
+ }
+
+ static void
+ usage()
+ {
+ System.err.println("usage: java TestDrop [ seconds ]");
+ System.exit(2);
+ }
+
+ public static void
+ main(String[] args)
+ {
+ if (args.length == 1) {
+ try {
+ seconds = Integer.parseInt(args[0]);
+ } catch (NumberFormatException e) {
+ usage();
+ }
+ } else if (args.length > 1) {
+ usage();
+ }
+
+ final Consumer consumer = new LocalConsumer() {
+ protected Thread createThread() {
+ Runnable worker = new Runnable() {
+ public void run() {
+ Thread t = Thread.currentThread();
+ consumerThreadID.set(t.getId());
+ work();
+ }
+ };
+ Thread t = new Thread(worker);
+ return t;
+ }
+ };
+
+ consumer.addConsumerListener(new ConsumerAdapter() {
+ public void consumerStarted(ConsumerEvent e) {
+ startAggregateThread(consumer);
+ startTimer();
+ }
+ public void dataDropped(DropEvent e) throws ConsumerException {
+ Thread t = Thread.currentThread();
+ if (t.getId() == getAggregateThreadID.get()) {
+ Drop drop = e.getDrop();
+ throw new ConsumerException(drop.getDefaultMessage(),
+ drop);
+ }
+ }
+ });
+
+ try {
+ consumer.open();
+ consumer.setOption(Option.aggsize, Option.kb(1));
+ consumer.setOption(Option.aggrate, Option.millis(101));
+ consumer.compile(PROGRAM);
+ consumer.enable();
+ consumer.go(new ExceptionHandler() {
+ public void handleException(Throwable e) {
+ e.printStackTrace();
+ }
+ });
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestEnable.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestEnable.java
new file mode 100644
index 000000000000..0e5a608691c0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestEnable.java
@@ -0,0 +1,151 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import org.opensolaris.os.dtrace.*;
+
+/**
+ * Prove that enable() handles multiple programs, recognizing programs
+ * that are already enabled and programs that were compiled by another
+ * consumer.
+ */
+public class TestEnable {
+ static void
+ exit(int status)
+ {
+ System.out.flush();
+ System.err.flush();
+ System.exit(status);
+ }
+
+ public static void
+ main(String[] args)
+ {
+ Consumer consumer = new LocalConsumer();
+
+ try {
+ consumer.open();
+ Program p0 = consumer.compile("dtrace:::BEGIN");
+ Program p1 = consumer.compile("syscall:::entry");
+ Program p2 = consumer.compile("dtrace:::END");
+ consumer.enable(p0);
+ consumer.enable(p1);
+ try {
+ consumer.go();
+ System.err.println("go() illegal, not all programs " +
+ "enabled (p0, p1)");
+ exit(1);
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ try {
+ consumer.enable();
+ System.err.println("enable() illegal, some programs " +
+ "already enabled (p0, p1)");
+ exit(1);
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ try {
+ consumer.enable(p0);
+ System.err.println("cannot enable a program that " +
+ "has already been enabled (p0)");
+ exit(1);
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ consumer.enable(p2);
+ Program p3 = consumer.compile("syscall:::return");
+ try {
+ consumer.go();
+ System.err.println("go() illegal, not all programs " +
+ "enabled (p0, p1, p2)");
+ exit(1);
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ try {
+ consumer.enable();
+ System.err.println("enable() illegal, some programs " +
+ "already enabled (p0, p1, p2)");
+ exit(1);
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ // Try to fool the consumer with a program compiled by
+ // another consumer
+ Consumer consumer2 = new LocalConsumer();
+ consumer2.open();
+ Program p3x = consumer2.compile("syscall:::return");
+ try {
+ consumer.enable(p3x);
+ System.err.println("cannot enable program compiled " +
+ "by another consumer");
+ exit(1);
+ } catch (IllegalArgumentException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1);
+ } finally {
+ consumer2.close();
+ }
+ consumer.enable(p3);
+ consumer.go();
+ consumer.close();
+
+ // Enable all compiled programs at once
+ consumer = new LocalConsumer();
+ consumer.open();
+ consumer.compile("dtrace:::BEGIN");
+ consumer.compile("syscall:::entry");
+ consumer.compile("dtrace:::END");
+ consumer.enable();
+ consumer.go();
+ consumer.close();
+ exit(0);
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestFunctionLookup.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestFunctionLookup.java
new file mode 100644
index 000000000000..2bc43ea6f1ce
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestFunctionLookup.java
@@ -0,0 +1,114 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+import org.opensolaris.os.dtrace.*;
+
+/**
+ * Regression for bug 6413280 lookupKernelFunction() and
+ * lookupUserFunction() truncate last character.
+ */
+public class TestFunctionLookup {
+ static final String kernelLookupProgram = "sdt:::callout-start { " +
+ "@[((callout_t *)arg0)->c_func] = count(); }";
+ static final String userLookupProgram = "pid$target::f2:entry { " +
+ "@[arg0] = count(); }";
+
+ public static void
+ main(String[] args)
+ {
+ if (args.length != 1) {
+ System.err.println("usage: java TestFunctionLookup <command>");
+ System.exit(1);
+ }
+ String cmd = args[0];
+
+ Consumer consumer = new LocalConsumer();
+ try {
+ consumer.open();
+ consumer.compile(kernelLookupProgram);
+ consumer.enable();
+ consumer.go();
+ Aggregate a;
+ Number address;
+ String f;
+ boolean done = false;
+ for (int i = 0; (i < 20) && !done; ++i) {
+ Thread.currentThread().sleep(100);
+ a = consumer.getAggregate();
+ for (Aggregation agg : a.getAggregations()) {
+ for (Tuple tuple : agg.asMap().keySet()) {
+ address = (Number)tuple.get(0).getValue();
+ if (address instanceof Integer) {
+ int addr = (Integer)address;
+ f = consumer.lookupKernelFunction(addr);
+ } else {
+ long addr = (Long)address;
+ f = consumer.lookupKernelFunction(addr);
+ }
+ if (f.equals("genunix`cv_wakeup")) {
+ System.out.println(f);
+ done = true;
+ }
+ }
+ }
+ }
+ consumer.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ consumer = new LocalConsumer();
+ try {
+ consumer.open();
+ int pid = consumer.createProcess(cmd);
+ consumer.compile(userLookupProgram);
+ consumer.enable();
+ consumer.go();
+ Thread.currentThread().sleep(500);
+ Aggregate a = consumer.getAggregate();
+ Number address;
+ String f;
+ for (Aggregation agg : a.getAggregations()) {
+ for (Tuple tuple : agg.asMap().keySet()) {
+ address = (Number)tuple.get(0).getValue();
+ if (address instanceof Integer) {
+ int addr = (Integer)address;
+ f = consumer.lookupUserFunction(pid, addr);
+ } else {
+ long addr = (Long)address;
+ f = consumer.lookupUserFunction(pid, addr);
+ }
+ System.out.println(f);
+ }
+ }
+ consumer.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestGetAggregate.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestGetAggregate.java
new file mode 100644
index 000000000000..e02df8582417
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestGetAggregate.java
@@ -0,0 +1,252 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+import org.opensolaris.os.dtrace.*;
+import java.util.*;
+
+/**
+ * Assert getAggregate() can explicitly specify the anonymous aggregation.
+ */
+public class TestGetAggregate {
+ static final String programString =
+ "profile:::tick-50ms" +
+ "{" +
+ " @ = count();" +
+ " @a = count();" +
+ "}";
+
+ static final String ANONYMOUS_AGGREGATION = "";
+ static final int TICK = 50;
+ static final int EXPECTED_TICKS = 3;
+ static final int INTERVALS = 4;
+
+ static void
+ testIncluded(Consumer consumer, String ... aggregationNames)
+ throws DTraceException, InterruptedException
+ {
+ Aggregate aggregate;
+ Set <String> included = new HashSet <String> ();
+ int n = 1;
+
+ for (String name : aggregationNames) {
+ included.add(name);
+ }
+
+ // Wait up to a full second to obtain aggregate data. Without a
+ // time limit, we'll loop forever if no aggregation was
+ // successfully included.
+ do {
+ Thread.sleep(TICK);
+ aggregate = consumer.getAggregate(included, null);
+ } while (aggregate.asMap().isEmpty() && n++ < (1000 / TICK));
+
+ for (String name : included) {
+ if (aggregate.getAggregation(name) == null) {
+ throw new IllegalStateException("@" + name +
+ " was explicitly included but did not appear " +
+ "in the aggregate");
+ }
+ }
+ for (Aggregation a : aggregate.getAggregations()) {
+ if (!included.contains(a.getName())) {
+ throw new IllegalStateException("@" + a.getName() +
+ " was not explicitly included but appeared " +
+ "in the aggregate anyway");
+ }
+ }
+
+ if (!consumer.isRunning()) {
+ throw new IllegalStateException("consumer exited");
+ }
+ }
+
+ static void
+ testCleared(Consumer consumer, String ... aggregationNames)
+ throws DTraceException, InterruptedException
+ {
+ Aggregate aggregate;
+ AggregationRecord rec;
+ long value;
+ Long firstValue;
+ int n = 1;
+ Map <String, Long> firstValues = new HashMap <String, Long> ();
+ Set <String> cleared = new HashSet <String> ();
+
+ for (String name : aggregationNames) {
+ cleared.add(name);
+ }
+
+ do {
+ Thread.sleep(TICK);
+ aggregate = consumer.getAggregate(null, cleared);
+ } while (aggregate.asMap().isEmpty() && n++ < (1000 / TICK));
+ n = 1;
+
+ do {
+ Thread.sleep(TICK * EXPECTED_TICKS);
+ aggregate = consumer.getAggregate(null, cleared);
+
+ for (Aggregation a : aggregate.getAggregations()) {
+ if (!firstValues.containsKey(a.getName())) {
+ rec = a.getRecord(Tuple.EMPTY);
+ value = rec.getValue().getValue().longValue();
+ firstValues.put(a.getName(), value);
+ }
+ }
+ } while (consumer.isRunning() && n++ < INTERVALS);
+
+ for (Aggregation a : aggregate.getAggregations()) {
+ rec = a.getRecord(Tuple.EMPTY);
+ value = rec.getValue().getValue().longValue();
+ firstValue = firstValues.get(a.getName());
+
+ if (cleared.contains(a.getName())) {
+ // last value should be about the same as first value
+ if (value > (firstValue * 2)) {
+ throw new IllegalStateException(
+ "@" + a.getName() + " should have " +
+ "been cleared but instead grew from " +
+ firstValue + " to " + value);
+ }
+ } else {
+ // last value should be about (INTERVALS * firstValue)
+ if (value < (firstValue * 2)) {
+ throw new IllegalStateException(
+ "@" + a.getName() + " should have " +
+ "accumulated a running total but " +
+ "instead went from " +
+ firstValue + " to " + value);
+ }
+ }
+ }
+
+ if (!consumer.isRunning()) {
+ throw new IllegalStateException("consumer exited");
+ }
+ }
+
+ static Integer includedStatus;
+ static Integer clearedStatus;
+
+ static void
+ startIncludedTest()
+ {
+ final Consumer consumer = new LocalConsumer();
+ consumer.addConsumerListener(new ConsumerAdapter() {
+ public void consumerStarted(ConsumerEvent e) {
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ testIncluded(consumer, ANONYMOUS_AGGREGATION);
+ includedStatus = 0;
+ } catch (Exception e) {
+ includedStatus = 1;
+ e.printStackTrace();
+ } finally {
+ consumer.abort();
+ }
+ }
+ }).start();
+ }
+ });
+
+ try {
+ consumer.open();
+ consumer.setOption(Option.aggrate, Option.millis(TICK));
+ consumer.compile(programString);
+ consumer.enable();
+ consumer.go();
+ } catch (Exception e) {
+ includedStatus = 1;
+ e.printStackTrace();
+ }
+ }
+
+ static void
+ startClearedTest()
+ {
+ final Consumer consumer = new LocalConsumer();
+ consumer.addConsumerListener(new ConsumerAdapter() {
+ public void consumerStarted(ConsumerEvent e) {
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ testCleared(consumer, ANONYMOUS_AGGREGATION);
+ clearedStatus = 0;
+ } catch (Exception e) {
+ clearedStatus = 1;
+ e.printStackTrace();
+ } finally {
+ consumer.abort();
+ }
+ }
+ }).start();
+ }
+ });
+
+ try {
+ consumer.open();
+ consumer.setOption(Option.aggrate, Option.millis(TICK));
+ consumer.compile(programString);
+ consumer.enable();
+ consumer.go();
+ } catch (Exception e) {
+ clearedStatus = 1;
+ e.printStackTrace();
+ }
+ }
+
+ public static void
+ main(String[] args)
+ {
+ startIncludedTest();
+
+ do {
+ try {
+ Thread.sleep(TICK);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } while (includedStatus == null);
+
+ startClearedTest();
+
+ do {
+ try {
+ Thread.sleep(TICK);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } while (clearedStatus == null);
+
+ if (includedStatus != 0 || clearedStatus != 0) {
+ System.out.println("Failure");
+ System.exit(1);
+ }
+
+ System.out.println("Success");
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestMaxConsumers.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestMaxConsumers.java
new file mode 100644
index 000000000000..50eeac23b7a1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestMaxConsumers.java
@@ -0,0 +1,97 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import org.opensolaris.os.dtrace.*;
+
+/**
+ * Regression for 6506495 -DJAVA_DTRACE_MAX_CONSUMERS=N for any N &lt; 8
+ * is treated as if it were 8.
+ */
+public class TestMaxConsumers {
+ static final String MAX_CONSUMERS_PROPERTY_NAME =
+ "JAVA_DTRACE_MAX_CONSUMERS";
+
+ static Integer
+ getIntegerProperty(String name)
+ {
+ Integer value = null;
+ String property = System.getProperty(name);
+ if (property != null && property.length() != 0) {
+ try {
+ value = Integer.parseInt(property);
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ }
+ return value;
+ }
+
+ public static void
+ main(String[] args)
+ {
+ Integer property = getIntegerProperty(MAX_CONSUMERS_PROPERTY_NAME);
+ int max = (property == null ? 0 : property);
+ int n = (property == null ? 11 : (max < 1 ? 1 : max));
+
+ Consumer[] consumers = new Consumer[n];
+ try {
+ for (int i = 0; i < n; ++i) {
+ consumers[i] = new LocalConsumer();
+ consumers[i].open();
+ }
+ for (int i = 0; i < n; ++i) {
+ consumers[i].close();
+ }
+ for (int i = 0; i < n; ++i) {
+ consumers[i] = new LocalConsumer();
+ consumers[i].open();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ try {
+ Consumer consumer = new LocalConsumer();
+ consumer.open();
+ if (max > 0) {
+ System.out.println("Error: " + (max + 1) + " > " +
+ MAX_CONSUMERS_PROPERTY_NAME);
+ } else {
+ System.out.println("Success");
+ }
+ consumer.close();
+ } catch (Exception e) {
+ System.out.println("Success");
+ } finally {
+ for (int i = 0; i < n; ++i) {
+ consumers[i].close();
+ }
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestMultiAggPrinta.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestMultiAggPrinta.java
new file mode 100644
index 000000000000..facdf7fad364
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestMultiAggPrinta.java
@@ -0,0 +1,144 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import org.opensolaris.os.dtrace.*;
+
+/**
+ * Regression for multi-aggregation printa() corner cases.
+ */
+public class TestMultiAggPrinta {
+ static int exitStatus;
+
+ // Gets a string representation of the given PrintaRecord minus the
+ // timestamp of the aggregate snapshot, so that the output is
+ // comparable across multiple test runs.
+ static String
+ printaRecordString(PrintaRecord rec)
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append(PrintaRecord.class.getName());
+ buf.append("[aggregations = ");
+ buf.append(rec.getAggregations());
+ buf.append(", formattedStrings = ");
+ buf.append(rec.getFormattedStrings());
+ buf.append(", tuples = ");
+ buf.append(rec.getTuples());
+ buf.append(", output = ");
+ buf.append(rec.getOutput());
+ buf.append(']');
+ return buf.toString();
+ }
+
+ static String
+ probeDataString(ProbeData data)
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append(ProbeData.class.getName());
+ buf.append("[epid = ");
+ buf.append(data.getEnabledProbeID());
+ // Do not include cpu, since it can change across test runs
+ buf.append(", enabledProbeDescription = ");
+ buf.append(data.getEnabledProbeDescription());
+ buf.append(", flow = ");
+ buf.append(data.getFlow());
+ buf.append(", records = ");
+
+ List <Record> records = data.getRecords();
+ Record record;
+ Object value;
+ buf.append('[');
+ for (int i = 0; i < records.size(); ++i) {
+ if (i > 0) {
+ buf.append(", ");
+ }
+ record = records.get(i);
+ if (record instanceof ValueRecord) {
+ value = ((ValueRecord)record).getValue();
+ if (value instanceof String) {
+ buf.append("\"");
+ buf.append((String)value);
+ buf.append("\"");
+ } else {
+ buf.append(record);
+ }
+ } else if (record instanceof PrintaRecord) {
+ PrintaRecord printa = (PrintaRecord)record;
+ buf.append(printaRecordString(printa));
+ } else {
+ buf.append(record);
+ }
+ }
+ buf.append(']');
+ return buf.toString();
+ }
+
+ public static void
+ main(String[] args)
+ {
+ if (args.length != 1) {
+ System.err.println("usage: java TestMultiAggPrinta <script>");
+ System.exit(2);
+ }
+
+ final Consumer consumer = new LocalConsumer();
+ consumer.addConsumerListener(new ConsumerAdapter() {
+ public void dataReceived(DataEvent e) {
+ ProbeData data = e.getProbeData();
+ List <Record> records = data.getRecords();
+ for (Record r : records) {
+ if (r instanceof ExitRecord) {
+ ExitRecord exitRecord = (ExitRecord)r;
+ exitStatus = exitRecord.getStatus();
+ }
+ }
+ System.out.println(probeDataString(e.getProbeData()));
+ }
+ public void consumerStopped(ConsumerEvent e) {
+ consumer.close();
+ System.exit(exitStatus);
+ }
+ });
+
+ File file = new File(args[0]);
+ try {
+ consumer.open();
+ consumer.compile(file);
+ consumer.enable();
+ consumer.go();
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ System.exit(1);
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestProbeData.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestProbeData.java
new file mode 100644
index 000000000000..78a65f9e68ee
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestProbeData.java
@@ -0,0 +1,110 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import java.util.*;
+import org.opensolaris.os.dtrace.*;
+
+/**
+ * Regression test verifies that ProbeData instances sort as expected
+ * with multiple enabled probe IDs and multiple records including byte
+ * array (sorted as unsigned bytes), stand-alone ufunc() action, and
+ * signed integer.
+ */
+public class TestProbeData {
+ public static final String PROGRAM =
+ "pid$target::fN:entry\n" +
+ "{\n" +
+ " tracemem(copyin(arg1, 6), 6);\n" +
+ " ufunc(arg0);\n" +
+ " trace((int)arg2);\n" +
+ "}" +
+ "" +
+ "pid$target::fN2:entry\n" +
+ "{\n" +
+ " tracemem(copyin(arg1, 6), 6);\n" +
+ " ufunc(arg0);\n" +
+ " trace((int)arg2);\n" +
+ "}";
+
+ static String
+ getString(ProbeData p)
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append("[probe ");
+ buf.append(p.getEnabledProbeID());
+ buf.append(' ');
+ ProbeDescription d = p.getEnabledProbeDescription();
+ buf.append("pid$target");
+ buf.append(':');
+ buf.append(d.getModule());
+ buf.append(':');
+ buf.append(d.getFunction());
+ buf.append(':');
+ buf.append(d.getName());
+ buf.append(' ');
+ buf.append(p.getRecords());
+ buf.append("]");
+ return buf.toString();
+ }
+
+ public static void
+ main(String[] args)
+ {
+ if (args.length != 1) {
+ System.err.println("usage: java TestProbedata <command>");
+ System.exit(2);
+ }
+
+ String command = args[0];
+ final Consumer consumer = new LocalConsumer();
+ final List <ProbeData> list = new ArrayList <ProbeData> ();
+ consumer.addConsumerListener(new ConsumerAdapter() {
+ public void dataReceived(DataEvent e) {
+ list.add(e.getProbeData());
+ }
+ public void consumerStopped(ConsumerEvent e) {
+ Collections.sort(list);
+ for (ProbeData p : list) {
+ System.out.println(getString(p));
+ System.out.println();
+ }
+ consumer.close();
+ }
+ });
+
+ try {
+ consumer.open();
+ consumer.createProcess(command);
+ consumer.compile(PROGRAM);
+ consumer.enable();
+ consumer.go();
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestProbeDescription.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestProbeDescription.java
new file mode 100644
index 000000000000..b9e95700278b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestProbeDescription.java
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import org.opensolaris.os.dtrace.*;
+import java.util.logging.*;
+
+/**
+ * Regression for 6399915 ProbeDescription single arg constructor should
+ * parse probe descriptions.
+ */
+public class TestProbeDescription {
+ public static void
+ main(String[] args)
+ {
+ ProbeDescription p = null;
+ int len = args.length;
+ if (len == 0) {
+ p = new ProbeDescription("syscall:::entry");
+ } else if (len == 1) {
+ p = new ProbeDescription(args[0]);
+ } else if (len == 2) {
+ p = new ProbeDescription(args[0], args[1]);
+ } else if (len == 3) {
+ p = new ProbeDescription(args[0], args[1], args[2]);
+ } else if (len == 4) {
+ p = new ProbeDescription(args[0], args[1], args[2], args[3]);
+ }
+ System.out.println(p);
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestStateMachine.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestStateMachine.java
new file mode 100644
index 000000000000..8875d0665a79
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestStateMachine.java
@@ -0,0 +1,627 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import org.opensolaris.os.dtrace.*;
+
+/**
+ * Regression test for the LocalConsumer state machine. Calls Consumer
+ * methods before and after open(), compile(), enable(), go(), stop(),
+ * and close() to verify that the calls succeed as expected or fail with
+ * the expected Java exception.
+ */
+public class TestStateMachine {
+ static Program program;
+
+ static void
+ exit(int status)
+ {
+ exit(status, null);
+ }
+
+ static void
+ exit(int status, String msg)
+ {
+ if (msg != null) {
+ System.out.println(msg);
+ }
+ System.out.flush();
+ System.err.flush();
+ System.exit(status);
+ }
+
+ static void
+ printState(Consumer consumer)
+ {
+ System.out.println("open: " + consumer.isOpen());
+ System.out.println("enabled: " + consumer.isEnabled());
+ System.out.println("closed: " + consumer.isClosed());
+ }
+
+ static void
+ beforeOpen(Consumer consumer)
+ {
+ System.out.println("before open");
+ printState(consumer);
+
+ // compile
+ try {
+ consumer.compile("syscall:::entry");
+ exit(1, "compile before open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "compile before open");
+ }
+
+ // enable
+ try {
+ consumer.enable();
+ exit(1, "enable before open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "enable before open");
+ }
+
+ // getOption, setOption, unsetOption
+ try {
+ consumer.getOption(Option.bufsize);
+ exit(1, "getOption before open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getOption before open");
+ }
+ try {
+ consumer.setOption(Option.bufsize, Option.mb(1));
+ exit(1, "setOption before open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "setOption before open");
+ }
+ try {
+ consumer.unsetOption(Option.quiet);
+ exit(1, "unsetOption before open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "unsetOption before open");
+ }
+
+ // createProcess, grabProcess
+ try {
+ consumer.createProcess("date");
+ exit(1, "createProcess before open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "createProcess before open");
+ }
+ try {
+ consumer.grabProcess(1);
+ exit(1, "grabProcess before open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "grabProcess before open");
+ }
+
+ // listProbes
+ try {
+ consumer.listProbes(ProbeDescription.EMPTY);
+ exit(1, "listProbes before open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "listProbes before open");
+ }
+
+ // getAggregate
+ try {
+ consumer.getAggregate();
+ exit(1, "getAggregate before open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getAggregate before open");
+ }
+
+ // getVersion
+ try {
+ consumer.getVersion(); // allowed
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getVersion before open");
+ }
+ }
+
+ static void
+ beforeCompile(Consumer consumer)
+ {
+ System.out.println("before compile");
+ printState(consumer);
+
+ // open
+ try {
+ consumer.open();
+ exit(1, "open after open");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "open after open");
+ }
+
+ // enable
+ try {
+ consumer.enable();
+ exit(1, "enable before compile");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "enable before compile");
+ }
+ }
+
+ static void
+ beforeEnable(Consumer consumer)
+ {
+ System.out.println("before enable");
+ printState(consumer);
+
+ // go
+ try {
+ consumer.go();
+ exit(1, "go before enable");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "go before enable");
+ }
+ }
+
+ static void
+ beforeGo(Consumer consumer)
+ {
+ System.out.println("before go");
+ printState(consumer);
+
+ // getAggregate
+ try {
+ consumer.getAggregate();
+ exit(1, "getAggregate before go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getAggregate before go");
+ }
+
+ // lookupKernelFunction, lookupUserFunction
+ try {
+ consumer.lookupKernelFunction(1);
+ exit(1, "lookupKernelFunction before go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "lookupKernelFunction before go");
+ }
+ try {
+ consumer.lookupUserFunction(1, 1);
+ exit(1, "lookupUserFunction before go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "lookupUserFunction before go");
+ }
+
+ // stop
+ try {
+ consumer.stop();
+ exit(1, "stop before go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "stop before go");
+ }
+ }
+
+ static void
+ afterGo(Consumer consumer, Program program)
+ {
+ System.out.println("after go");
+ printState(consumer);
+
+ // go
+ try {
+ consumer.go();
+ exit(1, "go after go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "go after go");
+ }
+
+ // createProcess, grabProcess
+ try {
+ consumer.createProcess("date");
+ exit(1, "createProcess after go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "createProcess after go");
+ }
+ try {
+ consumer.grabProcess(1);
+ exit(1, "grabProcess after go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "grabProcess after go");
+ }
+
+ // listProbes
+ try {
+ consumer.listProbes(ProbeDescription.EMPTY);
+ exit(1, "listProbes after go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "listProbes after go");
+ }
+
+ // compile
+ try {
+ consumer.compile("syscall:::entry");
+ exit(1, "compile after go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "compile after go");
+ }
+
+ // enable
+ try {
+ consumer.enable();
+ exit(1, "enable after go");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "enable after go");
+ }
+
+ // getAggregate
+ try {
+ consumer.getAggregate();
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getAggregate after go");
+ }
+
+ // getProgramInfo
+ try {
+ consumer.getProgramInfo(program);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getProgramInfo after go");
+ }
+
+ // getOption, setOption, unsetOption
+ try {
+ consumer.getOption(Option.quiet);
+ consumer.setOption(Option.quiet);
+ consumer.unsetOption(Option.quiet);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "get, set, unset option after go");
+ }
+ }
+
+ static void
+ afterStop(Consumer consumer, Program program)
+ {
+ System.out.println("after stop");
+ printState(consumer);
+
+ // stop
+ try {
+ consumer.stop();
+ exit(1, "stop after stop");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "stop after stop");
+ }
+
+ // getAggregate
+ try {
+ consumer.getAggregate();
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getAggregate after stop");
+ }
+
+ // getProgramInfo
+ try {
+ consumer.getProgramInfo(program);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getProgramInfo after stop");
+ }
+
+ // getOption, setOption, unsetOption
+ try {
+ consumer.getOption(Option.quiet);
+ consumer.setOption(Option.quiet);
+ consumer.unsetOption(Option.quiet);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "get, set, unset option after stop");
+ }
+ }
+
+ static void
+ afterClose(Consumer consumer, Program program)
+ {
+ System.out.println("after close");
+ printState(consumer);
+
+ // open
+ try {
+ consumer.open();
+ exit(1, "open after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "open after close");
+ }
+
+ // compile
+ try {
+ consumer.compile("syscall:::entry");
+ exit(1, "compile after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "compile after close");
+ }
+
+ // enable
+ try {
+ consumer.enable();
+ exit(1, "enable after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "enable after close");
+ }
+
+ // getOption, setOption, unsetOption
+ try {
+ consumer.getOption(Option.bufsize);
+ exit(1, "getOption after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getOption after close");
+ }
+ try {
+ consumer.setOption(Option.bufsize, Option.mb(1));
+ exit(1, "setOption after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "setOption after close");
+ }
+ try {
+ consumer.unsetOption(Option.quiet);
+ exit(1, "unsetOption after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "unsetOption after close");
+ }
+
+ // createProcess, grabProcess
+ try {
+ consumer.createProcess("date");
+ exit(1, "createProcess after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "createProcess after close");
+ }
+ try {
+ consumer.grabProcess(1);
+ exit(1, "grabProcess after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "grabProcess after close");
+ }
+
+ // listProbes
+ try {
+ consumer.listProbes(ProbeDescription.EMPTY);
+ exit(1, "listProbes after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "listProbes after close");
+ }
+
+ // getAggregate
+ try {
+ consumer.getAggregate();
+ exit(1, "getAggregate after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getAggregate after close");
+ }
+
+ // getVersion
+ try {
+ consumer.getVersion(); // allowed
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getVersion after close");
+ }
+
+ // go
+ try {
+ consumer.go();
+ exit(1, "go after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "go after close");
+ }
+
+ // lookupKernelFunction, lookupUserFunction
+ try {
+ consumer.lookupKernelFunction(1);
+ exit(1, "lookupKernelFunction after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "lookupKernelFunction after close");
+ }
+ try {
+ consumer.lookupUserFunction(1, 1);
+ exit(1, "lookupUserFunction after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "lookupUserFunction after close");
+ }
+
+ // stop
+ try {
+ consumer.stop();
+ exit(1, "stop after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "stop after close");
+ }
+
+ // getProgramInfo
+ try {
+ consumer.getProgramInfo(program);
+ exit(1, "getProgramInfo after close");
+ } catch (IllegalStateException e) {
+ System.out.println(e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ exit(1, "getProgramInfo after close");
+ }
+ }
+
+ public static void
+ main(String[] args)
+ {
+ final Consumer consumer = new LocalConsumer();
+ consumer.addConsumerListener(new ConsumerAdapter() {
+ public void consumerStarted(ConsumerEvent e) {
+ System.out.println("consumerStarted, running: " +
+ consumer.isRunning());
+ afterGo(consumer, program);
+ }
+ public void consumerStopped(ConsumerEvent e) {
+ System.out.println("consumerStopped, running: " +
+ consumer.isRunning());
+ }
+ });
+
+ try {
+ beforeOpen(consumer);
+ consumer.open();
+ beforeCompile(consumer);
+ program = consumer.compile(
+ "syscall:::entry { @[execname] = count(); } " +
+ "tick-101ms { printa(@); }");
+ beforeEnable(consumer);
+ consumer.enable();
+ beforeGo(consumer);
+ System.out.println("before go, running: " + consumer.isRunning());
+ consumer.go();
+ // Avoid race, call afterGo() in ConsumerListener
+ try {
+ Thread.currentThread().sleep(300);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ consumer.stop();
+ System.out.println("after stop, running: " + consumer.isRunning());
+ afterStop(consumer, program);
+ consumer.close();
+ afterClose(consumer, program);
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ exit(1);
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestStopLock.java b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestStopLock.java
new file mode 100644
index 000000000000..f37c9cf1eb7d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/src/TestStopLock.java
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ */
+
+import org.opensolaris.os.dtrace.*;
+
+/**
+ * Test for bug 6399888 stop() hangs if ConsumerListener calls
+ * synchronized Consumer method
+ */
+public class TestStopLock {
+ public static void
+ main(String[] args)
+ {
+ final Consumer consumer = new LocalConsumer();
+ consumer.addConsumerListener(new ConsumerAdapter() {
+ @Override
+ public void intervalBegan(ConsumerEvent e) {
+ consumer.isRunning();
+ }
+ });
+
+ try {
+ consumer.open();
+ consumer.compile("syscall:::entry { @[execname] = count(); } " +
+ "tick-101ms { printa(@); }");
+ consumer.enable();
+ consumer.go();
+ try {
+ Thread.currentThread().sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ consumer.stop();
+ consumer.close();
+ } catch (DTraceException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ System.out.println("Successful");
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Abort.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Abort.ksh
new file mode 100644
index 000000000000..85c2c706afc5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Abort.ksh
@@ -0,0 +1,39 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Fixed bug 6426129 abort() after close() throws
+# NoSuchElementException.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestAbort
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Abort.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Abort.ksh.out
new file mode 100644
index 000000000000..628d78702724
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Abort.ksh.out
@@ -0,0 +1 @@
+Successful
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Bean.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Bean.ksh
new file mode 100644
index 000000000000..99b232eb98b9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Bean.ksh
@@ -0,0 +1,41 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# All Serializable classes can be serializaed and deserialized,
+# also encoded in XML and decoded, and still remain equal and have
+# equal string values.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestBean TestBean.out
+rm -f TestBean.out
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Bean.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Bean.ksh.out
new file mode 100644
index 000000000000..cf24c672645e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Bean.ksh.out
@@ -0,0 +1,722 @@
+ExitRecord:
+ serialized: 1
+ deserialized: 1
+ExitRecord:
+ encoded: 1
+ decoded: 1
+AggregationRecord:
+ serialized: org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]
+ deserialized: org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]
+AggregationRecord:
+ encoded: org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]
+ decoded: org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]
+Aggregation:
+ serialized: org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]
+ deserialized: org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]
+Aggregation:
+ encoded: org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]
+ decoded: org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]
+Tuple:
+ serialized: [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]
+ deserialized: [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]
+Tuple:
+ encoded: [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]
+ decoded: [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]
+ScalarRecord:
+ serialized: [1, 2, 3]
+ deserialized: [1, 2, 3]
+ScalarRecord:
+ encoded: [1, 2, 3]
+ decoded: [1, 2, 3]
+KernelStackRecord:
+ serialized:
+ Frame 1
+ Frame 2
+ Frame 3
+
+ deserialized:
+ Frame 1
+ Frame 2
+ Frame 3
+
+KernelStackRecord:
+ encoded:
+ Frame 1
+ Frame 2
+ Frame 3
+
+ decoded:
+ Frame 1
+ Frame 2
+ Frame 3
+
+LogDistribution:
+ serialized: org.opensolaris.os.dtrace.Distribution[buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = -4611686018427387904, max = -2305843009213693953, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2305843009213693952, max = -1152921504606846977, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1152921504606846976, max = -576460752303423489, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = -576460752303423488, max = -288230376151711745, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = -288230376151711744, max = -144115188075855873, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = -144115188075855872, max = -72057594037927937, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = -72057594037927936, max = -36028797018963969, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = -36028797018963968, max = -18014398509481985, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = -18014398509481984, max = -9007199254740993, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = -9007199254740992, max = -4503599627370497, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4503599627370496, max = -2251799813685249, frequency = 10], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2251799813685248, max = -1125899906842625, frequency = 11], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1125899906842624, max = -562949953421313, frequency = 12], org.opensolaris.os.dtrace.Distribution$Bucket[min = -562949953421312, max = -281474976710657, frequency = 13], org.opensolaris.os.dtrace.Distribution$Bucket[min = -281474976710656, max = -140737488355329, frequency = 14], org.opensolaris.os.dtrace.Distribution$Bucket[min = -140737488355328, max = -70368744177665, frequency = 15], org.opensolaris.os.dtrace.Distribution$Bucket[min = -70368744177664, max = -35184372088833, frequency = 16], org.opensolaris.os.dtrace.Distribution$Bucket[min = -35184372088832, max = -17592186044417, frequency = 17], org.opensolaris.os.dtrace.Distribution$Bucket[min = -17592186044416, max = -8796093022209, frequency = 18], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8796093022208, max = -4398046511105, frequency = 19], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4398046511104, max = -2199023255553, frequency = 20], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2199023255552, max = -1099511627777, frequency = 21], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1099511627776, max = -549755813889, frequency = 22], org.opensolaris.os.dtrace.Distribution$Bucket[min = -549755813888, max = -274877906945, frequency = 23], org.opensolaris.os.dtrace.Distribution$Bucket[min = -274877906944, max = -137438953473, frequency = 24], org.opensolaris.os.dtrace.Distribution$Bucket[min = -137438953472, max = -68719476737, frequency = 25], org.opensolaris.os.dtrace.Distribution$Bucket[min = -68719476736, max = -34359738369, frequency = 26], org.opensolaris.os.dtrace.Distribution$Bucket[min = -34359738368, max = -17179869185, frequency = 27], org.opensolaris.os.dtrace.Distribution$Bucket[min = -17179869184, max = -8589934593, frequency = 28], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8589934592, max = -4294967297, frequency = 29], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4294967296, max = -2147483649, frequency = 30], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2147483648, max = -1073741825, frequency = 31], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1073741824, max = -536870913, frequency = 32], org.opensolaris.os.dtrace.Distribution$Bucket[min = -536870912, max = -268435457, frequency = 33], org.opensolaris.os.dtrace.Distribution$Bucket[min = -268435456, max = -134217729, frequency = 34], org.opensolaris.os.dtrace.Distribution$Bucket[min = -134217728, max = -67108865, frequency = 35], org.opensolaris.os.dtrace.Distribution$Bucket[min = -67108864, max = -33554433, frequency = 36], org.opensolaris.os.dtrace.Distribution$Bucket[min = -33554432, max = -16777217, frequency = 37], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16777216, max = -8388609, frequency = 38], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8388608, max = -4194305, frequency = 39], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4194304, max = -2097153, frequency = 40], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2097152, max = -1048577, frequency = 41], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1048576, max = -524289, frequency = 42], org.opensolaris.os.dtrace.Distribution$Bucket[min = -524288, max = -262145, frequency = 43], org.opensolaris.os.dtrace.Distribution$Bucket[min = -262144, max = -131073, frequency = 44], org.opensolaris.os.dtrace.Distribution$Bucket[min = -131072, max = -65537, frequency = 45], org.opensolaris.os.dtrace.Distribution$Bucket[min = -65536, max = -32769, frequency = 46], org.opensolaris.os.dtrace.Distribution$Bucket[min = -32768, max = -16385, frequency = 47], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16384, max = -8193, frequency = 48], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8192, max = -4097, frequency = 49], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4096, max = -2049, frequency = 50], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2048, max = -1025, frequency = 51], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1024, max = -513, frequency = 52], org.opensolaris.os.dtrace.Distribution$Bucket[min = -512, max = -257, frequency = 53], org.opensolaris.os.dtrace.Distribution$Bucket[min = -256, max = -129, frequency = 54], org.opensolaris.os.dtrace.Distribution$Bucket[min = -128, max = -65, frequency = 55], org.opensolaris.os.dtrace.Distribution$Bucket[min = -64, max = -33, frequency = 56], org.opensolaris.os.dtrace.Distribution$Bucket[min = -32, max = -17, frequency = 57], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16, max = -9, frequency = 58], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8, max = -5, frequency = 59], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4, max = -3, frequency = 60], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2, max = -2, frequency = 61], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1, max = -1, frequency = 62], org.opensolaris.os.dtrace.Distribution$Bucket[min = 0, max = 0, frequency = 63], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 1, frequency = 64], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2, max = 3, frequency = 65], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4, max = 7, frequency = 66], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8, max = 15, frequency = 67], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16, max = 31, frequency = 68], org.opensolaris.os.dtrace.Distribution$Bucket[min = 32, max = 63, frequency = 69], org.opensolaris.os.dtrace.Distribution$Bucket[min = 64, max = 127, frequency = 70], org.opensolaris.os.dtrace.Distribution$Bucket[min = 128, max = 255, frequency = 71], org.opensolaris.os.dtrace.Distribution$Bucket[min = 256, max = 511, frequency = 72], org.opensolaris.os.dtrace.Distribution$Bucket[min = 512, max = 1023, frequency = 73], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1024, max = 2047, frequency = 74], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2048, max = 4095, frequency = 75], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4096, max = 8191, frequency = 76], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8192, max = 16383, frequency = 77], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16384, max = 32767, frequency = 78], org.opensolaris.os.dtrace.Distribution$Bucket[min = 32768, max = 65535, frequency = 79], org.opensolaris.os.dtrace.Distribution$Bucket[min = 65536, max = 131071, frequency = 80], org.opensolaris.os.dtrace.Distribution$Bucket[min = 131072, max = 262143, frequency = 81], org.opensolaris.os.dtrace.Distribution$Bucket[min = 262144, max = 524287, frequency = 82], org.opensolaris.os.dtrace.Distribution$Bucket[min = 524288, max = 1048575, frequency = 83], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1048576, max = 2097151, frequency = 84], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2097152, max = 4194303, frequency = 85], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4194304, max = 8388607, frequency = 86], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8388608, max = 16777215, frequency = 87], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16777216, max = 33554431, frequency = 88], org.opensolaris.os.dtrace.Distribution$Bucket[min = 33554432, max = 67108863, frequency = 89], org.opensolaris.os.dtrace.Distribution$Bucket[min = 67108864, max = 134217727, frequency = 90], org.opensolaris.os.dtrace.Distribution$Bucket[min = 134217728, max = 268435455, frequency = 91], org.opensolaris.os.dtrace.Distribution$Bucket[min = 268435456, max = 536870911, frequency = 92], org.opensolaris.os.dtrace.Distribution$Bucket[min = 536870912, max = 1073741823, frequency = 93], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1073741824, max = 2147483647, frequency = 94], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2147483648, max = 4294967295, frequency = 95], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4294967296, max = 8589934591, frequency = 96], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8589934592, max = 17179869183, frequency = 97], org.opensolaris.os.dtrace.Distribution$Bucket[min = 17179869184, max = 34359738367, frequency = 98], org.opensolaris.os.dtrace.Distribution$Bucket[min = 34359738368, max = 68719476735, frequency = 99], org.opensolaris.os.dtrace.Distribution$Bucket[min = 68719476736, max = 137438953471, frequency = 100], org.opensolaris.os.dtrace.Distribution$Bucket[min = 137438953472, max = 274877906943, frequency = 101], org.opensolaris.os.dtrace.Distribution$Bucket[min = 274877906944, max = 549755813887, frequency = 102], org.opensolaris.os.dtrace.Distribution$Bucket[min = 549755813888, max = 1099511627775, frequency = 103], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1099511627776, max = 2199023255551, frequency = 104], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2199023255552, max = 4398046511103, frequency = 105], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4398046511104, max = 8796093022207, frequency = 106], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8796093022208, max = 17592186044415, frequency = 107], org.opensolaris.os.dtrace.Distribution$Bucket[min = 17592186044416, max = 35184372088831, frequency = 108], org.opensolaris.os.dtrace.Distribution$Bucket[min = 35184372088832, max = 70368744177663, frequency = 109], org.opensolaris.os.dtrace.Distribution$Bucket[min = 70368744177664, max = 140737488355327, frequency = 110], org.opensolaris.os.dtrace.Distribution$Bucket[min = 140737488355328, max = 281474976710655, frequency = 111], org.opensolaris.os.dtrace.Distribution$Bucket[min = 281474976710656, max = 562949953421311, frequency = 112], org.opensolaris.os.dtrace.Distribution$Bucket[min = 562949953421312, max = 1125899906842623, frequency = 113], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1125899906842624, max = 2251799813685247, frequency = 114], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2251799813685248, max = 4503599627370495, frequency = 115], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4503599627370496, max = 9007199254740991, frequency = 116], org.opensolaris.os.dtrace.Distribution$Bucket[min = 9007199254740992, max = 18014398509481983, frequency = 117], org.opensolaris.os.dtrace.Distribution$Bucket[min = 18014398509481984, max = 36028797018963967, frequency = 118], org.opensolaris.os.dtrace.Distribution$Bucket[min = 36028797018963968, max = 72057594037927935, frequency = 119], org.opensolaris.os.dtrace.Distribution$Bucket[min = 72057594037927936, max = 144115188075855871, frequency = 120], org.opensolaris.os.dtrace.Distribution$Bucket[min = 144115188075855872, max = 288230376151711743, frequency = 121], org.opensolaris.os.dtrace.Distribution$Bucket[min = 288230376151711744, max = 576460752303423487, frequency = 122], org.opensolaris.os.dtrace.Distribution$Bucket[min = 576460752303423488, max = 1152921504606846975, frequency = 123], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1152921504606846976, max = 2305843009213693951, frequency = 124], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2305843009213693952, max = 4611686018427387903, frequency = 125], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4611686018427387904, max = 9223372036854775807, frequency = 126]], total = 8001.0]
+ deserialized: org.opensolaris.os.dtrace.Distribution[buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = -4611686018427387904, max = -2305843009213693953, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2305843009213693952, max = -1152921504606846977, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1152921504606846976, max = -576460752303423489, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = -576460752303423488, max = -288230376151711745, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = -288230376151711744, max = -144115188075855873, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = -144115188075855872, max = -72057594037927937, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = -72057594037927936, max = -36028797018963969, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = -36028797018963968, max = -18014398509481985, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = -18014398509481984, max = -9007199254740993, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = -9007199254740992, max = -4503599627370497, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4503599627370496, max = -2251799813685249, frequency = 10], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2251799813685248, max = -1125899906842625, frequency = 11], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1125899906842624, max = -562949953421313, frequency = 12], org.opensolaris.os.dtrace.Distribution$Bucket[min = -562949953421312, max = -281474976710657, frequency = 13], org.opensolaris.os.dtrace.Distribution$Bucket[min = -281474976710656, max = -140737488355329, frequency = 14], org.opensolaris.os.dtrace.Distribution$Bucket[min = -140737488355328, max = -70368744177665, frequency = 15], org.opensolaris.os.dtrace.Distribution$Bucket[min = -70368744177664, max = -35184372088833, frequency = 16], org.opensolaris.os.dtrace.Distribution$Bucket[min = -35184372088832, max = -17592186044417, frequency = 17], org.opensolaris.os.dtrace.Distribution$Bucket[min = -17592186044416, max = -8796093022209, frequency = 18], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8796093022208, max = -4398046511105, frequency = 19], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4398046511104, max = -2199023255553, frequency = 20], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2199023255552, max = -1099511627777, frequency = 21], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1099511627776, max = -549755813889, frequency = 22], org.opensolaris.os.dtrace.Distribution$Bucket[min = -549755813888, max = -274877906945, frequency = 23], org.opensolaris.os.dtrace.Distribution$Bucket[min = -274877906944, max = -137438953473, frequency = 24], org.opensolaris.os.dtrace.Distribution$Bucket[min = -137438953472, max = -68719476737, frequency = 25], org.opensolaris.os.dtrace.Distribution$Bucket[min = -68719476736, max = -34359738369, frequency = 26], org.opensolaris.os.dtrace.Distribution$Bucket[min = -34359738368, max = -17179869185, frequency = 27], org.opensolaris.os.dtrace.Distribution$Bucket[min = -17179869184, max = -8589934593, frequency = 28], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8589934592, max = -4294967297, frequency = 29], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4294967296, max = -2147483649, frequency = 30], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2147483648, max = -1073741825, frequency = 31], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1073741824, max = -536870913, frequency = 32], org.opensolaris.os.dtrace.Distribution$Bucket[min = -536870912, max = -268435457, frequency = 33], org.opensolaris.os.dtrace.Distribution$Bucket[min = -268435456, max = -134217729, frequency = 34], org.opensolaris.os.dtrace.Distribution$Bucket[min = -134217728, max = -67108865, frequency = 35], org.opensolaris.os.dtrace.Distribution$Bucket[min = -67108864, max = -33554433, frequency = 36], org.opensolaris.os.dtrace.Distribution$Bucket[min = -33554432, max = -16777217, frequency = 37], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16777216, max = -8388609, frequency = 38], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8388608, max = -4194305, frequency = 39], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4194304, max = -2097153, frequency = 40], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2097152, max = -1048577, frequency = 41], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1048576, max = -524289, frequency = 42], org.opensolaris.os.dtrace.Distribution$Bucket[min = -524288, max = -262145, frequency = 43], org.opensolaris.os.dtrace.Distribution$Bucket[min = -262144, max = -131073, frequency = 44], org.opensolaris.os.dtrace.Distribution$Bucket[min = -131072, max = -65537, frequency = 45], org.opensolaris.os.dtrace.Distribution$Bucket[min = -65536, max = -32769, frequency = 46], org.opensolaris.os.dtrace.Distribution$Bucket[min = -32768, max = -16385, frequency = 47], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16384, max = -8193, frequency = 48], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8192, max = -4097, frequency = 49], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4096, max = -2049, frequency = 50], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2048, max = -1025, frequency = 51], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1024, max = -513, frequency = 52], org.opensolaris.os.dtrace.Distribution$Bucket[min = -512, max = -257, frequency = 53], org.opensolaris.os.dtrace.Distribution$Bucket[min = -256, max = -129, frequency = 54], org.opensolaris.os.dtrace.Distribution$Bucket[min = -128, max = -65, frequency = 55], org.opensolaris.os.dtrace.Distribution$Bucket[min = -64, max = -33, frequency = 56], org.opensolaris.os.dtrace.Distribution$Bucket[min = -32, max = -17, frequency = 57], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16, max = -9, frequency = 58], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8, max = -5, frequency = 59], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4, max = -3, frequency = 60], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2, max = -2, frequency = 61], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1, max = -1, frequency = 62], org.opensolaris.os.dtrace.Distribution$Bucket[min = 0, max = 0, frequency = 63], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 1, frequency = 64], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2, max = 3, frequency = 65], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4, max = 7, frequency = 66], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8, max = 15, frequency = 67], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16, max = 31, frequency = 68], org.opensolaris.os.dtrace.Distribution$Bucket[min = 32, max = 63, frequency = 69], org.opensolaris.os.dtrace.Distribution$Bucket[min = 64, max = 127, frequency = 70], org.opensolaris.os.dtrace.Distribution$Bucket[min = 128, max = 255, frequency = 71], org.opensolaris.os.dtrace.Distribution$Bucket[min = 256, max = 511, frequency = 72], org.opensolaris.os.dtrace.Distribution$Bucket[min = 512, max = 1023, frequency = 73], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1024, max = 2047, frequency = 74], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2048, max = 4095, frequency = 75], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4096, max = 8191, frequency = 76], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8192, max = 16383, frequency = 77], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16384, max = 32767, frequency = 78], org.opensolaris.os.dtrace.Distribution$Bucket[min = 32768, max = 65535, frequency = 79], org.opensolaris.os.dtrace.Distribution$Bucket[min = 65536, max = 131071, frequency = 80], org.opensolaris.os.dtrace.Distribution$Bucket[min = 131072, max = 262143, frequency = 81], org.opensolaris.os.dtrace.Distribution$Bucket[min = 262144, max = 524287, frequency = 82], org.opensolaris.os.dtrace.Distribution$Bucket[min = 524288, max = 1048575, frequency = 83], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1048576, max = 2097151, frequency = 84], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2097152, max = 4194303, frequency = 85], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4194304, max = 8388607, frequency = 86], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8388608, max = 16777215, frequency = 87], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16777216, max = 33554431, frequency = 88], org.opensolaris.os.dtrace.Distribution$Bucket[min = 33554432, max = 67108863, frequency = 89], org.opensolaris.os.dtrace.Distribution$Bucket[min = 67108864, max = 134217727, frequency = 90], org.opensolaris.os.dtrace.Distribution$Bucket[min = 134217728, max = 268435455, frequency = 91], org.opensolaris.os.dtrace.Distribution$Bucket[min = 268435456, max = 536870911, frequency = 92], org.opensolaris.os.dtrace.Distribution$Bucket[min = 536870912, max = 1073741823, frequency = 93], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1073741824, max = 2147483647, frequency = 94], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2147483648, max = 4294967295, frequency = 95], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4294967296, max = 8589934591, frequency = 96], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8589934592, max = 17179869183, frequency = 97], org.opensolaris.os.dtrace.Distribution$Bucket[min = 17179869184, max = 34359738367, frequency = 98], org.opensolaris.os.dtrace.Distribution$Bucket[min = 34359738368, max = 68719476735, frequency = 99], org.opensolaris.os.dtrace.Distribution$Bucket[min = 68719476736, max = 137438953471, frequency = 100], org.opensolaris.os.dtrace.Distribution$Bucket[min = 137438953472, max = 274877906943, frequency = 101], org.opensolaris.os.dtrace.Distribution$Bucket[min = 274877906944, max = 549755813887, frequency = 102], org.opensolaris.os.dtrace.Distribution$Bucket[min = 549755813888, max = 1099511627775, frequency = 103], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1099511627776, max = 2199023255551, frequency = 104], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2199023255552, max = 4398046511103, frequency = 105], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4398046511104, max = 8796093022207, frequency = 106], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8796093022208, max = 17592186044415, frequency = 107], org.opensolaris.os.dtrace.Distribution$Bucket[min = 17592186044416, max = 35184372088831, frequency = 108], org.opensolaris.os.dtrace.Distribution$Bucket[min = 35184372088832, max = 70368744177663, frequency = 109], org.opensolaris.os.dtrace.Distribution$Bucket[min = 70368744177664, max = 140737488355327, frequency = 110], org.opensolaris.os.dtrace.Distribution$Bucket[min = 140737488355328, max = 281474976710655, frequency = 111], org.opensolaris.os.dtrace.Distribution$Bucket[min = 281474976710656, max = 562949953421311, frequency = 112], org.opensolaris.os.dtrace.Distribution$Bucket[min = 562949953421312, max = 1125899906842623, frequency = 113], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1125899906842624, max = 2251799813685247, frequency = 114], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2251799813685248, max = 4503599627370495, frequency = 115], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4503599627370496, max = 9007199254740991, frequency = 116], org.opensolaris.os.dtrace.Distribution$Bucket[min = 9007199254740992, max = 18014398509481983, frequency = 117], org.opensolaris.os.dtrace.Distribution$Bucket[min = 18014398509481984, max = 36028797018963967, frequency = 118], org.opensolaris.os.dtrace.Distribution$Bucket[min = 36028797018963968, max = 72057594037927935, frequency = 119], org.opensolaris.os.dtrace.Distribution$Bucket[min = 72057594037927936, max = 144115188075855871, frequency = 120], org.opensolaris.os.dtrace.Distribution$Bucket[min = 144115188075855872, max = 288230376151711743, frequency = 121], org.opensolaris.os.dtrace.Distribution$Bucket[min = 288230376151711744, max = 576460752303423487, frequency = 122], org.opensolaris.os.dtrace.Distribution$Bucket[min = 576460752303423488, max = 1152921504606846975, frequency = 123], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1152921504606846976, max = 2305843009213693951, frequency = 124], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2305843009213693952, max = 4611686018427387903, frequency = 125], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4611686018427387904, max = 9223372036854775807, frequency = 126]], total = 8001.0]
+LogDistribution:
+ encoded: org.opensolaris.os.dtrace.Distribution[buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = -4611686018427387904, max = -2305843009213693953, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2305843009213693952, max = -1152921504606846977, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1152921504606846976, max = -576460752303423489, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = -576460752303423488, max = -288230376151711745, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = -288230376151711744, max = -144115188075855873, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = -144115188075855872, max = -72057594037927937, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = -72057594037927936, max = -36028797018963969, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = -36028797018963968, max = -18014398509481985, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = -18014398509481984, max = -9007199254740993, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = -9007199254740992, max = -4503599627370497, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4503599627370496, max = -2251799813685249, frequency = 10], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2251799813685248, max = -1125899906842625, frequency = 11], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1125899906842624, max = -562949953421313, frequency = 12], org.opensolaris.os.dtrace.Distribution$Bucket[min = -562949953421312, max = -281474976710657, frequency = 13], org.opensolaris.os.dtrace.Distribution$Bucket[min = -281474976710656, max = -140737488355329, frequency = 14], org.opensolaris.os.dtrace.Distribution$Bucket[min = -140737488355328, max = -70368744177665, frequency = 15], org.opensolaris.os.dtrace.Distribution$Bucket[min = -70368744177664, max = -35184372088833, frequency = 16], org.opensolaris.os.dtrace.Distribution$Bucket[min = -35184372088832, max = -17592186044417, frequency = 17], org.opensolaris.os.dtrace.Distribution$Bucket[min = -17592186044416, max = -8796093022209, frequency = 18], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8796093022208, max = -4398046511105, frequency = 19], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4398046511104, max = -2199023255553, frequency = 20], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2199023255552, max = -1099511627777, frequency = 21], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1099511627776, max = -549755813889, frequency = 22], org.opensolaris.os.dtrace.Distribution$Bucket[min = -549755813888, max = -274877906945, frequency = 23], org.opensolaris.os.dtrace.Distribution$Bucket[min = -274877906944, max = -137438953473, frequency = 24], org.opensolaris.os.dtrace.Distribution$Bucket[min = -137438953472, max = -68719476737, frequency = 25], org.opensolaris.os.dtrace.Distribution$Bucket[min = -68719476736, max = -34359738369, frequency = 26], org.opensolaris.os.dtrace.Distribution$Bucket[min = -34359738368, max = -17179869185, frequency = 27], org.opensolaris.os.dtrace.Distribution$Bucket[min = -17179869184, max = -8589934593, frequency = 28], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8589934592, max = -4294967297, frequency = 29], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4294967296, max = -2147483649, frequency = 30], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2147483648, max = -1073741825, frequency = 31], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1073741824, max = -536870913, frequency = 32], org.opensolaris.os.dtrace.Distribution$Bucket[min = -536870912, max = -268435457, frequency = 33], org.opensolaris.os.dtrace.Distribution$Bucket[min = -268435456, max = -134217729, frequency = 34], org.opensolaris.os.dtrace.Distribution$Bucket[min = -134217728, max = -67108865, frequency = 35], org.opensolaris.os.dtrace.Distribution$Bucket[min = -67108864, max = -33554433, frequency = 36], org.opensolaris.os.dtrace.Distribution$Bucket[min = -33554432, max = -16777217, frequency = 37], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16777216, max = -8388609, frequency = 38], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8388608, max = -4194305, frequency = 39], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4194304, max = -2097153, frequency = 40], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2097152, max = -1048577, frequency = 41], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1048576, max = -524289, frequency = 42], org.opensolaris.os.dtrace.Distribution$Bucket[min = -524288, max = -262145, frequency = 43], org.opensolaris.os.dtrace.Distribution$Bucket[min = -262144, max = -131073, frequency = 44], org.opensolaris.os.dtrace.Distribution$Bucket[min = -131072, max = -65537, frequency = 45], org.opensolaris.os.dtrace.Distribution$Bucket[min = -65536, max = -32769, frequency = 46], org.opensolaris.os.dtrace.Distribution$Bucket[min = -32768, max = -16385, frequency = 47], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16384, max = -8193, frequency = 48], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8192, max = -4097, frequency = 49], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4096, max = -2049, frequency = 50], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2048, max = -1025, frequency = 51], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1024, max = -513, frequency = 52], org.opensolaris.os.dtrace.Distribution$Bucket[min = -512, max = -257, frequency = 53], org.opensolaris.os.dtrace.Distribution$Bucket[min = -256, max = -129, frequency = 54], org.opensolaris.os.dtrace.Distribution$Bucket[min = -128, max = -65, frequency = 55], org.opensolaris.os.dtrace.Distribution$Bucket[min = -64, max = -33, frequency = 56], org.opensolaris.os.dtrace.Distribution$Bucket[min = -32, max = -17, frequency = 57], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16, max = -9, frequency = 58], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8, max = -5, frequency = 59], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4, max = -3, frequency = 60], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2, max = -2, frequency = 61], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1, max = -1, frequency = 62], org.opensolaris.os.dtrace.Distribution$Bucket[min = 0, max = 0, frequency = 63], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 1, frequency = 64], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2, max = 3, frequency = 65], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4, max = 7, frequency = 66], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8, max = 15, frequency = 67], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16, max = 31, frequency = 68], org.opensolaris.os.dtrace.Distribution$Bucket[min = 32, max = 63, frequency = 69], org.opensolaris.os.dtrace.Distribution$Bucket[min = 64, max = 127, frequency = 70], org.opensolaris.os.dtrace.Distribution$Bucket[min = 128, max = 255, frequency = 71], org.opensolaris.os.dtrace.Distribution$Bucket[min = 256, max = 511, frequency = 72], org.opensolaris.os.dtrace.Distribution$Bucket[min = 512, max = 1023, frequency = 73], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1024, max = 2047, frequency = 74], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2048, max = 4095, frequency = 75], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4096, max = 8191, frequency = 76], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8192, max = 16383, frequency = 77], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16384, max = 32767, frequency = 78], org.opensolaris.os.dtrace.Distribution$Bucket[min = 32768, max = 65535, frequency = 79], org.opensolaris.os.dtrace.Distribution$Bucket[min = 65536, max = 131071, frequency = 80], org.opensolaris.os.dtrace.Distribution$Bucket[min = 131072, max = 262143, frequency = 81], org.opensolaris.os.dtrace.Distribution$Bucket[min = 262144, max = 524287, frequency = 82], org.opensolaris.os.dtrace.Distribution$Bucket[min = 524288, max = 1048575, frequency = 83], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1048576, max = 2097151, frequency = 84], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2097152, max = 4194303, frequency = 85], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4194304, max = 8388607, frequency = 86], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8388608, max = 16777215, frequency = 87], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16777216, max = 33554431, frequency = 88], org.opensolaris.os.dtrace.Distribution$Bucket[min = 33554432, max = 67108863, frequency = 89], org.opensolaris.os.dtrace.Distribution$Bucket[min = 67108864, max = 134217727, frequency = 90], org.opensolaris.os.dtrace.Distribution$Bucket[min = 134217728, max = 268435455, frequency = 91], org.opensolaris.os.dtrace.Distribution$Bucket[min = 268435456, max = 536870911, frequency = 92], org.opensolaris.os.dtrace.Distribution$Bucket[min = 536870912, max = 1073741823, frequency = 93], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1073741824, max = 2147483647, frequency = 94], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2147483648, max = 4294967295, frequency = 95], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4294967296, max = 8589934591, frequency = 96], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8589934592, max = 17179869183, frequency = 97], org.opensolaris.os.dtrace.Distribution$Bucket[min = 17179869184, max = 34359738367, frequency = 98], org.opensolaris.os.dtrace.Distribution$Bucket[min = 34359738368, max = 68719476735, frequency = 99], org.opensolaris.os.dtrace.Distribution$Bucket[min = 68719476736, max = 137438953471, frequency = 100], org.opensolaris.os.dtrace.Distribution$Bucket[min = 137438953472, max = 274877906943, frequency = 101], org.opensolaris.os.dtrace.Distribution$Bucket[min = 274877906944, max = 549755813887, frequency = 102], org.opensolaris.os.dtrace.Distribution$Bucket[min = 549755813888, max = 1099511627775, frequency = 103], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1099511627776, max = 2199023255551, frequency = 104], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2199023255552, max = 4398046511103, frequency = 105], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4398046511104, max = 8796093022207, frequency = 106], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8796093022208, max = 17592186044415, frequency = 107], org.opensolaris.os.dtrace.Distribution$Bucket[min = 17592186044416, max = 35184372088831, frequency = 108], org.opensolaris.os.dtrace.Distribution$Bucket[min = 35184372088832, max = 70368744177663, frequency = 109], org.opensolaris.os.dtrace.Distribution$Bucket[min = 70368744177664, max = 140737488355327, frequency = 110], org.opensolaris.os.dtrace.Distribution$Bucket[min = 140737488355328, max = 281474976710655, frequency = 111], org.opensolaris.os.dtrace.Distribution$Bucket[min = 281474976710656, max = 562949953421311, frequency = 112], org.opensolaris.os.dtrace.Distribution$Bucket[min = 562949953421312, max = 1125899906842623, frequency = 113], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1125899906842624, max = 2251799813685247, frequency = 114], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2251799813685248, max = 4503599627370495, frequency = 115], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4503599627370496, max = 9007199254740991, frequency = 116], org.opensolaris.os.dtrace.Distribution$Bucket[min = 9007199254740992, max = 18014398509481983, frequency = 117], org.opensolaris.os.dtrace.Distribution$Bucket[min = 18014398509481984, max = 36028797018963967, frequency = 118], org.opensolaris.os.dtrace.Distribution$Bucket[min = 36028797018963968, max = 72057594037927935, frequency = 119], org.opensolaris.os.dtrace.Distribution$Bucket[min = 72057594037927936, max = 144115188075855871, frequency = 120], org.opensolaris.os.dtrace.Distribution$Bucket[min = 144115188075855872, max = 288230376151711743, frequency = 121], org.opensolaris.os.dtrace.Distribution$Bucket[min = 288230376151711744, max = 576460752303423487, frequency = 122], org.opensolaris.os.dtrace.Distribution$Bucket[min = 576460752303423488, max = 1152921504606846975, frequency = 123], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1152921504606846976, max = 2305843009213693951, frequency = 124], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2305843009213693952, max = 4611686018427387903, frequency = 125], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4611686018427387904, max = 9223372036854775807, frequency = 126]], total = 8001.0]
+ decoded: org.opensolaris.os.dtrace.Distribution[buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = -4611686018427387904, max = -2305843009213693953, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2305843009213693952, max = -1152921504606846977, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1152921504606846976, max = -576460752303423489, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = -576460752303423488, max = -288230376151711745, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = -288230376151711744, max = -144115188075855873, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = -144115188075855872, max = -72057594037927937, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = -72057594037927936, max = -36028797018963969, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = -36028797018963968, max = -18014398509481985, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = -18014398509481984, max = -9007199254740993, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = -9007199254740992, max = -4503599627370497, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4503599627370496, max = -2251799813685249, frequency = 10], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2251799813685248, max = -1125899906842625, frequency = 11], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1125899906842624, max = -562949953421313, frequency = 12], org.opensolaris.os.dtrace.Distribution$Bucket[min = -562949953421312, max = -281474976710657, frequency = 13], org.opensolaris.os.dtrace.Distribution$Bucket[min = -281474976710656, max = -140737488355329, frequency = 14], org.opensolaris.os.dtrace.Distribution$Bucket[min = -140737488355328, max = -70368744177665, frequency = 15], org.opensolaris.os.dtrace.Distribution$Bucket[min = -70368744177664, max = -35184372088833, frequency = 16], org.opensolaris.os.dtrace.Distribution$Bucket[min = -35184372088832, max = -17592186044417, frequency = 17], org.opensolaris.os.dtrace.Distribution$Bucket[min = -17592186044416, max = -8796093022209, frequency = 18], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8796093022208, max = -4398046511105, frequency = 19], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4398046511104, max = -2199023255553, frequency = 20], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2199023255552, max = -1099511627777, frequency = 21], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1099511627776, max = -549755813889, frequency = 22], org.opensolaris.os.dtrace.Distribution$Bucket[min = -549755813888, max = -274877906945, frequency = 23], org.opensolaris.os.dtrace.Distribution$Bucket[min = -274877906944, max = -137438953473, frequency = 24], org.opensolaris.os.dtrace.Distribution$Bucket[min = -137438953472, max = -68719476737, frequency = 25], org.opensolaris.os.dtrace.Distribution$Bucket[min = -68719476736, max = -34359738369, frequency = 26], org.opensolaris.os.dtrace.Distribution$Bucket[min = -34359738368, max = -17179869185, frequency = 27], org.opensolaris.os.dtrace.Distribution$Bucket[min = -17179869184, max = -8589934593, frequency = 28], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8589934592, max = -4294967297, frequency = 29], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4294967296, max = -2147483649, frequency = 30], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2147483648, max = -1073741825, frequency = 31], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1073741824, max = -536870913, frequency = 32], org.opensolaris.os.dtrace.Distribution$Bucket[min = -536870912, max = -268435457, frequency = 33], org.opensolaris.os.dtrace.Distribution$Bucket[min = -268435456, max = -134217729, frequency = 34], org.opensolaris.os.dtrace.Distribution$Bucket[min = -134217728, max = -67108865, frequency = 35], org.opensolaris.os.dtrace.Distribution$Bucket[min = -67108864, max = -33554433, frequency = 36], org.opensolaris.os.dtrace.Distribution$Bucket[min = -33554432, max = -16777217, frequency = 37], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16777216, max = -8388609, frequency = 38], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8388608, max = -4194305, frequency = 39], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4194304, max = -2097153, frequency = 40], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2097152, max = -1048577, frequency = 41], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1048576, max = -524289, frequency = 42], org.opensolaris.os.dtrace.Distribution$Bucket[min = -524288, max = -262145, frequency = 43], org.opensolaris.os.dtrace.Distribution$Bucket[min = -262144, max = -131073, frequency = 44], org.opensolaris.os.dtrace.Distribution$Bucket[min = -131072, max = -65537, frequency = 45], org.opensolaris.os.dtrace.Distribution$Bucket[min = -65536, max = -32769, frequency = 46], org.opensolaris.os.dtrace.Distribution$Bucket[min = -32768, max = -16385, frequency = 47], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16384, max = -8193, frequency = 48], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8192, max = -4097, frequency = 49], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4096, max = -2049, frequency = 50], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2048, max = -1025, frequency = 51], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1024, max = -513, frequency = 52], org.opensolaris.os.dtrace.Distribution$Bucket[min = -512, max = -257, frequency = 53], org.opensolaris.os.dtrace.Distribution$Bucket[min = -256, max = -129, frequency = 54], org.opensolaris.os.dtrace.Distribution$Bucket[min = -128, max = -65, frequency = 55], org.opensolaris.os.dtrace.Distribution$Bucket[min = -64, max = -33, frequency = 56], org.opensolaris.os.dtrace.Distribution$Bucket[min = -32, max = -17, frequency = 57], org.opensolaris.os.dtrace.Distribution$Bucket[min = -16, max = -9, frequency = 58], org.opensolaris.os.dtrace.Distribution$Bucket[min = -8, max = -5, frequency = 59], org.opensolaris.os.dtrace.Distribution$Bucket[min = -4, max = -3, frequency = 60], org.opensolaris.os.dtrace.Distribution$Bucket[min = -2, max = -2, frequency = 61], org.opensolaris.os.dtrace.Distribution$Bucket[min = -1, max = -1, frequency = 62], org.opensolaris.os.dtrace.Distribution$Bucket[min = 0, max = 0, frequency = 63], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 1, frequency = 64], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2, max = 3, frequency = 65], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4, max = 7, frequency = 66], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8, max = 15, frequency = 67], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16, max = 31, frequency = 68], org.opensolaris.os.dtrace.Distribution$Bucket[min = 32, max = 63, frequency = 69], org.opensolaris.os.dtrace.Distribution$Bucket[min = 64, max = 127, frequency = 70], org.opensolaris.os.dtrace.Distribution$Bucket[min = 128, max = 255, frequency = 71], org.opensolaris.os.dtrace.Distribution$Bucket[min = 256, max = 511, frequency = 72], org.opensolaris.os.dtrace.Distribution$Bucket[min = 512, max = 1023, frequency = 73], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1024, max = 2047, frequency = 74], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2048, max = 4095, frequency = 75], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4096, max = 8191, frequency = 76], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8192, max = 16383, frequency = 77], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16384, max = 32767, frequency = 78], org.opensolaris.os.dtrace.Distribution$Bucket[min = 32768, max = 65535, frequency = 79], org.opensolaris.os.dtrace.Distribution$Bucket[min = 65536, max = 131071, frequency = 80], org.opensolaris.os.dtrace.Distribution$Bucket[min = 131072, max = 262143, frequency = 81], org.opensolaris.os.dtrace.Distribution$Bucket[min = 262144, max = 524287, frequency = 82], org.opensolaris.os.dtrace.Distribution$Bucket[min = 524288, max = 1048575, frequency = 83], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1048576, max = 2097151, frequency = 84], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2097152, max = 4194303, frequency = 85], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4194304, max = 8388607, frequency = 86], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8388608, max = 16777215, frequency = 87], org.opensolaris.os.dtrace.Distribution$Bucket[min = 16777216, max = 33554431, frequency = 88], org.opensolaris.os.dtrace.Distribution$Bucket[min = 33554432, max = 67108863, frequency = 89], org.opensolaris.os.dtrace.Distribution$Bucket[min = 67108864, max = 134217727, frequency = 90], org.opensolaris.os.dtrace.Distribution$Bucket[min = 134217728, max = 268435455, frequency = 91], org.opensolaris.os.dtrace.Distribution$Bucket[min = 268435456, max = 536870911, frequency = 92], org.opensolaris.os.dtrace.Distribution$Bucket[min = 536870912, max = 1073741823, frequency = 93], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1073741824, max = 2147483647, frequency = 94], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2147483648, max = 4294967295, frequency = 95], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4294967296, max = 8589934591, frequency = 96], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8589934592, max = 17179869183, frequency = 97], org.opensolaris.os.dtrace.Distribution$Bucket[min = 17179869184, max = 34359738367, frequency = 98], org.opensolaris.os.dtrace.Distribution$Bucket[min = 34359738368, max = 68719476735, frequency = 99], org.opensolaris.os.dtrace.Distribution$Bucket[min = 68719476736, max = 137438953471, frequency = 100], org.opensolaris.os.dtrace.Distribution$Bucket[min = 137438953472, max = 274877906943, frequency = 101], org.opensolaris.os.dtrace.Distribution$Bucket[min = 274877906944, max = 549755813887, frequency = 102], org.opensolaris.os.dtrace.Distribution$Bucket[min = 549755813888, max = 1099511627775, frequency = 103], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1099511627776, max = 2199023255551, frequency = 104], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2199023255552, max = 4398046511103, frequency = 105], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4398046511104, max = 8796093022207, frequency = 106], org.opensolaris.os.dtrace.Distribution$Bucket[min = 8796093022208, max = 17592186044415, frequency = 107], org.opensolaris.os.dtrace.Distribution$Bucket[min = 17592186044416, max = 35184372088831, frequency = 108], org.opensolaris.os.dtrace.Distribution$Bucket[min = 35184372088832, max = 70368744177663, frequency = 109], org.opensolaris.os.dtrace.Distribution$Bucket[min = 70368744177664, max = 140737488355327, frequency = 110], org.opensolaris.os.dtrace.Distribution$Bucket[min = 140737488355328, max = 281474976710655, frequency = 111], org.opensolaris.os.dtrace.Distribution$Bucket[min = 281474976710656, max = 562949953421311, frequency = 112], org.opensolaris.os.dtrace.Distribution$Bucket[min = 562949953421312, max = 1125899906842623, frequency = 113], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1125899906842624, max = 2251799813685247, frequency = 114], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2251799813685248, max = 4503599627370495, frequency = 115], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4503599627370496, max = 9007199254740991, frequency = 116], org.opensolaris.os.dtrace.Distribution$Bucket[min = 9007199254740992, max = 18014398509481983, frequency = 117], org.opensolaris.os.dtrace.Distribution$Bucket[min = 18014398509481984, max = 36028797018963967, frequency = 118], org.opensolaris.os.dtrace.Distribution$Bucket[min = 36028797018963968, max = 72057594037927935, frequency = 119], org.opensolaris.os.dtrace.Distribution$Bucket[min = 72057594037927936, max = 144115188075855871, frequency = 120], org.opensolaris.os.dtrace.Distribution$Bucket[min = 144115188075855872, max = 288230376151711743, frequency = 121], org.opensolaris.os.dtrace.Distribution$Bucket[min = 288230376151711744, max = 576460752303423487, frequency = 122], org.opensolaris.os.dtrace.Distribution$Bucket[min = 576460752303423488, max = 1152921504606846975, frequency = 123], org.opensolaris.os.dtrace.Distribution$Bucket[min = 1152921504606846976, max = 2305843009213693951, frequency = 124], org.opensolaris.os.dtrace.Distribution$Bucket[min = 2305843009213693952, max = 4611686018427387903, frequency = 125], org.opensolaris.os.dtrace.Distribution$Bucket[min = 4611686018427387904, max = 9223372036854775807, frequency = 126]], total = 8001.0]
+LinearDistribution:
+ serialized: class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]
+ deserialized: class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]
+LinearDistribution:
+ encoded: class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]
+ decoded: class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]
+Option:
+ serialized: org.opensolaris.os.dtrace.Option[name = aggrate, value = 1s]
+ deserialized: org.opensolaris.os.dtrace.Option[name = aggrate, value = 1s]
+Option:
+ encoded: org.opensolaris.os.dtrace.Option[name = aggrate, value = 1s]
+ decoded: org.opensolaris.os.dtrace.Option[name = aggrate, value = 1s]
+ProcessState:
+ serialized: org.opensolaris.os.dtrace.ProcessState[pid = 123456, state = UNDEAD, terminationSignal = 3, terminationSignalName = SIGSTOP, exitStatus = -2, message = Process stopped on dime]
+ deserialized: org.opensolaris.os.dtrace.ProcessState[pid = 123456, state = UNDEAD, terminationSignal = 3, terminationSignalName = SIGSTOP, exitStatus = -2, message = Process stopped on dime]
+ProcessState:
+ encoded: org.opensolaris.os.dtrace.ProcessState[pid = 123456, state = UNDEAD, terminationSignal = 3, terminationSignalName = SIGSTOP, exitStatus = -2, message = Process stopped on dime]
+ decoded: org.opensolaris.os.dtrace.ProcessState[pid = 123456, state = UNDEAD, terminationSignal = 3, terminationSignalName = SIGSTOP, exitStatus = -2, message = Process stopped on dime]
+ProbeDescription:
+ serialized: syscall::malloc:entry
+ deserialized: syscall::malloc:entry
+ProbeDescription:
+ encoded: syscall::malloc:entry
+ decoded: syscall::malloc:entry
+PrintaRecord:
+ serialized: org.opensolaris.os.dtrace.PrintaRecord[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]], formattedStrings = {[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!]=cat, [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]=cat}, tuples = [[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]], output = Yes, this is the formatted printa() output]
+ deserialized: org.opensolaris.os.dtrace.PrintaRecord[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]], formattedStrings = {[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!]=cat, [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]=cat}, tuples = [[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]], output = Yes, this is the formatted printa() output]
+PrintaRecord:
+ encoded: org.opensolaris.os.dtrace.PrintaRecord[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]], formattedStrings = {[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!]=cat, [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]=cat}, tuples = [[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]], output = Yes, this is the formatted printa() output]
+ decoded: org.opensolaris.os.dtrace.PrintaRecord[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]], formattedStrings = {[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!]=cat, [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]=cat}, tuples = [[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]], output = Yes, this is the formatted printa() output]
+PrintfRecord:
+ serialized: long formatted string
+ deserialized: long formatted string
+PrintfRecord:
+ encoded: long formatted string
+ decoded: long formatted string
+ProbeData:
+ serialized: org.opensolaris.os.dtrace.ProbeData[epid = 7, cpu = 1, enabledProbeDescription = syscall::malloc:entry, flow = org.opensolaris.os.dtrace.Flow[kind = RETURN, depth = 3], records = [org.opensolaris.os.dtrace.PrintaRecord[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]], formattedStrings = {[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!]=cat, [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]=cat}, tuples = [[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]], output = Yes, this is the formatted printa() output], long formatted string,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, mod`func+0x4,
+ process ID: 123456
+ User Stack Frame 1
+ User Stack Frame 2
+ User Stack Frame 3
+, 1]]
+ deserialized: org.opensolaris.os.dtrace.ProbeData[epid = 7, cpu = 1, enabledProbeDescription = syscall::malloc:entry, flow = org.opensolaris.os.dtrace.Flow[kind = RETURN, depth = 3], records = [org.opensolaris.os.dtrace.PrintaRecord[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]], formattedStrings = {[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!]=cat, [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]=cat}, tuples = [[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]], output = Yes, this is the formatted printa() output], long formatted string,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, mod`func+0x4,
+ process ID: 123456
+ User Stack Frame 1
+ User Stack Frame 2
+ User Stack Frame 3
+, 1]]
+ProbeData:
+ encoded: org.opensolaris.os.dtrace.ProbeData[epid = 7, cpu = 1, enabledProbeDescription = syscall::malloc:entry, flow = org.opensolaris.os.dtrace.Flow[kind = RETURN, depth = 3], records = [org.opensolaris.os.dtrace.PrintaRecord[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]], formattedStrings = {[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!]=cat, [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]=cat}, tuples = [[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]], output = Yes, this is the formatted printa() output], long formatted string,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, mod`func+0x4,
+ process ID: 123456
+ User Stack Frame 1
+ User Stack Frame 2
+ User Stack Frame 3
+, 1]]
+ decoded: org.opensolaris.os.dtrace.ProbeData[epid = 7, cpu = 1, enabledProbeDescription = syscall::malloc:entry, flow = org.opensolaris.os.dtrace.Flow[kind = RETURN, depth = 3], records = [org.opensolaris.os.dtrace.PrintaRecord[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]]], formattedStrings = {[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!]=cat, [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]=cat}, tuples = [[
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+]], output = Yes, this is the formatted printa() output], long formatted string,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, mod`func+0x4,
+ process ID: 123456
+ User Stack Frame 1
+ User Stack Frame 2
+ User Stack Frame 3
+, 1]]
+Aggregate:
+ serialized: org.opensolaris.os.dtrace.Aggregate[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = times, id = 1, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, dog, mouse, mouse, 67, 7], value = 9]]]]
+ deserialized: org.opensolaris.os.dtrace.Aggregate[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = times, id = 1, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, dog, mouse, mouse, 67, 7], value = 9]]]]
+Aggregate:
+ encoded: org.opensolaris.os.dtrace.Aggregate[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = times, id = 1, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, dog, mouse, mouse, 67, 7], value = 9]]]]
+ decoded: org.opensolaris.os.dtrace.Aggregate[snaptime = 1234567890, aggregations = [org.opensolaris.os.dtrace.Aggregation[name = counts, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+, shebang!], value = class org.opensolaris.os.dtrace.LinearDistribution[base = 1, step = 10, buckets = [org.opensolaris.os.dtrace.Distribution$Bucket[min = 1, max = 10, frequency = 0], org.opensolaris.os.dtrace.Distribution$Bucket[min = 11, max = 20, frequency = 1], org.opensolaris.os.dtrace.Distribution$Bucket[min = 21, max = 30, frequency = 2], org.opensolaris.os.dtrace.Distribution$Bucket[min = 31, max = 40, frequency = 3], org.opensolaris.os.dtrace.Distribution$Bucket[min = 41, max = 50, frequency = 4], org.opensolaris.os.dtrace.Distribution$Bucket[min = 51, max = 60, frequency = 5], org.opensolaris.os.dtrace.Distribution$Bucket[min = 61, max = 70, frequency = 6], org.opensolaris.os.dtrace.Distribution$Bucket[min = 71, max = 80, frequency = 7], org.opensolaris.os.dtrace.Distribution$Bucket[min = 81, max = 90, frequency = 8], org.opensolaris.os.dtrace.Distribution$Bucket[min = 91, max = 100, frequency = 9], org.opensolaris.os.dtrace.Distribution$Bucket[min = 101, max = 9223372036854775807, frequency = 0]], total = 45.0]], org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, 9,
+ has
+ nine
+ lives
+,
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 1 2 3 ...
+], value = 7]], org.opensolaris.os.dtrace.Aggregation[name = times, id = 1, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [cat, dog, mouse, mouse, 67, 7], value = 9]]]]
+UserStackRecord:
+ serialized:
+ process ID: 123456
+ User Stack Frame 1
+ User Stack Frame 2
+ User Stack Frame 3
+
+ deserialized:
+ process ID: 123456
+ User Stack Frame 1
+ User Stack Frame 2
+ User Stack Frame 3
+
+UserStackRecord:
+ encoded:
+ process ID: 123456
+ User Stack Frame 1
+ User Stack Frame 2
+ User Stack Frame 3
+
+ decoded:
+ process ID: 123456
+ User Stack Frame 1
+ User Stack Frame 2
+ User Stack Frame 3
+
+AvgValue:
+ serialized: 5
+ deserialized: 5
+AvgValue:
+ encoded: 5
+ decoded: 5
+CountValue:
+ serialized: 9
+ deserialized: 9
+CountValue:
+ encoded: 9
+ decoded: 9
+SumValue:
+ serialized: 25
+ deserialized: 25
+SumValue:
+ encoded: 25
+ decoded: 25
+MinValue:
+ serialized: 101
+ deserialized: 101
+MinValue:
+ encoded: 101
+ decoded: 101
+MaxValue:
+ serialized: 101
+ deserialized: 101
+MaxValue:
+ encoded: 101
+ decoded: 101
+Error:
+ serialized: org.opensolaris.os.dtrace.Error[probeDescription = syscall::malloc:entry, epid = 8, cpu = 3, action = 1, offset = 20, fault = DTRACEFLT_BADALIGN, address = -1, defaultMessage = error on enabled probe ID 8 (ID 256: syscall::malloc:entry): Bad alignment (0x33ef) in action #1 at DIF offset 20]
+ deserialized: org.opensolaris.os.dtrace.Error[probeDescription = syscall::malloc:entry, epid = 8, cpu = 3, action = 1, offset = 20, fault = DTRACEFLT_BADALIGN, address = -1, defaultMessage = error on enabled probe ID 8 (ID 256: syscall::malloc:entry): Bad alignment (0x33ef) in action #1 at DIF offset 20]
+Error:
+ encoded: org.opensolaris.os.dtrace.Error[probeDescription = syscall::malloc:entry, epid = 8, cpu = 3, action = 1, offset = 20, fault = DTRACEFLT_BADALIGN, address = -1, defaultMessage = error on enabled probe ID 8 (ID 256: syscall::malloc:entry): Bad alignment (0x33ef) in action #1 at DIF offset 20]
+ decoded: org.opensolaris.os.dtrace.Error[probeDescription = syscall::malloc:entry, epid = 8, cpu = 3, action = 1, offset = 20, fault = DTRACEFLT_BADALIGN, address = -1, defaultMessage = error on enabled probe ID 8 (ID 256: syscall::malloc:entry): Bad alignment (0x33ef) in action #1 at DIF offset 20]
+Drop:
+ serialized: org.opensolaris.os.dtrace.Drop[cpu = 2, kind = Speculation (busy), count = 72, total = 1041, defaultMessage = Guess we dropped stuff all over the place.]
+ deserialized: org.opensolaris.os.dtrace.Drop[cpu = 2, kind = Speculation (busy), count = 72, total = 1041, defaultMessage = Guess we dropped stuff all over the place.]
+Drop:
+ encoded: org.opensolaris.os.dtrace.Drop[cpu = 2, kind = Speculation (busy), count = 72, total = 1041, defaultMessage = Guess we dropped stuff all over the place.]
+ decoded: org.opensolaris.os.dtrace.Drop[cpu = 2, kind = Speculation (busy), count = 72, total = 1041, defaultMessage = Guess we dropped stuff all over the place.]
+InterfaceAttributes:
+ serialized: Unstable / Evolving / ISA
+ deserialized: Unstable / Evolving / ISA
+InterfaceAttributes:
+ encoded: Unstable / Evolving / ISA
+ decoded: Unstable / Evolving / ISA
+ProgramInfo:
+ serialized: org.opensolaris.os.dtrace.ProgramInfo[minimumProbeAttributes = Unstable / Evolving / ISA, minimumStatementAttributes = Unstable / Evolving / ISA, matchingProbeCount = 256]
+ deserialized: org.opensolaris.os.dtrace.ProgramInfo[minimumProbeAttributes = Unstable / Evolving / ISA, minimumStatementAttributes = Unstable / Evolving / ISA, matchingProbeCount = 256]
+ProgramInfo:
+ encoded: org.opensolaris.os.dtrace.ProgramInfo[minimumProbeAttributes = Unstable / Evolving / ISA, minimumStatementAttributes = Unstable / Evolving / ISA, matchingProbeCount = 256]
+ decoded: org.opensolaris.os.dtrace.ProgramInfo[minimumProbeAttributes = Unstable / Evolving / ISA, minimumStatementAttributes = Unstable / Evolving / ISA, matchingProbeCount = 256]
+ProbeInfo:
+ serialized: org.opensolaris.os.dtrace.ProbeInfo[probeAttributes = Unstable / Evolving / ISA, argumentAttributes = Unstable / Evolving / ISA]
+ deserialized: org.opensolaris.os.dtrace.ProbeInfo[probeAttributes = Unstable / Evolving / ISA, argumentAttributes = Unstable / Evolving / ISA]
+ProbeInfo:
+ encoded: org.opensolaris.os.dtrace.ProbeInfo[probeAttributes = Unstable / Evolving / ISA, argumentAttributes = Unstable / Evolving / ISA]
+ decoded: org.opensolaris.os.dtrace.ProbeInfo[probeAttributes = Unstable / Evolving / ISA, argumentAttributes = Unstable / Evolving / ISA]
+Probe:
+ serialized: org.opensolaris.os.dtrace.Probe[description = syscall::malloc:entry, info = org.opensolaris.os.dtrace.ProbeInfo[probeAttributes = Unstable / Evolving / ISA, argumentAttributes = Unstable / Evolving / ISA]]
+ deserialized: org.opensolaris.os.dtrace.Probe[description = syscall::malloc:entry, info = org.opensolaris.os.dtrace.ProbeInfo[probeAttributes = Unstable / Evolving / ISA, argumentAttributes = Unstable / Evolving / ISA]]
+Probe:
+ encoded: org.opensolaris.os.dtrace.Probe[description = syscall::malloc:entry, info = org.opensolaris.os.dtrace.ProbeInfo[probeAttributes = Unstable / Evolving / ISA, argumentAttributes = Unstable / Evolving / ISA]]
+ decoded: org.opensolaris.os.dtrace.Probe[description = syscall::malloc:entry, info = org.opensolaris.os.dtrace.ProbeInfo[probeAttributes = Unstable / Evolving / ISA, argumentAttributes = Unstable / Evolving / ISA]]
+Flow:
+ serialized: org.opensolaris.os.dtrace.Flow[kind = RETURN, depth = 3]
+ deserialized: org.opensolaris.os.dtrace.Flow[kind = RETURN, depth = 3]
+Flow:
+ encoded: org.opensolaris.os.dtrace.Flow[kind = RETURN, depth = 3]
+ decoded: org.opensolaris.os.dtrace.Flow[kind = RETURN, depth = 3]
+KernelSymbolRecord:
+ serialized: mod`func+0x4
+ deserialized: mod`func+0x4
+KernelSymbolRecord:
+ encoded: mod`func+0x4
+ decoded: mod`func+0x4
+UserSymbolRecord:
+ serialized: mod`func+0x4
+ deserialized: mod`func+0x4
+UserSymbolRecord:
+ encoded: mod`func+0x4
+ decoded: mod`func+0x4
+UserSymbolRecord$Value:
+ serialized: org.opensolaris.os.dtrace.UserSymbolRecord$Value[processID = 7, address = -1]
+ deserialized: org.opensolaris.os.dtrace.UserSymbolRecord$Value[processID = 7, address = -1]
+UserSymbolRecord$Value:
+ encoded: org.opensolaris.os.dtrace.UserSymbolRecord$Value[processID = 7, address = -1]
+ decoded: org.opensolaris.os.dtrace.UserSymbolRecord$Value[processID = 7, address = -1]
+Program:
+ serialized: org.opensolaris.os.dtrace.Program[contents = syscall:::entry { @[execname] = count(); }, info = null]
+ deserialized: org.opensolaris.os.dtrace.Program[contents = syscall:::entry { @[execname] = count(); }, info = null]
+Program$File:
+ serialized: org.opensolaris.os.dtrace.Program$File[super = org.opensolaris.os.dtrace.Program[contents = syscall:::entry { @[execname] = count(); }, info = null], file = TestBean.out]
+ deserialized: org.opensolaris.os.dtrace.Program$File[super = org.opensolaris.os.dtrace.Program[contents = syscall:::entry { @[execname] = count(); }, info = null], file = TestBean.out]
+StddevValue:
+ serialized: 37
+ deserialized: 37
+StddevValue:
+ encoded: 37
+ decoded: 37
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Close.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Close.ksh
new file mode 100644
index 000000000000..299755c6638e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Close.ksh
@@ -0,0 +1,38 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Fixed bug 6419880 close() hangs running consumer.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestClose
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Close.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Close.ksh.out
new file mode 100644
index 000000000000..628d78702724
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Close.ksh.out
@@ -0,0 +1 @@
+Successful
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Drop.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Drop.ksh
new file mode 100644
index 000000000000..a03de9531ebb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Drop.ksh
@@ -0,0 +1,38 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Fixed bug 6521523 aggregation drops can hang the Java DTrace API.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestDrop 3
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Drop.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Drop.ksh.out
new file mode 100644
index 000000000000..266c4d460880
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Drop.ksh.out
@@ -0,0 +1 @@
+Lock released
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Enable.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Enable.ksh
new file mode 100644
index 000000000000..df1c11f0c2a9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Enable.ksh
@@ -0,0 +1,40 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Consumer enable() correctly handles multiple programs,
+# recognizing programs that have already been enabled or that were
+# compiled by another consumer.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestEnable
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Enable.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Enable.ksh.out
new file mode 100644
index 000000000000..a13fb7090003
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.Enable.ksh.out
@@ -0,0 +1,6 @@
+java.lang.IllegalStateException: Not all compiled probes are enabled. Compiled description dtrace:::END not enabled.
+java.lang.IllegalStateException: program already enabled
+java.lang.IllegalStateException: program already enabled
+java.lang.IllegalStateException: Not all compiled probes are enabled. Compiled description syscall:::return not enabled.
+java.lang.IllegalStateException: program already enabled
+java.lang.IllegalArgumentException: program not compiled by this consumer
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.c
new file mode 100644
index 000000000000..0e6291f60912
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.c
@@ -0,0 +1,51 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+
+typedef void f(int x);
+
+static void
+f1(int i)
+{
+ printf("%d\n", i);
+}
+
+static void
+f2(f func, int i)
+{
+ func(i);
+}
+
+int
+main()
+{
+ f2(f1, 3);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.ksh
new file mode 100644
index 000000000000..e1ffbdfa479f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.ksh
@@ -0,0 +1,39 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Fixed bug 6413280 lookupKernelFunction() and
+# lookupUserFunction() truncate last character.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestFunctionLookup ./tst.FunctionLookup.exe
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.ksh.out
new file mode 100644
index 000000000000..d42e9b59b6e1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.FunctionLookup.ksh.out
@@ -0,0 +1,3 @@
+genunix`cv_wakeup
+3
+tst.FunctionLookup.exe`f1
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.GetAggregate.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.GetAggregate.ksh
new file mode 100644
index 000000000000..2fdd5a9eac44
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.GetAggregate.ksh
@@ -0,0 +1,36 @@
+#!/bin/ksh -p
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+############################################################################
+# ASSERTION:
+# getAggregate() can explicitly specify the anonymous aggregation
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestGetAggregate
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MaxConsumers.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MaxConsumers.ksh
new file mode 100644
index 000000000000..992fcb5e8b09
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MaxConsumers.ksh
@@ -0,0 +1,47 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Fixed bug 6506495 -DJAVA_DTRACE_MAX_CONSUMERS=N for any N < 8 is
+# treated as if it were 8.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestMaxConsumers
+java -DJAVA_DTRACE_MAX_CONSUMERS=-1 -cp test.jar TestMaxConsumers
+java -DJAVA_DTRACE_MAX_CONSUMERS=0 -cp test.jar TestMaxConsumers
+java -DJAVA_DTRACE_MAX_CONSUMERS=1 -cp test.jar TestMaxConsumers
+java -DJAVA_DTRACE_MAX_CONSUMERS=2 -cp test.jar TestMaxConsumers
+java -DJAVA_DTRACE_MAX_CONSUMERS=7 -cp test.jar TestMaxConsumers
+java -DJAVA_DTRACE_MAX_CONSUMERS=8 -cp test.jar TestMaxConsumers
+java -DJAVA_DTRACE_MAX_CONSUMERS=9 -cp test.jar TestMaxConsumers
+java -DJAVA_DTRACE_MAX_CONSUMERS=19 -cp test.jar TestMaxConsumers
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MaxConsumers.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MaxConsumers.ksh.out
new file mode 100644
index 000000000000..f68fc4ea5f7e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MaxConsumers.ksh.out
@@ -0,0 +1,17 @@
+Success
+JAVA_DTRACE_MAX_CONSUMERS=-1
+Success
+JAVA_DTRACE_MAX_CONSUMERS=0
+Success
+JAVA_DTRACE_MAX_CONSUMERS=1
+Success
+JAVA_DTRACE_MAX_CONSUMERS=2
+Success
+JAVA_DTRACE_MAX_CONSUMERS=7
+Success
+JAVA_DTRACE_MAX_CONSUMERS=8
+Success
+JAVA_DTRACE_MAX_CONSUMERS=9
+Success
+JAVA_DTRACE_MAX_CONSUMERS=19
+Success
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MultiAggPrinta.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MultiAggPrinta.ksh
new file mode 100644
index 000000000000..6bb864a61eae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MultiAggPrinta.ksh
@@ -0,0 +1,38 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Regression for multi-aggregation printa() corner cases.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestMultiAggPrinta tst.printa.d
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MultiAggPrinta.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MultiAggPrinta.ksh.out
new file mode 100644
index 000000000000..8b8fd6ef5040
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.MultiAggPrinta.ksh.out
@@ -0,0 +1,78 @@
+org.opensolaris.os.dtrace.ProbeData[epid = 1, enabledProbeDescription = dtrace:::BEGIN, flow = null, records = [org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = , id = 1, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [], value = 1]]], formattedStrings = {[]=
+ 1
+}, tuples = [[]], output =
+ 1
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = , id = 1, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [], value = 1]]], formattedStrings = {[]=count: 1
+}, tuples = [[]], output = count: 1
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [], formattedStrings = {[]= }, tuples = [[]], output = ], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = a, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 1], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 3]]], formattedStrings = {[1, 3]=
+ 1 3 3
+, [1, 2]= 1 2 1
+}, tuples = [[1, 3], [1, 2]], output =
+ 1 3 3
+ 1 2 1
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = a, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 1], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 3], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 0]], org.opensolaris.os.dtrace.Aggregation[name = b, id = 3, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 2], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 0], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 4]]], formattedStrings = {[2, 3]=
+ 2 3 0 4
+, [1, 3]= 1 3 3 0
+, [1, 2]= 1 2 1 2
+}, tuples = [[2, 3], [1, 2], [1, 3]], output =
+ 2 3 0 4
+ 1 2 1 2
+ 1 3 3 0
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = c, id = 4, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [], value = 3]], org.opensolaris.os.dtrace.Aggregation[name = d, id = 5, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [], value = 4]]], formattedStrings = {[]=3 4
+}, tuples = [[]], output = 3 4
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = c, id = 4, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [], value = 3]], org.opensolaris.os.dtrace.Aggregation[name = d, id = 5, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [], value = 4]]], formattedStrings = {[]=3 4
+}, tuples = [[]], output = 3 4
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = c, id = 4, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [], value = 3]]], formattedStrings = {[]=3
+}, tuples = [[]], output = 3
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = a, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 1], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 3], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 0]], org.opensolaris.os.dtrace.Aggregation[name = b, id = 3, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 2], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 0], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 4]]], formattedStrings = {[2, 3]=[2, 3] 0 4
+, [1, 3]=[1, 3] 3 0
+, [1, 2]=[1, 2] 1 2
+}, tuples = [[2, 3], [1, 2], [1, 3]], output = [2, 3] 0 4
+[1, 2] 1 2
+[1, 3] 3 0
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = a, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 1], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 3], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 0]], org.opensolaris.os.dtrace.Aggregation[name = b, id = 3, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 2], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 0], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 4]]], formattedStrings = {[2, 3]=[2, 3] 0 4
+, [1, 3]=[1, 3] 3 0
+, [1, 2]=[1, 2] 1 2
+}, tuples = [[2, 3], [1, 3], [1, 2]], output = [2, 3] 0 4
+[1, 3] 3 0
+[1, 2] 1 2
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = a, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 1], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 3], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 0]], org.opensolaris.os.dtrace.Aggregation[name = b, id = 3, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 2], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 0], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 4]]], formattedStrings = {[2, 3]=[2, 3] 0 4
+, [1, 3]=[1, 3] 3 0
+, [1, 2]=[1, 2] 1 2
+}, tuples = [[2, 3], [1, 3], [1, 2]], output = [2, 3] 0 4
+[1, 3] 3 0
+[1, 2] 1 2
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = a, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 1], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 3], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 0]], org.opensolaris.os.dtrace.Aggregation[name = b, id = 3, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 2], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 0], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 4]]], formattedStrings = {[2, 3]=0 4 [2, 3]
+, [1, 3]=3 0 [1, 3]
+, [1, 2]=1 2 [1, 2]
+}, tuples = [[2, 3], [1, 3], [1, 2]], output = 0 4 [2, 3]
+3 0 [1, 3]
+1 2 [1, 2]
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [], formattedStrings = {[2, 3]=[2, 3]
+, [1, 3]=[1, 3]
+, [1, 2]=[1, 2]
+}, tuples = [[2, 3], [1, 3], [1, 2]], output = [2, 3]
+[1, 3]
+[1, 2]
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [], formattedStrings = {}, tuples = [], output = [2]
+[1]
+[1]
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [], formattedStrings = {}, tuples = [], output = [2] 0 4
+[1] 3 0
+[1] 1 2
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [], formattedStrings = {}, tuples = [], output = 0 4
+3 0
+1 2
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [], formattedStrings = {}, tuples = [], output = 0 4 4
+3 0 0
+1 2 2
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [], formattedStrings = {}, tuples = [], output = [2] 0 4 4
+[1] 3 0 0
+[1] 1 2 2
+], org.opensolaris.os.dtrace.PrintaRecord[aggregations = [org.opensolaris.os.dtrace.Aggregation[name = a, id = 2, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 1], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 3], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 0]], org.opensolaris.os.dtrace.Aggregation[name = b, id = 3, records = [org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 2], value = 2], org.opensolaris.os.dtrace.AggregationRecord[tuple = [1, 3], value = 0], org.opensolaris.os.dtrace.AggregationRecord[tuple = [2, 3], value = 4]]], formattedStrings = {[2, 3]=[2, 3] 0 4 4
+, [1, 3]=[1, 3] 3 0 0
+, [1, 2]=[1, 2] 1 2 2
+}, tuples = [[2, 3], [1, 3], [1, 2]], output = [2, 3] 0 4 4
+[1, 3] 3 0 0
+[1, 2] 1 2 2
+], 0]
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.c
new file mode 100644
index 000000000000..0833912ad94c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.c
@@ -0,0 +1,93 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+typedef void f(char *);
+
+static void
+f_a(char *a)
+{
+}
+
+static void
+f_b(char *a)
+{
+}
+
+static void
+f_c(char *a)
+{
+}
+
+static void
+f_d(char *a)
+{
+}
+
+static void
+f_e(char *a)
+{
+}
+
+static void
+fN(f func, char *a, int i)
+{
+ func(a);
+}
+
+static void
+fN2(f func, char *a, int i)
+{
+ func(a);
+}
+
+int
+main()
+{
+ /*
+ * Avoid length of 1, 2, 4, or 8 bytes so DTrace will treat the data as
+ * a byte array.
+ */
+ char a[] = {(char)-7, (char)201, (char)0, (char)0, (char)28, (char)1};
+ char b[] = {(char)84, (char)69, (char)0, (char)0, (char)28, (char)0};
+ char c[] = {(char)84, (char)69, (char)0, (char)0, (char)28, (char)1};
+ char d[] = {(char)-7, (char)201, (char)0, (char)0, (char)29, (char)0};
+ char e[] = {(char)84, (char)69, (char)0, (char)0, (char)28, (char)0};
+
+ fN(f_a, a, 1);
+ fN(f_b, b, 0);
+ fN(f_d, d, 102);
+ fN2(f_e, e, -2);
+ fN(f_c, c, 0);
+ fN(f_a, a, -1);
+ fN(f_d, d, 101);
+ fN(f_e, e, -2);
+ fN(f_e, e, 2);
+ fN2(f_e, e, 2);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.ksh
new file mode 100644
index 000000000000..97f49454e9ae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.ksh
@@ -0,0 +1,38 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# ProbeData instances sort as expected with multiple enabled probe
+# IDs and multiple records including byte array (sorted as
+# unsigned bytes), stand-alone ufunc() action, and signed integer.
+#
+############################################################################
+
+java -cp test.jar TestProbeData ./tst.ProbeData.exe
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.ksh.out
new file mode 100644
index 000000000000..6789514f6897
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeData.ksh.out
@@ -0,0 +1,50 @@
+[probe 1 pid$target:tst.ProbeData.exe:fN:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 54 45 0 0 1c 0 TE....
+, tst.ProbeData.exe`f_b , 0]]
+
+[probe 1 pid$target:tst.ProbeData.exe:fN:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 54 45 0 0 1c 0 TE....
+, tst.ProbeData.exe`f_e , -2]]
+
+[probe 2 pid$target:tst.ProbeData.exe:fN2:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 54 45 0 0 1c 0 TE....
+, tst.ProbeData.exe`f_e , -2]]
+
+[probe 1 pid$target:tst.ProbeData.exe:fN:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 54 45 0 0 1c 0 TE....
+, tst.ProbeData.exe`f_e , 2]]
+
+[probe 2 pid$target:tst.ProbeData.exe:fN2:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 54 45 0 0 1c 0 TE....
+, tst.ProbeData.exe`f_e , 2]]
+
+[probe 1 pid$target:tst.ProbeData.exe:fN:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 54 45 0 0 1c 1 TE....
+, tst.ProbeData.exe`f_c , 0]]
+
+[probe 1 pid$target:tst.ProbeData.exe:fN:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: f9 c9 0 0 1c 1 ......
+, tst.ProbeData.exe`f_a , -1]]
+
+[probe 1 pid$target:tst.ProbeData.exe:fN:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: f9 c9 0 0 1c 1 ......
+, tst.ProbeData.exe`f_a , 1]]
+
+[probe 1 pid$target:tst.ProbeData.exe:fN:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: f9 c9 0 0 1d 0 ......
+, tst.ProbeData.exe`f_d , 101]]
+
+[probe 1 pid$target:tst.ProbeData.exe:fN:entry [
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: f9 c9 0 0 1d 0 ......
+, tst.ProbeData.exe`f_d , 102]]
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeDescription.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeDescription.ksh
new file mode 100644
index 000000000000..bee1cca6a371
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeDescription.ksh
@@ -0,0 +1,45 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# ProbeDescription constructors function as expected.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestProbeDescription syscall:::entry
+java -cp test.jar TestProbeDescription BEGIN
+java -cp test.jar TestProbeDescription isdigit entry
+java -cp test.jar TestProbeDescription genunix isdigit entry
+java -cp test.jar TestProbeDescription fbt genunix isdigit entry
+java -cp test.jar TestProbeDescription fbt:genunix:isdigit:entry
+java -cp test.jar TestProbeDescription syscall::entry
+java -cp test.jar TestProbeDescription syscall:entry
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeDescription.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeDescription.ksh.out
new file mode 100644
index 000000000000..326018a5e908
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.ProbeDescription.ksh.out
@@ -0,0 +1,8 @@
+syscall:::entry
+:::BEGIN
+::isdigit:entry
+:genunix:isdigit:entry
+fbt:genunix:isdigit:entry
+fbt:genunix:isdigit:entry
+:syscall::entry
+::syscall:entry
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StateMachine.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StateMachine.ksh
new file mode 100644
index 000000000000..638ce7ace8fa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StateMachine.ksh
@@ -0,0 +1,40 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Consumer state machine prevents illegal calls, allows legal
+# ones; consumer behaves predictably when methods called out of
+# order.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestStateMachine
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StateMachine.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StateMachine.ksh.out
new file mode 100644
index 000000000000..5ddb528f7995
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StateMachine.ksh.out
@@ -0,0 +1,70 @@
+before open
+open: false
+enabled: false
+closed: false
+java.lang.IllegalStateException: consumer not open
+java.lang.IllegalStateException: consumer not open
+java.lang.IllegalStateException: consumer not open
+java.lang.IllegalStateException: consumer not open
+java.lang.IllegalStateException: consumer not open
+java.lang.IllegalStateException: consumer not open
+java.lang.IllegalStateException: consumer not open
+java.lang.IllegalStateException: consumer not open
+java.lang.IllegalStateException: consumer not open
+before compile
+open: true
+enabled: false
+closed: false
+java.lang.IllegalStateException: consumer already open
+java.lang.IllegalStateException: no compiled program
+before enable
+open: true
+enabled: false
+closed: false
+java.lang.IllegalStateException: Not all compiled probes are enabled. Compiled description syscall:::entry { @[execname] = count(); } tick-101ms { printa(@); } not enabled.
+before go
+open: true
+enabled: true
+closed: false
+java.lang.IllegalStateException: go() not called
+java.lang.IllegalStateException: go() not called
+java.lang.IllegalStateException: go() not called
+java.lang.IllegalStateException: go() not called
+before go, running: false
+consumerStarted, running: true
+after go
+open: true
+enabled: false
+closed: false
+java.lang.IllegalStateException: go() already called
+java.lang.IllegalStateException: go() already called
+java.lang.IllegalStateException: go() already called
+java.lang.IllegalStateException: go() already called
+java.lang.IllegalStateException: go() already called
+java.lang.IllegalStateException: go() already called
+consumerStopped, running: false
+after stop, running: false
+after stop
+open: true
+enabled: false
+closed: false
+java.lang.IllegalStateException: consumer already stopped
+after close
+open: false
+enabled: false
+closed: true
+java.lang.IllegalStateException: cannot reopen a closed consumer
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
+java.lang.IllegalStateException: consumer closed
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StopLock.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StopLock.ksh
new file mode 100644
index 000000000000..4637a7adc70d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StopLock.ksh
@@ -0,0 +1,39 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Fixed bug 6399888 stop() hangs if ConsumerListener calls
+# synchronized Consumer method.
+#
+# SECTION: Java API
+#
+############################################################################
+
+java -cp test.jar TestStopLock
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StopLock.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StopLock.ksh.out
new file mode 100644
index 000000000000..628d78702724
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.StopLock.ksh.out
@@ -0,0 +1 @@
+Successful
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.printa.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.printa.d
new file mode 100644
index 000000000000..574a9eab3eba
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.printa.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * printa() test with/without tuple, with multiple aggregations and
+ * mismatched format strings, and sorting options.
+ *
+ * SECTION: Aggregations/Aggregations; Output Formatting, printa()
+ *
+ * NOTES: This test attempts to cover all multi-agg printa() corner cases.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @ = count();
+ @a[1, 2] = sum(1);
+ @b[1, 2] = sum(2);
+ @a[1, 3] = sum(3);
+ @b[2, 3] = sum(4);
+ @c = sum(3);
+ @d = sum(4);
+ setopt("aggsortpos", "1");
+ setopt("aggsortrev");
+ printa(@);
+ printa("count: %@d\n", @);
+ printa(" ", @);
+ printa(@a);
+ printa(@a, @b);
+ printa("%@d %@d\n", @c, @d);
+ printa("%@d %@d\n", @c, @d);
+ printa("%@d\n", @c, @d);
+
+ printa("[%d, %d] %@d %@d\n", @a, @b);
+ setopt("aggsortkey");
+ printa("[%d, %d] %@d %@d\n", @a, @b);
+ setopt("aggsortpos", "0");
+ setopt("aggsortkeypos", "1");
+ printa("[%d, %d] %@d %@d\n", @a, @b);
+
+ printa("%@d %@d [%d, %d]\n", @a, @b);
+ printa("[%d, %d]\n", @a, @b);
+ printa("[%d]\n", @a, @b);
+ printa("[%d] %@d %@d\n", @a, @b);
+ printa("%@d %@d\n", @a, @b);
+ printa("%@d %@d %@d\n", @a, @b);
+ printa("[%d] %@d %@d %@d\n", @a, @b);
+ printa("[%d, %d] %@d %@d %@d\n", @a, @b);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.printa.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.printa.d.out
new file mode 100644
index 000000000000..10b90b3c9b61
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/java_api/tst.printa.d.out
@@ -0,0 +1,47 @@
+
+ 1
+count: 1
+
+ 1 3 3
+ 1 2 1
+
+ 2 3 0 4
+ 1 2 1 2
+ 1 3 3 0
+3 4
+3 4
+3
+[2, 3] 0 4
+[1, 2] 1 2
+[1, 3] 3 0
+[2, 3] 0 4
+[1, 3] 3 0
+[1, 2] 1 2
+[2, 3] 0 4
+[1, 3] 3 0
+[1, 2] 1 2
+0 4 [2, 3]
+3 0 [1, 3]
+1 2 [1, 2]
+[2, 3]
+[1, 3]
+[1, 2]
+[2]
+[1]
+[1]
+[2] 0 4
+[1] 3 0
+[1] 1 2
+0 4
+3 0
+1 2
+0 4 4
+3 0 0
+1 2 2
+[2] 0 4 4
+[1] 3 0 0
+[1] 1 2 2
+[2, 3] 0 4 4
+[1, 3] 3 0 0
+[1, 2] 1 2 2
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d
new file mode 100644
index 000000000000..4600811d95b9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d
@@ -0,0 +1,179 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * General functional tests of JSON parser for json().
+ */
+
+#pragma D option quiet
+#pragma D option strsize=1k
+
+#define TST(name) \
+ printf("\ntst |%s|\n", name)
+#define IN2(vala, valb) \
+ in = strjoin(vala, valb); \
+ printf("in |%s|\n", in)
+#define IN(val) \
+ in = val; \
+ printf("in |%s|\n", in)
+#define SEL(ss) \
+ out = json(in, ss); \
+ printf("sel |%s|\nout |%s|\n", ss, \
+ out != NULL ? out : "<NULL>")
+
+BEGIN
+{
+ TST("empty array");
+ IN("[]");
+ SEL("0");
+
+ TST("one-element array: integer");
+ IN("[1]");
+ SEL("0");
+ SEL("1");
+ SEL("100");
+ SEL("-1");
+
+ TST("one-element array: hex integer (not in spec, not supported)");
+ IN("[0x1000]");
+ SEL("0");
+
+ TST("one-element array: float");
+ IN("[1.5001]");
+ SEL("0");
+
+ TST("one-element array: float + exponent");
+ IN("[16.3e10]");
+ SEL("0");
+
+ TST("one-element array: integer + whitespace");
+ IN("[ \t 5\t]");
+ SEL("0");
+
+ TST("one-element array: integer + exponent + whitespace");
+ IN("[ \t \t 16E10 \t ]");
+ SEL("0");
+
+ TST("one-element array: string");
+ IN("[\"alpha\"]");
+ SEL("0");
+
+ TST("alternative first-element indexing");
+ IN("[1,5,10,15,20]");
+ SEL("[0]");
+ SEL("[3]");
+ SEL("[4]");
+ SEL("[5]");
+
+ TST("one-element array: object");
+ IN("[ { \"first\": true, \"second\": false }]");
+ SEL("0.first");
+ SEL("0.second");
+ SEL("0.third");
+
+ TST("many-element array: integers");
+ IN("[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377]");
+ SEL("10"); /* F(10) = 55 */
+ SEL("14"); /* F(14) = 377 */
+ SEL("19");
+
+ TST("many-element array: multiple types");
+ IN2("[\"string\",32,true,{\"a\":9,\"b\":false},100.3e10,false,200.5,",
+ "{\"key\":\"val\"},null]");
+ SEL("0");
+ SEL("0.notobject");
+ SEL("1");
+ SEL("2");
+ SEL("3");
+ SEL("3.a");
+ SEL("3.b");
+ SEL("3.c");
+ SEL("4");
+ SEL("5");
+ SEL("6");
+ SEL("7");
+ SEL("7.key");
+ SEL("7.key.notobject");
+ SEL("7.nonexist");
+ SEL("8");
+ SEL("9");
+
+ TST("many-element array: multiple types + whitespace");
+ IN2("\n[\t\"string\" ,\t32 , true\t,\t {\"a\": 9,\t\"b\": false},\t\t",
+ "100.3e10, false, 200.5,{\"key\" \t:\n \"val\"},\t\t null ]\t\t");
+ SEL("0");
+ SEL("0.notobject");
+ SEL("1");
+ SEL("2");
+ SEL("3");
+ SEL("3.a");
+ SEL("3.b");
+ SEL("3.c");
+ SEL("4");
+ SEL("5");
+ SEL("6");
+ SEL("7");
+ SEL("7.key");
+ SEL("7.key.notobject");
+ SEL("7.nonexist");
+ SEL("8");
+ SEL("9");
+
+ TST("two-element array: various string escape codes");
+ IN2("[\"abcd \\\" \\\\ \\/ \\b \\f \\n \\r \\t \\u0000 \\uf00F \", ",
+ "\"final\"]");
+ SEL("0");
+ SEL("1");
+
+ TST("three-element array: broken escape code");
+ IN("[\"fine here\", \"dodgey \\u00AZ\", \"wont get here\"]");
+ SEL("0");
+ SEL("1");
+ SEL("2");
+
+ TST("nested objects");
+ IN2("{ \"top\": { \"mid\" : { \"legs\": \"feet\" }, \"number\": 9, ",
+ "\"array\":[0,1,{\"a\":true,\"bb\":[1,2,false,{\"x\":\"yz\"}]}]}}");
+ SEL("top");
+ SEL("fargo");
+ SEL("top.mid");
+ SEL("top.centre");
+ SEL("top.mid.legs");
+ SEL("top.mid.number");
+ SEL("top.mid.array");
+ SEL("top.number");
+ SEL("top.array");
+ SEL("top.array[0]");
+ SEL("top.array[1]");
+ SEL("top.array[2]");
+ SEL("top.array[2].a");
+ SEL("top.array[2].b");
+ SEL("top.array[2].bb");
+ SEL("top.array[2].bb[0]");
+ SEL("top.array[2].bb[1]");
+ SEL("top.array[2].bb[2]");
+ SEL("top.array[2].bb[3]");
+ SEL("top.array[2].bb[3].x");
+ SEL("top.array[2].bb[3].x.nofurther");
+ SEL("top.array[2].bb[4]");
+ SEL("top.array[3]");
+
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d.out
new file mode 100644
index 000000000000..a857ab91d831
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d.out
@@ -0,0 +1,218 @@
+
+tst |empty array|
+in |[]|
+sel |0|
+out |<NULL>|
+
+tst |one-element array: integer|
+in |[1]|
+sel |0|
+out |1|
+sel |1|
+out |<NULL>|
+sel |100|
+out |<NULL>|
+sel |-1|
+out |<NULL>|
+
+tst |one-element array: hex integer (not in spec, not supported)|
+in |[0x1000]|
+sel |0|
+out |<NULL>|
+
+tst |one-element array: float|
+in |[1.5001]|
+sel |0|
+out |1.5001|
+
+tst |one-element array: float + exponent|
+in |[16.3e10]|
+sel |0|
+out |16.3e10|
+
+tst |one-element array: integer + whitespace|
+in |[ 5 ]|
+sel |0|
+out |5|
+
+tst |one-element array: integer + exponent + whitespace|
+in |[ 16E10 ]|
+sel |0|
+out |16E10|
+
+tst |one-element array: string|
+in |["alpha"]|
+sel |0|
+out |alpha|
+
+tst |alternative first-element indexing|
+in |[1,5,10,15,20]|
+sel |[0]|
+out |1|
+sel |[3]|
+out |15|
+sel |[4]|
+out |20|
+sel |[5]|
+out |<NULL>|
+
+tst |one-element array: object|
+in |[ { "first": true, "second": false }]|
+sel |0.first|
+out |true|
+sel |0.second|
+out |false|
+sel |0.third|
+out |<NULL>|
+
+tst |many-element array: integers|
+in |[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377]|
+sel |10|
+out |55|
+sel |14|
+out |377|
+sel |19|
+out |<NULL>|
+
+tst |many-element array: multiple types|
+in |["string",32,true,{"a":9,"b":false},100.3e10,false,200.5,{"key":"val"},null]|
+sel |0|
+out |string|
+sel |0.notobject|
+out |<NULL>|
+sel |1|
+out |32|
+sel |2|
+out |true|
+sel |3|
+out |{"a":9,"b":false}|
+sel |3.a|
+out |9|
+sel |3.b|
+out |false|
+sel |3.c|
+out |<NULL>|
+sel |4|
+out |100.3e10|
+sel |5|
+out |false|
+sel |6|
+out |200.5|
+sel |7|
+out |{"key":"val"}|
+sel |7.key|
+out |val|
+sel |7.key.notobject|
+out |<NULL>|
+sel |7.nonexist|
+out |<NULL>|
+sel |8|
+out |null|
+sel |9|
+out |<NULL>|
+
+tst |many-element array: multiple types + whitespace|
+in |
+[ "string" , 32 , true , {"a": 9, "b": false}, 100.3e10, false, 200.5,{"key" :
+ "val"}, null ] |
+sel |0|
+out |string|
+sel |0.notobject|
+out |<NULL>|
+sel |1|
+out |32|
+sel |2|
+out |true|
+sel |3|
+out |{"a": 9, "b": false}|
+sel |3.a|
+out |9|
+sel |3.b|
+out |false|
+sel |3.c|
+out |<NULL>|
+sel |4|
+out |100.3e10|
+sel |5|
+out |false|
+sel |6|
+out |200.5|
+sel |7|
+out |{"key" :
+ "val"}|
+sel |7.key|
+out |val|
+sel |7.key.notobject|
+out |<NULL>|
+sel |7.nonexist|
+out |<NULL>|
+sel |8|
+out |null|
+sel |9|
+out |<NULL>|
+
+tst |two-element array: various string escape codes|
+in |["abcd \" \\ \/ \b \f \n \r \t \u0000 \uf00F ", "final"]|
+sel |0|
+out |abcd \" \\ \/ \b \f \n \r \t \u0000 \uf00F |
+sel |1|
+out |final|
+
+tst |three-element array: broken escape code|
+in |["fine here", "dodgey \u00AZ", "wont get here"]|
+sel |0|
+out |fine here|
+sel |1|
+out |<NULL>|
+sel |2|
+out |<NULL>|
+
+tst |nested objects|
+in |{ "top": { "mid" : { "legs": "feet" }, "number": 9, "array":[0,1,{"a":true,"bb":[1,2,false,{"x":"yz"}]}]}}|
+sel |top|
+out |{ "mid" : { "legs": "feet" }, "number": 9, "array":[0,1,{"a":true,"bb":[1,2,false,{"x":"yz"}]}]}|
+sel |fargo|
+out |<NULL>|
+sel |top.mid|
+out |{ "legs": "feet" }|
+sel |top.centre|
+out |<NULL>|
+sel |top.mid.legs|
+out |feet|
+sel |top.mid.number|
+out |<NULL>|
+sel |top.mid.array|
+out |<NULL>|
+sel |top.number|
+out |9|
+sel |top.array|
+out |[0,1,{"a":true,"bb":[1,2,false,{"x":"yz"}]}]|
+sel |top.array[0]|
+out |0|
+sel |top.array[1]|
+out |1|
+sel |top.array[2]|
+out |{"a":true,"bb":[1,2,false,{"x":"yz"}]}|
+sel |top.array[2].a|
+out |true|
+sel |top.array[2].b|
+out |<NULL>|
+sel |top.array[2].bb|
+out |[1,2,false,{"x":"yz"}]|
+sel |top.array[2].bb[0]|
+out |1|
+sel |top.array[2].bb[1]|
+out |2|
+sel |top.array[2].bb[2]|
+out |false|
+sel |top.array[2].bb[3]|
+out |{"x":"yz"}|
+sel |top.array[2].bb[3].x|
+out |yz|
+sel |top.array[2].bb[3].x.nofurther|
+out |<NULL>|
+sel |top.array[2].bb[4]|
+out |<NULL>|
+sel |top.array[3]|
+out |<NULL>|
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d
new file mode 100644
index 000000000000..6aa50b9ad02b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d
@@ -0,0 +1,51 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * json() run time must be bounded above by strsize. This test makes strsize
+ * small and deliberately overflows it to prove we bail and return NULL in
+ * the event that we run off the end of the string.
+ *
+ */
+
+#pragma D option quiet
+#pragma D option strsize=18
+
+BEGIN
+{
+ in = "{\"a\": 1024}"; /* length == 19 */
+ out = json(in, "a");
+ printf("|%s|\n%s\n\n", in, out != NULL ? out : "<NULL>");
+
+ in = "{\"a\": 1024}"; /* length == 11 */
+ out = json(in, "a");
+ printf("|%s|\n%s\n\n", in, out != NULL ? out : "<NULL>");
+
+ in = "{\"a\":false,\"b\":true}"; /* length == 20 */
+ out = json(in, "b");
+ printf("|%s|\n%s\n\n", in, out != NULL ? out : "<NULL>");
+
+ in = "{\"a\":false,\"b\":20}"; /* length == 18 */
+ out = json(in, "b");
+ printf("|%s|\n%s\n\n", in, out != NULL ? out : "<NULL>");
+
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d.out
new file mode 100644
index 000000000000..7f1d79b6fedb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d.out
@@ -0,0 +1,13 @@
+|{"a": 1024|
+<NULL>
+
+|{"a": 1024}|
+1024
+
+|{"a":false,"b":tru|
+<NULL>
+
+|{"a":false,"b":20}|
+20
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.c
new file mode 100644
index 000000000000..2a54d4974be0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.c
@@ -0,0 +1,63 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012 (c), Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/sdt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "usdt.h"
+
+#define FMT "{" \
+ " \"sizes\": [ \"first\", 2, %f ]," \
+ " \"index\": %d," \
+ " \"facts\": {" \
+ " \"odd\": \"%s\"," \
+ " \"even\": \"%s\"" \
+ " }," \
+ " \"action\": \"%s\"" \
+ "}\n"
+
+int
+waiting(volatile int *a)
+{
+ return (*a);
+}
+
+int
+main(int argc, char **argv)
+{
+ volatile int a = 0;
+ int idx;
+ double size = 250.5;
+
+ while (waiting(&a) == 0)
+ continue;
+
+ for (idx = 0; idx < 10; idx++) {
+ char *odd, *even, *json, *action;
+
+ size *= 1.78;
+ odd = idx % 2 == 1 ? "true" : "false";
+ even = idx % 2 == 0 ? "true" : "false";
+ action = idx == 7 ? "ignore" : "print";
+
+ asprintf(&json, FMT, size, idx, odd, even, action);
+ BUNYAN_FAKE_LOG_DEBUG(json);
+ free(json);
+ }
+
+ BUNYAN_FAKE_LOG_DEBUG("{\"finished\": true}");
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d
new file mode 100644
index 000000000000..f0fbdd5cabab
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d
@@ -0,0 +1,65 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option strsize=4k
+#pragma D option quiet
+#pragma D option destructive
+
+/*
+ * This test reads a JSON string from a USDT probe, roughly simulating the
+ * primary motivating use case for the json() subroutine: filtering
+ * JSON-formatted log messages from a logging subsystem like node-bunyan.
+ */
+
+pid$1:a.out:waiting:entry
+{
+ this->value = (int *)alloca(sizeof (int));
+ *this->value = 1;
+ copyout(this->value, arg0, sizeof (int));
+}
+
+bunyan*$1:::log-*
+{
+ this->j = copyinstr(arg0);
+}
+
+bunyan*$1:::log-*
+/json(this->j, "finished") == NULL && json(this->j, "action") != "ignore"/
+{
+ this->index = strtoll(json(this->j, "index"));
+ this->size = json(this->j, "sizes[2]");
+ this->odd = json(this->j, "facts.odd");
+ this->even = json(this->j, "facts.even");
+ printf("[%d] sz %s odd %s even %s\n", this->index, this->size,
+ this->odd, this->even);
+}
+
+bunyan*$1:::log-*
+/json(this->j, "finished") != NULL/
+{
+ printf("FINISHED!\n");
+ exit(0);
+}
+
+tick-10s
+{
+ printf("ERROR: Timed out before finish message!\n");
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d.out
new file mode 100644
index 000000000000..c7f58bb535dd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d.out
@@ -0,0 +1,11 @@
+[0] sz 445.890000 odd false even true
+[1] sz 793.684200 odd true even false
+[2] sz 1412.757876 odd false even true
+[3] sz 2514.709019 odd true even false
+[4] sz 4476.182054 odd false even true
+[5] sz 7967.604057 odd true even false
+[6] sz 14182.335221 odd false even true
+[8] sz 44935.310914 odd false even true
+[9] sz 79984.853427 odd true even false
+FINISHED!
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/usdt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/usdt.d
new file mode 100644
index 000000000000..1a4fc87f60f4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/usdt.d
@@ -0,0 +1,27 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Sets up a fake node-bunyan-like USDT provider for use from C.
+ */
+
+provider bunyan_fake {
+ probe log__trace(char *msg);
+ probe log__debug(char *msg);
+ probe log__info(char *msg);
+ probe log__warn(char *msg);
+ probe log__error(char *msg);
+ probe log__fatal(char *msg);
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_CHR_NL.char.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_CHR_NL.char.d
new file mode 100644
index 000000000000..abae0c147b45
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_CHR_NL.char.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Newlines may not be embedded in character constants..
+ *
+ * SECTION: Lexer
+ */
+
+
+BEGIN
+{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winvalid-pp-token"
+ h = '
+ ';
+#pragma clang diagnostic pop
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_CHR_NULL.char.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_CHR_NULL.char.d
new file mode 100644
index 000000000000..8cfbcc2bab36
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_CHR_NULL.char.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Char constants may not be empty
+ *
+ * SECTION: Lexer
+ */
+
+
+BEGIN
+{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winvalid-pp-token"
+ h = '';
+ exit(0);
+#pragma clang diagnostic pop
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_INT_DIGIT.InvalidDigit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_INT_DIGIT.InvalidDigit.d
new file mode 100644
index 000000000000..4fac03bc575e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_INT_DIGIT.InvalidDigit.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: If an integer representation contains an invalid digit
+ * a D_INT_DIGIT is thrown.
+ *
+ * SECTION: Errtags/D_INT_DIGIT
+ */
+
+BEGIN
+{
+ 0128;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_INT_OFLOW.BigInt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_INT_OFLOW.BigInt.d
new file mode 100644
index 000000000000..1ec8be8f1075
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_INT_OFLOW.BigInt.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Using an integer constant that cannot be represented in any of the
+ * builtin integral types throws a D_INT_OFLOW error.
+ *
+ * SECTION: Errtags/D_INT_OFLOW
+ */
+
+BEGIN
+{
+ 0x12345678123456781;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_STR_NL.string.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_STR_NL.string.d
new file mode 100644
index 000000000000..c83e0c505dd3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_STR_NL.string.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Newlines may not be embedded in string literals.
+ *
+ * SECTION: Lexer
+ */
+
+
+BEGIN
+{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winvalid-pp-token"
+ h = "hello
+
+ there";
+ exit(0);
+#pragma clang diagnostic pop
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brace1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brace1.d
new file mode 100644
index 000000000000..ae6dc6ceb1e0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brace1.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test detection of extra curly braces.
+ *
+ * SECTION: Lexer
+ */
+
+BEGIN
+{
+ trace(epid);
+}
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brace2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brace2.d
new file mode 100644
index 000000000000..196f7d7ca606
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brace2.d
@@ -0,0 +1,37 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: * Test detection of missing curly braces.
+ *
+ * SECTION: Lexer
+ */
+
+BEGIN
+{
+ trace(epid);
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack1.d
new file mode 100644
index 000000000000..8e4c97dad6da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack1.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test detection of extra square brackets
+ *
+ * SECTION: Lexer
+ */
+
+BEGIN
+{
+ trace(args[0]]);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack2.d
new file mode 100644
index 000000000000..307bd08d6cb5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack2.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test detection of missing square brackets
+ *
+ * SECTION: Lexer
+ */
+
+BEGIN
+{
+ args[0
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack3.d
new file mode 100644
index 000000000000..2d66828ced2d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.brack3.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test detection of missing square brackets
+ *
+ * SECTION: Lexer
+ */
+
+BEGIN
+/args[0/
+{
+ trace(epid);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren1.d
new file mode 100644
index 000000000000..812dbb7d753f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren1.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test detection of extra parentheses
+ *
+ * SECTION: Lexer
+ */
+
+BEGIN
+{
+ trace(epid));
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren2.d
new file mode 100644
index 000000000000..078d08c61294
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren2.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test detection of missing parentheses
+ *
+ * SECTION: Lexer
+ */
+
+BEGIN
+{
+ rand(
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren3.d
new file mode 100644
index 000000000000..38cdb7e8269e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/err.D_SYNTAX.paren3.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test detection of missing parentheses
+ *
+ * SECTION: Lexer
+ */
+
+BEGIN
+/rand(/
+{
+ trace(epid);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/tst.D_MACRO_OFLOW.ParIntOvflow.d.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/tst.D_MACRO_OFLOW.ParIntOvflow.d.ksh
new file mode 100644
index 000000000000..ad124ea9367d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/lexer/tst.D_MACRO_OFLOW.ParIntOvflow.d.ksh
@@ -0,0 +1,54 @@
+#!/bin/ksh -p
+
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# ASSERTION:
+# If a macro argument results in an integer overflow, a D_MACRO_OFLOW is
+# thrown.
+#
+# SECTION: Errtags/D_MACRO_OFLOW
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -n 'BEGIN { $1; }' 0x12345678123456781
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ exit 0
+fi
+
+echo dtrace failed
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTOREVEN.nodivide.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTOREVEN.nodivide.d
new file mode 100644
index 000000000000..b11d2828bb7f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTOREVEN.nodivide.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 0, 10, 25);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTOREVEN.notfactor.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTOREVEN.notfactor.d
new file mode 100644
index 000000000000..c8af7d920f3c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTOREVEN.notfactor.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 0, 10, 30);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORMATCH.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORMATCH.d
new file mode 100644
index 000000000000..0404b4ffbdcf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORMATCH.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 0, 10, 10);
+ @ = llquantize(0, 3, 0, 10, 81);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORNSTEPS.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORNSTEPS.d
new file mode 100644
index 000000000000..fd6b0e67f261
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORNSTEPS.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 0, 10, 7);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORSMALL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORSMALL.d
new file mode 100644
index 000000000000..7074f5f66501
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORSMALL.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 1, 0, 10, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORTYPE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORTYPE.d
new file mode 100644
index 000000000000..ea39c7e38ca9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORTYPE.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ this->doogle = 10;
+ @ = llquantize(0, this->doogle, 0, 10, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORVAL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORVAL.d
new file mode 100644
index 000000000000..a1ad20f28a62
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_FACTORVAL.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 65537, 0, 10, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHMATCH.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHMATCH.d
new file mode 100644
index 000000000000..46bf0e6fc206
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHMATCH.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 0, 10, 10);
+ @ = llquantize(0, 10, 0, 11, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHTYPE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHTYPE.d
new file mode 100644
index 000000000000..fee786d39e0d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHTYPE.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ this->doogle = 10;
+ @ = llquantize(0, 10, 0, this->doogle, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHVAL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHVAL.d
new file mode 100644
index 000000000000..531ab0b6641f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_HIGHVAL.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 0, -1, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWMATCH.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWMATCH.d
new file mode 100644
index 000000000000..126429a2996d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWMATCH.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 0, 10, 10);
+ @ = llquantize(0, 10, 1, 10, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWTYPE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWTYPE.d
new file mode 100644
index 000000000000..2a9b2efdc8d1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWTYPE.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ this->doogle = 0;
+ @ = llquantize(0, 10, this->doogle, 10, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWVAL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWVAL.d
new file mode 100644
index 000000000000..e1045d83bdcf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_LOWVAL.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, -1, 10, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGRANGE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGRANGE.d
new file mode 100644
index 000000000000..9852c1ab9532
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGRANGE.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 10, 0, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGTOOBIG.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGTOOBIG.d
new file mode 100644
index 000000000000..c7076308446b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGTOOBIG.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 0, 100, 10);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGTOOBIG.offbyone.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGTOOBIG.offbyone.d
new file mode 100644
index 000000000000..47dccafbe4c4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_MAGTOOBIG.offbyone.d
@@ -0,0 +1,25 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Mark Johnston <markj@FreeBSD.org>
+ */
+
+/*
+ * A regression test for FreeBSD r322773. 100^9 fits in 64 bits, but
+ * llquantize() will create buckets up to 100^{10}, which does not fit.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 100, 0, 9, 100);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPMATCH.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPMATCH.d
new file mode 100644
index 000000000000..77b4d8a84d20
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPMATCH.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(0, 10, 0, 10, 10);
+ @ = llquantize(0, 10, 0, 10, 100);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPTYPE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPTYPE.d
new file mode 100644
index 000000000000..4eb9b2f06d0a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPTYPE.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ this->doogle = 10;
+ @ = llquantize(0, 10, 0, 10, this->doogle);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPVAL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPVAL.d
new file mode 100644
index 000000000000..3855beb4adc2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/err.D_LLQUANT_NSTEPVAL.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = llquantize(123, 10, 0, 10, 123456);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.bases.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.bases.d
new file mode 100644
index 000000000000..e3a6ff1a8cde
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.bases.d
@@ -0,0 +1,46 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+tick-1ms
+/i++ <= 100/
+{
+ @two = llquantize(i, 2, 0, 6, 2);
+ @three = llquantize(i, 3, 0, 1, 9);
+ @four = llquantize(i, 4, 0, 1, 4);
+ @five = llquantize(i, 5, 0, 1, 25);
+ @six = llquantize(i, 6, 0, 3, 12);
+ @seven = llquantize(i, 7, 0, 1, 7);
+ @eight = llquantize(i, 8, 0, 1, 16);
+ @nine = llquantize(i, 9, 0, 1, 9);
+ @ten = llquantize(i, 10, 0, 1, 10);
+}
+
+tick-1ms
+/i > 100/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.bases.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.bases.d.out
new file mode 100644
index 000000000000..1b207bf6f292
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.bases.d.out
@@ -0,0 +1,177 @@
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 |@ 2
+ 4 |@@ 4
+ 8 |@@@ 8
+ 16 |@@@@@@ 16
+ 32 |@@@@@@@@@@@@@ 32
+ 64 |@@@@@@@@@@@@@@@ 38
+ >= 128 | 0
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 | 1
+ 8 | 1
+ >= 9 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 93
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 |@@ 4
+ 8 |@@ 4
+ 12 |@@ 4
+ >= 16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 86
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 | 1
+ 8 | 1
+ 9 | 1
+ 10 | 1
+ 11 | 1
+ 12 | 1
+ 13 | 1
+ 14 | 1
+ 15 | 1
+ 16 | 1
+ 17 | 1
+ 18 | 1
+ 19 | 1
+ 20 | 1
+ 21 | 1
+ 22 | 1
+ 23 | 1
+ 24 | 1
+ >= 25 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 77
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 1
+ 5 | 1
+ 6 |@ 3
+ 9 |@ 3
+ 12 |@ 3
+ 15 |@ 3
+ 18 |@ 3
+ 21 |@ 3
+ 24 |@ 3
+ 27 |@ 3
+ 30 |@ 3
+ 33 |@ 3
+ 36 |@@@@@@@ 18
+ 54 |@@@@@@@ 18
+ 72 |@@@@@@@ 18
+ 90 |@@@@@ 12
+ 108 | 0
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 |@@@ 7
+ 14 |@@@ 7
+ 21 |@@@ 7
+ 28 |@@@ 7
+ 35 |@@@ 7
+ 42 |@@@ 7
+ >= 49 |@@@@@@@@@@@@@@@@@@@@@ 53
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 | 1
+ 8 |@@ 4
+ 12 |@@ 4
+ 16 |@@ 4
+ 20 |@@ 4
+ 24 |@@ 4
+ 28 |@@ 4
+ 32 |@@ 4
+ 36 |@@ 4
+ 40 |@@ 4
+ 44 |@@ 4
+ 48 |@@ 4
+ 52 |@@ 4
+ 56 |@@ 4
+ 60 |@@ 4
+ >= 64 |@@@@@@@@@@@@@@@ 38
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 | 1
+ 8 | 1
+ 9 |@@@@ 9
+ 18 |@@@@ 9
+ 27 |@@@@ 9
+ 36 |@@@@ 9
+ 45 |@@@@ 9
+ 54 |@@@@ 9
+ 63 |@@@@ 9
+ 72 |@@@@ 9
+ >= 81 |@@@@@@@@ 21
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 | 1
+ 8 | 1
+ 9 | 1
+ 10 |@@@@ 10
+ 20 |@@@@ 10
+ 30 |@@@@ 10
+ 40 |@@@@ 10
+ 50 |@@@@ 10
+ 60 |@@@@ 10
+ 70 |@@@@ 10
+ 80 |@@@@ 10
+ 90 |@@@@ 10
+ >= 100 |@ 2
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.basic.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.basic.d
new file mode 100644
index 000000000000..57b6ed881b7f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.basic.d
@@ -0,0 +1,38 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+tick-1ms
+/i++ <= 100/
+{
+ @ = llquantize(i, 10, 0, 10, 10);
+}
+
+tick-1ms
+/i > 100/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.basic.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.basic.d.out
new file mode 100644
index 000000000000..9a7b288966f3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.basic.d.out
@@ -0,0 +1,25 @@
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 | 1
+ 8 | 1
+ 9 | 1
+ 10 |@@@@ 10
+ 20 |@@@@ 10
+ 30 |@@@@ 10
+ 40 |@@@@ 10
+ 50 |@@@@ 10
+ 60 |@@@@ 10
+ 70 |@@@@ 10
+ 80 |@@@@ 10
+ 90 |@@@@ 10
+ 100 |@ 2
+ 200 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negorder.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negorder.d
new file mode 100644
index 000000000000..b18c688bc750
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negorder.d
@@ -0,0 +1,62 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = 7;
+ b = 13;
+ val = (-a * b) + a;
+}
+
+tick-1ms
+{
+ incr = val % b;
+ val += a;
+}
+
+tick-1ms
+/val == 0/
+{
+ val += a;
+}
+
+tick-1ms
+/incr != 0/
+{
+ i++;
+ @llquanty[i] = llquantize(1, 10, 0, 10, 10, incr);
+}
+
+tick-1ms
+/incr == 0/
+{
+ printf("Ordering of llquantize() with some negative weights:\n");
+ printa(@llquanty);
+ printf("\n");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negorder.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negorder.d.out
new file mode 100644
index 000000000000..ac0f3cb300e1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negorder.d.out
@@ -0,0 +1,148 @@
+Ordering of llquantize() with some negative weights:
+
+ 2
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -12
+ 2 | 0
+
+ 4
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -11
+ 2 | 0
+
+ 6
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -10
+ 2 | 0
+
+ 8
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -9
+ 2 | 0
+
+ 10
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -8
+ 2 | 0
+
+ 12
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -7
+ 2 | 0
+
+ 1
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -6
+ 2 | 0
+
+ 3
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -5
+ 2 | 0
+
+ 5
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -4
+ 2 | 0
+
+ 7
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -3
+ 2 | 0
+
+ 9
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -2
+ 2 | 0
+
+ 11
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -1
+ 2 | 0
+
+ 14
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 2 | 0
+
+ 16
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2
+ 2 | 0
+
+ 18
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
+ 2 | 0
+
+ 20
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 2 | 0
+
+ 22
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5
+ 2 | 0
+
+ 24
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
+ 2 | 0
+
+ 13
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
+ 2 | 0
+
+ 15
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8
+ 2 | 0
+
+ 17
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9
+ 2 | 0
+
+ 19
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10
+ 2 | 0
+
+ 21
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
+ 2 | 0
+
+ 23
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 12
+ 2 | 0
+
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negvalue.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negvalue.d
new file mode 100644
index 000000000000..c74d019cb186
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negvalue.d
@@ -0,0 +1,38 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+tick-1ms
+/i++ <= 100/
+{
+ @ = llquantize(i, 10, 0, 10, 10, 50 - i);
+}
+
+tick-1ms
+/i > 100/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negvalue.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negvalue.d.out
new file mode 100644
index 000000000000..04b0d5e1bded
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.negvalue.d.out
@@ -0,0 +1,25 @@
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 49
+ 2 | 48
+ 3 | 47
+ 4 | 46
+ 5 | 45
+ 6 | 44
+ 7 | 43
+ 8 | 42
+ 9 | 41
+ 10 |@@@ 355
+ 20 |@@ 255
+ 30 |@ 155
+ 40 | 55
+ 50 | -45
+ 60 @| -145
+ 70 @@| -245
+ 80 @@@| -345
+ 90 @@@| -445
+ 100 @| -101
+ 200 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.normal.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.normal.d
new file mode 100644
index 000000000000..7097ba7d33c7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.normal.d
@@ -0,0 +1,40 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+tick-1ms
+/i++ <= 100/
+{
+ @ = llquantize(i, 10, 0, 10, 10);
+}
+
+tick-1ms
+/i > 100/
+{
+ normalize(@, 10);
+ printa(@);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.normal.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.normal.d.out
new file mode 100644
index 000000000000..3b1f41b218fc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.normal.d.out
@@ -0,0 +1,26 @@
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 0
+ 2 | 0
+ 3 | 0
+ 4 | 0
+ 5 | 0
+ 6 | 0
+ 7 | 0
+ 8 | 0
+ 9 | 0
+ 10 |@@@@ 1
+ 20 |@@@@ 1
+ 30 |@@@@ 1
+ 40 |@@@@ 1
+ 50 |@@@@ 1
+ 60 |@@@@ 1
+ 70 |@@@@ 1
+ 80 |@@@@ 1
+ 90 |@@@@ 1
+ 100 |@ 0
+ 200 | 0
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.range.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.range.d
new file mode 100644
index 000000000000..e2882b3f8e3f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.range.d
@@ -0,0 +1,38 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @["Screven"] = llquantize(0, 10, 1, 2, 20, 25);
+ @["Katz"] = llquantize(1, 10, 1, 2, 20, -100);
+ @["Kurian"] = llquantize(7, 10, 1, 2, 20, 15);
+ @["Rozwat"] = llquantize(49, 10, 1, 2, 20, 15);
+ @["Fowler"] = llquantize(343, 10, 1, 2, 20, 150);
+
+ printa(@);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.range.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.range.d.out
new file mode 100644
index 000000000000..c6736c6fc153
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.range.d.out
@@ -0,0 +1,29 @@
+
+ Katz
+ value ------------- Distribution ------------- count
+ < 10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| -100
+ 10 | 0
+
+ Kurian
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 15
+ 10 | 0
+
+ Screven
+ value ------------- Distribution ------------- count
+ < 10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 25
+ 10 | 0
+
+ Rozwat
+ value ------------- Distribution ------------- count
+ 40 | 0
+ 45 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 15
+ 50 | 0
+
+ Fowler
+ value ------------- Distribution ------------- count
+ 250 | 0
+ 300 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 150
+ 350 | 0
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.steps.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.steps.d
new file mode 100644
index 000000000000..f00659e57513
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.steps.d
@@ -0,0 +1,52 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+tick-1ms
+/i++ <= 100/
+{
+ @ = llquantize(i, 10, 0, 10, 20);
+ @hunid = llquantize(i * 10, 10, 0, 10, 100);
+ @large = llquantize(i * 100, 10, 0, 10, 1000);
+}
+
+tick-1ms
+/i > 100/
+{
+ exit(0);
+}
+
+END
+{
+ printf("20 steps:\n");
+ printa(@);
+
+ printf("100 steps:\n");
+ printa(@hunid);
+
+ printf("1000 steps:\n");
+ printa(@large);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.steps.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.steps.d.out
new file mode 100644
index 000000000000..08885515c002
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.steps.d.out
@@ -0,0 +1,2033 @@
+20 steps:
+
+
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 | 1
+ 8 | 1
+ 9 | 1
+ 10 |@@ 5
+ 15 |@@ 5
+ 20 |@@ 5
+ 25 |@@ 5
+ 30 |@@ 5
+ 35 |@@ 5
+ 40 |@@ 5
+ 45 |@@ 5
+ 50 |@@ 5
+ 55 |@@ 5
+ 60 |@@ 5
+ 65 |@@ 5
+ 70 |@@ 5
+ 75 |@@ 5
+ 80 |@@ 5
+ 85 |@@ 5
+ 90 |@@ 5
+ 95 |@@ 5
+ 100 |@ 2
+ 150 | 0
+
+100 steps:
+
+
+ value ------------- Distribution ------------- count
+ 9 | 0
+ 10 | 1
+ 11 | 0
+ 12 | 0
+ 13 | 0
+ 14 | 0
+ 15 | 0
+ 16 | 0
+ 17 | 0
+ 18 | 0
+ 19 | 0
+ 20 | 1
+ 21 | 0
+ 22 | 0
+ 23 | 0
+ 24 | 0
+ 25 | 0
+ 26 | 0
+ 27 | 0
+ 28 | 0
+ 29 | 0
+ 30 | 1
+ 31 | 0
+ 32 | 0
+ 33 | 0
+ 34 | 0
+ 35 | 0
+ 36 | 0
+ 37 | 0
+ 38 | 0
+ 39 | 0
+ 40 | 1
+ 41 | 0
+ 42 | 0
+ 43 | 0
+ 44 | 0
+ 45 | 0
+ 46 | 0
+ 47 | 0
+ 48 | 0
+ 49 | 0
+ 50 | 1
+ 51 | 0
+ 52 | 0
+ 53 | 0
+ 54 | 0
+ 55 | 0
+ 56 | 0
+ 57 | 0
+ 58 | 0
+ 59 | 0
+ 60 | 1
+ 61 | 0
+ 62 | 0
+ 63 | 0
+ 64 | 0
+ 65 | 0
+ 66 | 0
+ 67 | 0
+ 68 | 0
+ 69 | 0
+ 70 | 1
+ 71 | 0
+ 72 | 0
+ 73 | 0
+ 74 | 0
+ 75 | 0
+ 76 | 0
+ 77 | 0
+ 78 | 0
+ 79 | 0
+ 80 | 1
+ 81 | 0
+ 82 | 0
+ 83 | 0
+ 84 | 0
+ 85 | 0
+ 86 | 0
+ 87 | 0
+ 88 | 0
+ 89 | 0
+ 90 | 1
+ 91 | 0
+ 92 | 0
+ 93 | 0
+ 94 | 0
+ 95 | 0
+ 96 | 0
+ 97 | 0
+ 98 | 0
+ 99 | 0
+ 100 | 1
+ 110 | 1
+ 120 | 1
+ 130 | 1
+ 140 | 1
+ 150 | 1
+ 160 | 1
+ 170 | 1
+ 180 | 1
+ 190 | 1
+ 200 | 1
+ 210 | 1
+ 220 | 1
+ 230 | 1
+ 240 | 1
+ 250 | 1
+ 260 | 1
+ 270 | 1
+ 280 | 1
+ 290 | 1
+ 300 | 1
+ 310 | 1
+ 320 | 1
+ 330 | 1
+ 340 | 1
+ 350 | 1
+ 360 | 1
+ 370 | 1
+ 380 | 1
+ 390 | 1
+ 400 | 1
+ 410 | 1
+ 420 | 1
+ 430 | 1
+ 440 | 1
+ 450 | 1
+ 460 | 1
+ 470 | 1
+ 480 | 1
+ 490 | 1
+ 500 | 1
+ 510 | 1
+ 520 | 1
+ 530 | 1
+ 540 | 1
+ 550 | 1
+ 560 | 1
+ 570 | 1
+ 580 | 1
+ 590 | 1
+ 600 | 1
+ 610 | 1
+ 620 | 1
+ 630 | 1
+ 640 | 1
+ 650 | 1
+ 660 | 1
+ 670 | 1
+ 680 | 1
+ 690 | 1
+ 700 | 1
+ 710 | 1
+ 720 | 1
+ 730 | 1
+ 740 | 1
+ 750 | 1
+ 760 | 1
+ 770 | 1
+ 780 | 1
+ 790 | 1
+ 800 | 1
+ 810 | 1
+ 820 | 1
+ 830 | 1
+ 840 | 1
+ 850 | 1
+ 860 | 1
+ 870 | 1
+ 880 | 1
+ 890 | 1
+ 900 | 1
+ 910 | 1
+ 920 | 1
+ 930 | 1
+ 940 | 1
+ 950 | 1
+ 960 | 1
+ 970 | 1
+ 980 | 1
+ 990 | 1
+ 1000 |@ 2
+ 1100 | 0
+
+1000 steps:
+
+
+ value ------------- Distribution ------------- count
+ 99 | 0
+ 100 | 1
+ 101 | 0
+ 102 | 0
+ 103 | 0
+ 104 | 0
+ 105 | 0
+ 106 | 0
+ 107 | 0
+ 108 | 0
+ 109 | 0
+ 110 | 0
+ 111 | 0
+ 112 | 0
+ 113 | 0
+ 114 | 0
+ 115 | 0
+ 116 | 0
+ 117 | 0
+ 118 | 0
+ 119 | 0
+ 120 | 0
+ 121 | 0
+ 122 | 0
+ 123 | 0
+ 124 | 0
+ 125 | 0
+ 126 | 0
+ 127 | 0
+ 128 | 0
+ 129 | 0
+ 130 | 0
+ 131 | 0
+ 132 | 0
+ 133 | 0
+ 134 | 0
+ 135 | 0
+ 136 | 0
+ 137 | 0
+ 138 | 0
+ 139 | 0
+ 140 | 0
+ 141 | 0
+ 142 | 0
+ 143 | 0
+ 144 | 0
+ 145 | 0
+ 146 | 0
+ 147 | 0
+ 148 | 0
+ 149 | 0
+ 150 | 0
+ 151 | 0
+ 152 | 0
+ 153 | 0
+ 154 | 0
+ 155 | 0
+ 156 | 0
+ 157 | 0
+ 158 | 0
+ 159 | 0
+ 160 | 0
+ 161 | 0
+ 162 | 0
+ 163 | 0
+ 164 | 0
+ 165 | 0
+ 166 | 0
+ 167 | 0
+ 168 | 0
+ 169 | 0
+ 170 | 0
+ 171 | 0
+ 172 | 0
+ 173 | 0
+ 174 | 0
+ 175 | 0
+ 176 | 0
+ 177 | 0
+ 178 | 0
+ 179 | 0
+ 180 | 0
+ 181 | 0
+ 182 | 0
+ 183 | 0
+ 184 | 0
+ 185 | 0
+ 186 | 0
+ 187 | 0
+ 188 | 0
+ 189 | 0
+ 190 | 0
+ 191 | 0
+ 192 | 0
+ 193 | 0
+ 194 | 0
+ 195 | 0
+ 196 | 0
+ 197 | 0
+ 198 | 0
+ 199 | 0
+ 200 | 1
+ 201 | 0
+ 202 | 0
+ 203 | 0
+ 204 | 0
+ 205 | 0
+ 206 | 0
+ 207 | 0
+ 208 | 0
+ 209 | 0
+ 210 | 0
+ 211 | 0
+ 212 | 0
+ 213 | 0
+ 214 | 0
+ 215 | 0
+ 216 | 0
+ 217 | 0
+ 218 | 0
+ 219 | 0
+ 220 | 0
+ 221 | 0
+ 222 | 0
+ 223 | 0
+ 224 | 0
+ 225 | 0
+ 226 | 0
+ 227 | 0
+ 228 | 0
+ 229 | 0
+ 230 | 0
+ 231 | 0
+ 232 | 0
+ 233 | 0
+ 234 | 0
+ 235 | 0
+ 236 | 0
+ 237 | 0
+ 238 | 0
+ 239 | 0
+ 240 | 0
+ 241 | 0
+ 242 | 0
+ 243 | 0
+ 244 | 0
+ 245 | 0
+ 246 | 0
+ 247 | 0
+ 248 | 0
+ 249 | 0
+ 250 | 0
+ 251 | 0
+ 252 | 0
+ 253 | 0
+ 254 | 0
+ 255 | 0
+ 256 | 0
+ 257 | 0
+ 258 | 0
+ 259 | 0
+ 260 | 0
+ 261 | 0
+ 262 | 0
+ 263 | 0
+ 264 | 0
+ 265 | 0
+ 266 | 0
+ 267 | 0
+ 268 | 0
+ 269 | 0
+ 270 | 0
+ 271 | 0
+ 272 | 0
+ 273 | 0
+ 274 | 0
+ 275 | 0
+ 276 | 0
+ 277 | 0
+ 278 | 0
+ 279 | 0
+ 280 | 0
+ 281 | 0
+ 282 | 0
+ 283 | 0
+ 284 | 0
+ 285 | 0
+ 286 | 0
+ 287 | 0
+ 288 | 0
+ 289 | 0
+ 290 | 0
+ 291 | 0
+ 292 | 0
+ 293 | 0
+ 294 | 0
+ 295 | 0
+ 296 | 0
+ 297 | 0
+ 298 | 0
+ 299 | 0
+ 300 | 1
+ 301 | 0
+ 302 | 0
+ 303 | 0
+ 304 | 0
+ 305 | 0
+ 306 | 0
+ 307 | 0
+ 308 | 0
+ 309 | 0
+ 310 | 0
+ 311 | 0
+ 312 | 0
+ 313 | 0
+ 314 | 0
+ 315 | 0
+ 316 | 0
+ 317 | 0
+ 318 | 0
+ 319 | 0
+ 320 | 0
+ 321 | 0
+ 322 | 0
+ 323 | 0
+ 324 | 0
+ 325 | 0
+ 326 | 0
+ 327 | 0
+ 328 | 0
+ 329 | 0
+ 330 | 0
+ 331 | 0
+ 332 | 0
+ 333 | 0
+ 334 | 0
+ 335 | 0
+ 336 | 0
+ 337 | 0
+ 338 | 0
+ 339 | 0
+ 340 | 0
+ 341 | 0
+ 342 | 0
+ 343 | 0
+ 344 | 0
+ 345 | 0
+ 346 | 0
+ 347 | 0
+ 348 | 0
+ 349 | 0
+ 350 | 0
+ 351 | 0
+ 352 | 0
+ 353 | 0
+ 354 | 0
+ 355 | 0
+ 356 | 0
+ 357 | 0
+ 358 | 0
+ 359 | 0
+ 360 | 0
+ 361 | 0
+ 362 | 0
+ 363 | 0
+ 364 | 0
+ 365 | 0
+ 366 | 0
+ 367 | 0
+ 368 | 0
+ 369 | 0
+ 370 | 0
+ 371 | 0
+ 372 | 0
+ 373 | 0
+ 374 | 0
+ 375 | 0
+ 376 | 0
+ 377 | 0
+ 378 | 0
+ 379 | 0
+ 380 | 0
+ 381 | 0
+ 382 | 0
+ 383 | 0
+ 384 | 0
+ 385 | 0
+ 386 | 0
+ 387 | 0
+ 388 | 0
+ 389 | 0
+ 390 | 0
+ 391 | 0
+ 392 | 0
+ 393 | 0
+ 394 | 0
+ 395 | 0
+ 396 | 0
+ 397 | 0
+ 398 | 0
+ 399 | 0
+ 400 | 1
+ 401 | 0
+ 402 | 0
+ 403 | 0
+ 404 | 0
+ 405 | 0
+ 406 | 0
+ 407 | 0
+ 408 | 0
+ 409 | 0
+ 410 | 0
+ 411 | 0
+ 412 | 0
+ 413 | 0
+ 414 | 0
+ 415 | 0
+ 416 | 0
+ 417 | 0
+ 418 | 0
+ 419 | 0
+ 420 | 0
+ 421 | 0
+ 422 | 0
+ 423 | 0
+ 424 | 0
+ 425 | 0
+ 426 | 0
+ 427 | 0
+ 428 | 0
+ 429 | 0
+ 430 | 0
+ 431 | 0
+ 432 | 0
+ 433 | 0
+ 434 | 0
+ 435 | 0
+ 436 | 0
+ 437 | 0
+ 438 | 0
+ 439 | 0
+ 440 | 0
+ 441 | 0
+ 442 | 0
+ 443 | 0
+ 444 | 0
+ 445 | 0
+ 446 | 0
+ 447 | 0
+ 448 | 0
+ 449 | 0
+ 450 | 0
+ 451 | 0
+ 452 | 0
+ 453 | 0
+ 454 | 0
+ 455 | 0
+ 456 | 0
+ 457 | 0
+ 458 | 0
+ 459 | 0
+ 460 | 0
+ 461 | 0
+ 462 | 0
+ 463 | 0
+ 464 | 0
+ 465 | 0
+ 466 | 0
+ 467 | 0
+ 468 | 0
+ 469 | 0
+ 470 | 0
+ 471 | 0
+ 472 | 0
+ 473 | 0
+ 474 | 0
+ 475 | 0
+ 476 | 0
+ 477 | 0
+ 478 | 0
+ 479 | 0
+ 480 | 0
+ 481 | 0
+ 482 | 0
+ 483 | 0
+ 484 | 0
+ 485 | 0
+ 486 | 0
+ 487 | 0
+ 488 | 0
+ 489 | 0
+ 490 | 0
+ 491 | 0
+ 492 | 0
+ 493 | 0
+ 494 | 0
+ 495 | 0
+ 496 | 0
+ 497 | 0
+ 498 | 0
+ 499 | 0
+ 500 | 1
+ 501 | 0
+ 502 | 0
+ 503 | 0
+ 504 | 0
+ 505 | 0
+ 506 | 0
+ 507 | 0
+ 508 | 0
+ 509 | 0
+ 510 | 0
+ 511 | 0
+ 512 | 0
+ 513 | 0
+ 514 | 0
+ 515 | 0
+ 516 | 0
+ 517 | 0
+ 518 | 0
+ 519 | 0
+ 520 | 0
+ 521 | 0
+ 522 | 0
+ 523 | 0
+ 524 | 0
+ 525 | 0
+ 526 | 0
+ 527 | 0
+ 528 | 0
+ 529 | 0
+ 530 | 0
+ 531 | 0
+ 532 | 0
+ 533 | 0
+ 534 | 0
+ 535 | 0
+ 536 | 0
+ 537 | 0
+ 538 | 0
+ 539 | 0
+ 540 | 0
+ 541 | 0
+ 542 | 0
+ 543 | 0
+ 544 | 0
+ 545 | 0
+ 546 | 0
+ 547 | 0
+ 548 | 0
+ 549 | 0
+ 550 | 0
+ 551 | 0
+ 552 | 0
+ 553 | 0
+ 554 | 0
+ 555 | 0
+ 556 | 0
+ 557 | 0
+ 558 | 0
+ 559 | 0
+ 560 | 0
+ 561 | 0
+ 562 | 0
+ 563 | 0
+ 564 | 0
+ 565 | 0
+ 566 | 0
+ 567 | 0
+ 568 | 0
+ 569 | 0
+ 570 | 0
+ 571 | 0
+ 572 | 0
+ 573 | 0
+ 574 | 0
+ 575 | 0
+ 576 | 0
+ 577 | 0
+ 578 | 0
+ 579 | 0
+ 580 | 0
+ 581 | 0
+ 582 | 0
+ 583 | 0
+ 584 | 0
+ 585 | 0
+ 586 | 0
+ 587 | 0
+ 588 | 0
+ 589 | 0
+ 590 | 0
+ 591 | 0
+ 592 | 0
+ 593 | 0
+ 594 | 0
+ 595 | 0
+ 596 | 0
+ 597 | 0
+ 598 | 0
+ 599 | 0
+ 600 | 1
+ 601 | 0
+ 602 | 0
+ 603 | 0
+ 604 | 0
+ 605 | 0
+ 606 | 0
+ 607 | 0
+ 608 | 0
+ 609 | 0
+ 610 | 0
+ 611 | 0
+ 612 | 0
+ 613 | 0
+ 614 | 0
+ 615 | 0
+ 616 | 0
+ 617 | 0
+ 618 | 0
+ 619 | 0
+ 620 | 0
+ 621 | 0
+ 622 | 0
+ 623 | 0
+ 624 | 0
+ 625 | 0
+ 626 | 0
+ 627 | 0
+ 628 | 0
+ 629 | 0
+ 630 | 0
+ 631 | 0
+ 632 | 0
+ 633 | 0
+ 634 | 0
+ 635 | 0
+ 636 | 0
+ 637 | 0
+ 638 | 0
+ 639 | 0
+ 640 | 0
+ 641 | 0
+ 642 | 0
+ 643 | 0
+ 644 | 0
+ 645 | 0
+ 646 | 0
+ 647 | 0
+ 648 | 0
+ 649 | 0
+ 650 | 0
+ 651 | 0
+ 652 | 0
+ 653 | 0
+ 654 | 0
+ 655 | 0
+ 656 | 0
+ 657 | 0
+ 658 | 0
+ 659 | 0
+ 660 | 0
+ 661 | 0
+ 662 | 0
+ 663 | 0
+ 664 | 0
+ 665 | 0
+ 666 | 0
+ 667 | 0
+ 668 | 0
+ 669 | 0
+ 670 | 0
+ 671 | 0
+ 672 | 0
+ 673 | 0
+ 674 | 0
+ 675 | 0
+ 676 | 0
+ 677 | 0
+ 678 | 0
+ 679 | 0
+ 680 | 0
+ 681 | 0
+ 682 | 0
+ 683 | 0
+ 684 | 0
+ 685 | 0
+ 686 | 0
+ 687 | 0
+ 688 | 0
+ 689 | 0
+ 690 | 0
+ 691 | 0
+ 692 | 0
+ 693 | 0
+ 694 | 0
+ 695 | 0
+ 696 | 0
+ 697 | 0
+ 698 | 0
+ 699 | 0
+ 700 | 1
+ 701 | 0
+ 702 | 0
+ 703 | 0
+ 704 | 0
+ 705 | 0
+ 706 | 0
+ 707 | 0
+ 708 | 0
+ 709 | 0
+ 710 | 0
+ 711 | 0
+ 712 | 0
+ 713 | 0
+ 714 | 0
+ 715 | 0
+ 716 | 0
+ 717 | 0
+ 718 | 0
+ 719 | 0
+ 720 | 0
+ 721 | 0
+ 722 | 0
+ 723 | 0
+ 724 | 0
+ 725 | 0
+ 726 | 0
+ 727 | 0
+ 728 | 0
+ 729 | 0
+ 730 | 0
+ 731 | 0
+ 732 | 0
+ 733 | 0
+ 734 | 0
+ 735 | 0
+ 736 | 0
+ 737 | 0
+ 738 | 0
+ 739 | 0
+ 740 | 0
+ 741 | 0
+ 742 | 0
+ 743 | 0
+ 744 | 0
+ 745 | 0
+ 746 | 0
+ 747 | 0
+ 748 | 0
+ 749 | 0
+ 750 | 0
+ 751 | 0
+ 752 | 0
+ 753 | 0
+ 754 | 0
+ 755 | 0
+ 756 | 0
+ 757 | 0
+ 758 | 0
+ 759 | 0
+ 760 | 0
+ 761 | 0
+ 762 | 0
+ 763 | 0
+ 764 | 0
+ 765 | 0
+ 766 | 0
+ 767 | 0
+ 768 | 0
+ 769 | 0
+ 770 | 0
+ 771 | 0
+ 772 | 0
+ 773 | 0
+ 774 | 0
+ 775 | 0
+ 776 | 0
+ 777 | 0
+ 778 | 0
+ 779 | 0
+ 780 | 0
+ 781 | 0
+ 782 | 0
+ 783 | 0
+ 784 | 0
+ 785 | 0
+ 786 | 0
+ 787 | 0
+ 788 | 0
+ 789 | 0
+ 790 | 0
+ 791 | 0
+ 792 | 0
+ 793 | 0
+ 794 | 0
+ 795 | 0
+ 796 | 0
+ 797 | 0
+ 798 | 0
+ 799 | 0
+ 800 | 1
+ 801 | 0
+ 802 | 0
+ 803 | 0
+ 804 | 0
+ 805 | 0
+ 806 | 0
+ 807 | 0
+ 808 | 0
+ 809 | 0
+ 810 | 0
+ 811 | 0
+ 812 | 0
+ 813 | 0
+ 814 | 0
+ 815 | 0
+ 816 | 0
+ 817 | 0
+ 818 | 0
+ 819 | 0
+ 820 | 0
+ 821 | 0
+ 822 | 0
+ 823 | 0
+ 824 | 0
+ 825 | 0
+ 826 | 0
+ 827 | 0
+ 828 | 0
+ 829 | 0
+ 830 | 0
+ 831 | 0
+ 832 | 0
+ 833 | 0
+ 834 | 0
+ 835 | 0
+ 836 | 0
+ 837 | 0
+ 838 | 0
+ 839 | 0
+ 840 | 0
+ 841 | 0
+ 842 | 0
+ 843 | 0
+ 844 | 0
+ 845 | 0
+ 846 | 0
+ 847 | 0
+ 848 | 0
+ 849 | 0
+ 850 | 0
+ 851 | 0
+ 852 | 0
+ 853 | 0
+ 854 | 0
+ 855 | 0
+ 856 | 0
+ 857 | 0
+ 858 | 0
+ 859 | 0
+ 860 | 0
+ 861 | 0
+ 862 | 0
+ 863 | 0
+ 864 | 0
+ 865 | 0
+ 866 | 0
+ 867 | 0
+ 868 | 0
+ 869 | 0
+ 870 | 0
+ 871 | 0
+ 872 | 0
+ 873 | 0
+ 874 | 0
+ 875 | 0
+ 876 | 0
+ 877 | 0
+ 878 | 0
+ 879 | 0
+ 880 | 0
+ 881 | 0
+ 882 | 0
+ 883 | 0
+ 884 | 0
+ 885 | 0
+ 886 | 0
+ 887 | 0
+ 888 | 0
+ 889 | 0
+ 890 | 0
+ 891 | 0
+ 892 | 0
+ 893 | 0
+ 894 | 0
+ 895 | 0
+ 896 | 0
+ 897 | 0
+ 898 | 0
+ 899 | 0
+ 900 | 1
+ 901 | 0
+ 902 | 0
+ 903 | 0
+ 904 | 0
+ 905 | 0
+ 906 | 0
+ 907 | 0
+ 908 | 0
+ 909 | 0
+ 910 | 0
+ 911 | 0
+ 912 | 0
+ 913 | 0
+ 914 | 0
+ 915 | 0
+ 916 | 0
+ 917 | 0
+ 918 | 0
+ 919 | 0
+ 920 | 0
+ 921 | 0
+ 922 | 0
+ 923 | 0
+ 924 | 0
+ 925 | 0
+ 926 | 0
+ 927 | 0
+ 928 | 0
+ 929 | 0
+ 930 | 0
+ 931 | 0
+ 932 | 0
+ 933 | 0
+ 934 | 0
+ 935 | 0
+ 936 | 0
+ 937 | 0
+ 938 | 0
+ 939 | 0
+ 940 | 0
+ 941 | 0
+ 942 | 0
+ 943 | 0
+ 944 | 0
+ 945 | 0
+ 946 | 0
+ 947 | 0
+ 948 | 0
+ 949 | 0
+ 950 | 0
+ 951 | 0
+ 952 | 0
+ 953 | 0
+ 954 | 0
+ 955 | 0
+ 956 | 0
+ 957 | 0
+ 958 | 0
+ 959 | 0
+ 960 | 0
+ 961 | 0
+ 962 | 0
+ 963 | 0
+ 964 | 0
+ 965 | 0
+ 966 | 0
+ 967 | 0
+ 968 | 0
+ 969 | 0
+ 970 | 0
+ 971 | 0
+ 972 | 0
+ 973 | 0
+ 974 | 0
+ 975 | 0
+ 976 | 0
+ 977 | 0
+ 978 | 0
+ 979 | 0
+ 980 | 0
+ 981 | 0
+ 982 | 0
+ 983 | 0
+ 984 | 0
+ 985 | 0
+ 986 | 0
+ 987 | 0
+ 988 | 0
+ 989 | 0
+ 990 | 0
+ 991 | 0
+ 992 | 0
+ 993 | 0
+ 994 | 0
+ 995 | 0
+ 996 | 0
+ 997 | 0
+ 998 | 0
+ 999 | 0
+ 1000 | 1
+ 1010 | 0
+ 1020 | 0
+ 1030 | 0
+ 1040 | 0
+ 1050 | 0
+ 1060 | 0
+ 1070 | 0
+ 1080 | 0
+ 1090 | 0
+ 1100 | 1
+ 1110 | 0
+ 1120 | 0
+ 1130 | 0
+ 1140 | 0
+ 1150 | 0
+ 1160 | 0
+ 1170 | 0
+ 1180 | 0
+ 1190 | 0
+ 1200 | 1
+ 1210 | 0
+ 1220 | 0
+ 1230 | 0
+ 1240 | 0
+ 1250 | 0
+ 1260 | 0
+ 1270 | 0
+ 1280 | 0
+ 1290 | 0
+ 1300 | 1
+ 1310 | 0
+ 1320 | 0
+ 1330 | 0
+ 1340 | 0
+ 1350 | 0
+ 1360 | 0
+ 1370 | 0
+ 1380 | 0
+ 1390 | 0
+ 1400 | 1
+ 1410 | 0
+ 1420 | 0
+ 1430 | 0
+ 1440 | 0
+ 1450 | 0
+ 1460 | 0
+ 1470 | 0
+ 1480 | 0
+ 1490 | 0
+ 1500 | 1
+ 1510 | 0
+ 1520 | 0
+ 1530 | 0
+ 1540 | 0
+ 1550 | 0
+ 1560 | 0
+ 1570 | 0
+ 1580 | 0
+ 1590 | 0
+ 1600 | 1
+ 1610 | 0
+ 1620 | 0
+ 1630 | 0
+ 1640 | 0
+ 1650 | 0
+ 1660 | 0
+ 1670 | 0
+ 1680 | 0
+ 1690 | 0
+ 1700 | 1
+ 1710 | 0
+ 1720 | 0
+ 1730 | 0
+ 1740 | 0
+ 1750 | 0
+ 1760 | 0
+ 1770 | 0
+ 1780 | 0
+ 1790 | 0
+ 1800 | 1
+ 1810 | 0
+ 1820 | 0
+ 1830 | 0
+ 1840 | 0
+ 1850 | 0
+ 1860 | 0
+ 1870 | 0
+ 1880 | 0
+ 1890 | 0
+ 1900 | 1
+ 1910 | 0
+ 1920 | 0
+ 1930 | 0
+ 1940 | 0
+ 1950 | 0
+ 1960 | 0
+ 1970 | 0
+ 1980 | 0
+ 1990 | 0
+ 2000 | 1
+ 2010 | 0
+ 2020 | 0
+ 2030 | 0
+ 2040 | 0
+ 2050 | 0
+ 2060 | 0
+ 2070 | 0
+ 2080 | 0
+ 2090 | 0
+ 2100 | 1
+ 2110 | 0
+ 2120 | 0
+ 2130 | 0
+ 2140 | 0
+ 2150 | 0
+ 2160 | 0
+ 2170 | 0
+ 2180 | 0
+ 2190 | 0
+ 2200 | 1
+ 2210 | 0
+ 2220 | 0
+ 2230 | 0
+ 2240 | 0
+ 2250 | 0
+ 2260 | 0
+ 2270 | 0
+ 2280 | 0
+ 2290 | 0
+ 2300 | 1
+ 2310 | 0
+ 2320 | 0
+ 2330 | 0
+ 2340 | 0
+ 2350 | 0
+ 2360 | 0
+ 2370 | 0
+ 2380 | 0
+ 2390 | 0
+ 2400 | 1
+ 2410 | 0
+ 2420 | 0
+ 2430 | 0
+ 2440 | 0
+ 2450 | 0
+ 2460 | 0
+ 2470 | 0
+ 2480 | 0
+ 2490 | 0
+ 2500 | 1
+ 2510 | 0
+ 2520 | 0
+ 2530 | 0
+ 2540 | 0
+ 2550 | 0
+ 2560 | 0
+ 2570 | 0
+ 2580 | 0
+ 2590 | 0
+ 2600 | 1
+ 2610 | 0
+ 2620 | 0
+ 2630 | 0
+ 2640 | 0
+ 2650 | 0
+ 2660 | 0
+ 2670 | 0
+ 2680 | 0
+ 2690 | 0
+ 2700 | 1
+ 2710 | 0
+ 2720 | 0
+ 2730 | 0
+ 2740 | 0
+ 2750 | 0
+ 2760 | 0
+ 2770 | 0
+ 2780 | 0
+ 2790 | 0
+ 2800 | 1
+ 2810 | 0
+ 2820 | 0
+ 2830 | 0
+ 2840 | 0
+ 2850 | 0
+ 2860 | 0
+ 2870 | 0
+ 2880 | 0
+ 2890 | 0
+ 2900 | 1
+ 2910 | 0
+ 2920 | 0
+ 2930 | 0
+ 2940 | 0
+ 2950 | 0
+ 2960 | 0
+ 2970 | 0
+ 2980 | 0
+ 2990 | 0
+ 3000 | 1
+ 3010 | 0
+ 3020 | 0
+ 3030 | 0
+ 3040 | 0
+ 3050 | 0
+ 3060 | 0
+ 3070 | 0
+ 3080 | 0
+ 3090 | 0
+ 3100 | 1
+ 3110 | 0
+ 3120 | 0
+ 3130 | 0
+ 3140 | 0
+ 3150 | 0
+ 3160 | 0
+ 3170 | 0
+ 3180 | 0
+ 3190 | 0
+ 3200 | 1
+ 3210 | 0
+ 3220 | 0
+ 3230 | 0
+ 3240 | 0
+ 3250 | 0
+ 3260 | 0
+ 3270 | 0
+ 3280 | 0
+ 3290 | 0
+ 3300 | 1
+ 3310 | 0
+ 3320 | 0
+ 3330 | 0
+ 3340 | 0
+ 3350 | 0
+ 3360 | 0
+ 3370 | 0
+ 3380 | 0
+ 3390 | 0
+ 3400 | 1
+ 3410 | 0
+ 3420 | 0
+ 3430 | 0
+ 3440 | 0
+ 3450 | 0
+ 3460 | 0
+ 3470 | 0
+ 3480 | 0
+ 3490 | 0
+ 3500 | 1
+ 3510 | 0
+ 3520 | 0
+ 3530 | 0
+ 3540 | 0
+ 3550 | 0
+ 3560 | 0
+ 3570 | 0
+ 3580 | 0
+ 3590 | 0
+ 3600 | 1
+ 3610 | 0
+ 3620 | 0
+ 3630 | 0
+ 3640 | 0
+ 3650 | 0
+ 3660 | 0
+ 3670 | 0
+ 3680 | 0
+ 3690 | 0
+ 3700 | 1
+ 3710 | 0
+ 3720 | 0
+ 3730 | 0
+ 3740 | 0
+ 3750 | 0
+ 3760 | 0
+ 3770 | 0
+ 3780 | 0
+ 3790 | 0
+ 3800 | 1
+ 3810 | 0
+ 3820 | 0
+ 3830 | 0
+ 3840 | 0
+ 3850 | 0
+ 3860 | 0
+ 3870 | 0
+ 3880 | 0
+ 3890 | 0
+ 3900 | 1
+ 3910 | 0
+ 3920 | 0
+ 3930 | 0
+ 3940 | 0
+ 3950 | 0
+ 3960 | 0
+ 3970 | 0
+ 3980 | 0
+ 3990 | 0
+ 4000 | 1
+ 4010 | 0
+ 4020 | 0
+ 4030 | 0
+ 4040 | 0
+ 4050 | 0
+ 4060 | 0
+ 4070 | 0
+ 4080 | 0
+ 4090 | 0
+ 4100 | 1
+ 4110 | 0
+ 4120 | 0
+ 4130 | 0
+ 4140 | 0
+ 4150 | 0
+ 4160 | 0
+ 4170 | 0
+ 4180 | 0
+ 4190 | 0
+ 4200 | 1
+ 4210 | 0
+ 4220 | 0
+ 4230 | 0
+ 4240 | 0
+ 4250 | 0
+ 4260 | 0
+ 4270 | 0
+ 4280 | 0
+ 4290 | 0
+ 4300 | 1
+ 4310 | 0
+ 4320 | 0
+ 4330 | 0
+ 4340 | 0
+ 4350 | 0
+ 4360 | 0
+ 4370 | 0
+ 4380 | 0
+ 4390 | 0
+ 4400 | 1
+ 4410 | 0
+ 4420 | 0
+ 4430 | 0
+ 4440 | 0
+ 4450 | 0
+ 4460 | 0
+ 4470 | 0
+ 4480 | 0
+ 4490 | 0
+ 4500 | 1
+ 4510 | 0
+ 4520 | 0
+ 4530 | 0
+ 4540 | 0
+ 4550 | 0
+ 4560 | 0
+ 4570 | 0
+ 4580 | 0
+ 4590 | 0
+ 4600 | 1
+ 4610 | 0
+ 4620 | 0
+ 4630 | 0
+ 4640 | 0
+ 4650 | 0
+ 4660 | 0
+ 4670 | 0
+ 4680 | 0
+ 4690 | 0
+ 4700 | 1
+ 4710 | 0
+ 4720 | 0
+ 4730 | 0
+ 4740 | 0
+ 4750 | 0
+ 4760 | 0
+ 4770 | 0
+ 4780 | 0
+ 4790 | 0
+ 4800 | 1
+ 4810 | 0
+ 4820 | 0
+ 4830 | 0
+ 4840 | 0
+ 4850 | 0
+ 4860 | 0
+ 4870 | 0
+ 4880 | 0
+ 4890 | 0
+ 4900 | 1
+ 4910 | 0
+ 4920 | 0
+ 4930 | 0
+ 4940 | 0
+ 4950 | 0
+ 4960 | 0
+ 4970 | 0
+ 4980 | 0
+ 4990 | 0
+ 5000 | 1
+ 5010 | 0
+ 5020 | 0
+ 5030 | 0
+ 5040 | 0
+ 5050 | 0
+ 5060 | 0
+ 5070 | 0
+ 5080 | 0
+ 5090 | 0
+ 5100 | 1
+ 5110 | 0
+ 5120 | 0
+ 5130 | 0
+ 5140 | 0
+ 5150 | 0
+ 5160 | 0
+ 5170 | 0
+ 5180 | 0
+ 5190 | 0
+ 5200 | 1
+ 5210 | 0
+ 5220 | 0
+ 5230 | 0
+ 5240 | 0
+ 5250 | 0
+ 5260 | 0
+ 5270 | 0
+ 5280 | 0
+ 5290 | 0
+ 5300 | 1
+ 5310 | 0
+ 5320 | 0
+ 5330 | 0
+ 5340 | 0
+ 5350 | 0
+ 5360 | 0
+ 5370 | 0
+ 5380 | 0
+ 5390 | 0
+ 5400 | 1
+ 5410 | 0
+ 5420 | 0
+ 5430 | 0
+ 5440 | 0
+ 5450 | 0
+ 5460 | 0
+ 5470 | 0
+ 5480 | 0
+ 5490 | 0
+ 5500 | 1
+ 5510 | 0
+ 5520 | 0
+ 5530 | 0
+ 5540 | 0
+ 5550 | 0
+ 5560 | 0
+ 5570 | 0
+ 5580 | 0
+ 5590 | 0
+ 5600 | 1
+ 5610 | 0
+ 5620 | 0
+ 5630 | 0
+ 5640 | 0
+ 5650 | 0
+ 5660 | 0
+ 5670 | 0
+ 5680 | 0
+ 5690 | 0
+ 5700 | 1
+ 5710 | 0
+ 5720 | 0
+ 5730 | 0
+ 5740 | 0
+ 5750 | 0
+ 5760 | 0
+ 5770 | 0
+ 5780 | 0
+ 5790 | 0
+ 5800 | 1
+ 5810 | 0
+ 5820 | 0
+ 5830 | 0
+ 5840 | 0
+ 5850 | 0
+ 5860 | 0
+ 5870 | 0
+ 5880 | 0
+ 5890 | 0
+ 5900 | 1
+ 5910 | 0
+ 5920 | 0
+ 5930 | 0
+ 5940 | 0
+ 5950 | 0
+ 5960 | 0
+ 5970 | 0
+ 5980 | 0
+ 5990 | 0
+ 6000 | 1
+ 6010 | 0
+ 6020 | 0
+ 6030 | 0
+ 6040 | 0
+ 6050 | 0
+ 6060 | 0
+ 6070 | 0
+ 6080 | 0
+ 6090 | 0
+ 6100 | 1
+ 6110 | 0
+ 6120 | 0
+ 6130 | 0
+ 6140 | 0
+ 6150 | 0
+ 6160 | 0
+ 6170 | 0
+ 6180 | 0
+ 6190 | 0
+ 6200 | 1
+ 6210 | 0
+ 6220 | 0
+ 6230 | 0
+ 6240 | 0
+ 6250 | 0
+ 6260 | 0
+ 6270 | 0
+ 6280 | 0
+ 6290 | 0
+ 6300 | 1
+ 6310 | 0
+ 6320 | 0
+ 6330 | 0
+ 6340 | 0
+ 6350 | 0
+ 6360 | 0
+ 6370 | 0
+ 6380 | 0
+ 6390 | 0
+ 6400 | 1
+ 6410 | 0
+ 6420 | 0
+ 6430 | 0
+ 6440 | 0
+ 6450 | 0
+ 6460 | 0
+ 6470 | 0
+ 6480 | 0
+ 6490 | 0
+ 6500 | 1
+ 6510 | 0
+ 6520 | 0
+ 6530 | 0
+ 6540 | 0
+ 6550 | 0
+ 6560 | 0
+ 6570 | 0
+ 6580 | 0
+ 6590 | 0
+ 6600 | 1
+ 6610 | 0
+ 6620 | 0
+ 6630 | 0
+ 6640 | 0
+ 6650 | 0
+ 6660 | 0
+ 6670 | 0
+ 6680 | 0
+ 6690 | 0
+ 6700 | 1
+ 6710 | 0
+ 6720 | 0
+ 6730 | 0
+ 6740 | 0
+ 6750 | 0
+ 6760 | 0
+ 6770 | 0
+ 6780 | 0
+ 6790 | 0
+ 6800 | 1
+ 6810 | 0
+ 6820 | 0
+ 6830 | 0
+ 6840 | 0
+ 6850 | 0
+ 6860 | 0
+ 6870 | 0
+ 6880 | 0
+ 6890 | 0
+ 6900 | 1
+ 6910 | 0
+ 6920 | 0
+ 6930 | 0
+ 6940 | 0
+ 6950 | 0
+ 6960 | 0
+ 6970 | 0
+ 6980 | 0
+ 6990 | 0
+ 7000 | 1
+ 7010 | 0
+ 7020 | 0
+ 7030 | 0
+ 7040 | 0
+ 7050 | 0
+ 7060 | 0
+ 7070 | 0
+ 7080 | 0
+ 7090 | 0
+ 7100 | 1
+ 7110 | 0
+ 7120 | 0
+ 7130 | 0
+ 7140 | 0
+ 7150 | 0
+ 7160 | 0
+ 7170 | 0
+ 7180 | 0
+ 7190 | 0
+ 7200 | 1
+ 7210 | 0
+ 7220 | 0
+ 7230 | 0
+ 7240 | 0
+ 7250 | 0
+ 7260 | 0
+ 7270 | 0
+ 7280 | 0
+ 7290 | 0
+ 7300 | 1
+ 7310 | 0
+ 7320 | 0
+ 7330 | 0
+ 7340 | 0
+ 7350 | 0
+ 7360 | 0
+ 7370 | 0
+ 7380 | 0
+ 7390 | 0
+ 7400 | 1
+ 7410 | 0
+ 7420 | 0
+ 7430 | 0
+ 7440 | 0
+ 7450 | 0
+ 7460 | 0
+ 7470 | 0
+ 7480 | 0
+ 7490 | 0
+ 7500 | 1
+ 7510 | 0
+ 7520 | 0
+ 7530 | 0
+ 7540 | 0
+ 7550 | 0
+ 7560 | 0
+ 7570 | 0
+ 7580 | 0
+ 7590 | 0
+ 7600 | 1
+ 7610 | 0
+ 7620 | 0
+ 7630 | 0
+ 7640 | 0
+ 7650 | 0
+ 7660 | 0
+ 7670 | 0
+ 7680 | 0
+ 7690 | 0
+ 7700 | 1
+ 7710 | 0
+ 7720 | 0
+ 7730 | 0
+ 7740 | 0
+ 7750 | 0
+ 7760 | 0
+ 7770 | 0
+ 7780 | 0
+ 7790 | 0
+ 7800 | 1
+ 7810 | 0
+ 7820 | 0
+ 7830 | 0
+ 7840 | 0
+ 7850 | 0
+ 7860 | 0
+ 7870 | 0
+ 7880 | 0
+ 7890 | 0
+ 7900 | 1
+ 7910 | 0
+ 7920 | 0
+ 7930 | 0
+ 7940 | 0
+ 7950 | 0
+ 7960 | 0
+ 7970 | 0
+ 7980 | 0
+ 7990 | 0
+ 8000 | 1
+ 8010 | 0
+ 8020 | 0
+ 8030 | 0
+ 8040 | 0
+ 8050 | 0
+ 8060 | 0
+ 8070 | 0
+ 8080 | 0
+ 8090 | 0
+ 8100 | 1
+ 8110 | 0
+ 8120 | 0
+ 8130 | 0
+ 8140 | 0
+ 8150 | 0
+ 8160 | 0
+ 8170 | 0
+ 8180 | 0
+ 8190 | 0
+ 8200 | 1
+ 8210 | 0
+ 8220 | 0
+ 8230 | 0
+ 8240 | 0
+ 8250 | 0
+ 8260 | 0
+ 8270 | 0
+ 8280 | 0
+ 8290 | 0
+ 8300 | 1
+ 8310 | 0
+ 8320 | 0
+ 8330 | 0
+ 8340 | 0
+ 8350 | 0
+ 8360 | 0
+ 8370 | 0
+ 8380 | 0
+ 8390 | 0
+ 8400 | 1
+ 8410 | 0
+ 8420 | 0
+ 8430 | 0
+ 8440 | 0
+ 8450 | 0
+ 8460 | 0
+ 8470 | 0
+ 8480 | 0
+ 8490 | 0
+ 8500 | 1
+ 8510 | 0
+ 8520 | 0
+ 8530 | 0
+ 8540 | 0
+ 8550 | 0
+ 8560 | 0
+ 8570 | 0
+ 8580 | 0
+ 8590 | 0
+ 8600 | 1
+ 8610 | 0
+ 8620 | 0
+ 8630 | 0
+ 8640 | 0
+ 8650 | 0
+ 8660 | 0
+ 8670 | 0
+ 8680 | 0
+ 8690 | 0
+ 8700 | 1
+ 8710 | 0
+ 8720 | 0
+ 8730 | 0
+ 8740 | 0
+ 8750 | 0
+ 8760 | 0
+ 8770 | 0
+ 8780 | 0
+ 8790 | 0
+ 8800 | 1
+ 8810 | 0
+ 8820 | 0
+ 8830 | 0
+ 8840 | 0
+ 8850 | 0
+ 8860 | 0
+ 8870 | 0
+ 8880 | 0
+ 8890 | 0
+ 8900 | 1
+ 8910 | 0
+ 8920 | 0
+ 8930 | 0
+ 8940 | 0
+ 8950 | 0
+ 8960 | 0
+ 8970 | 0
+ 8980 | 0
+ 8990 | 0
+ 9000 | 1
+ 9010 | 0
+ 9020 | 0
+ 9030 | 0
+ 9040 | 0
+ 9050 | 0
+ 9060 | 0
+ 9070 | 0
+ 9080 | 0
+ 9090 | 0
+ 9100 | 1
+ 9110 | 0
+ 9120 | 0
+ 9130 | 0
+ 9140 | 0
+ 9150 | 0
+ 9160 | 0
+ 9170 | 0
+ 9180 | 0
+ 9190 | 0
+ 9200 | 1
+ 9210 | 0
+ 9220 | 0
+ 9230 | 0
+ 9240 | 0
+ 9250 | 0
+ 9260 | 0
+ 9270 | 0
+ 9280 | 0
+ 9290 | 0
+ 9300 | 1
+ 9310 | 0
+ 9320 | 0
+ 9330 | 0
+ 9340 | 0
+ 9350 | 0
+ 9360 | 0
+ 9370 | 0
+ 9380 | 0
+ 9390 | 0
+ 9400 | 1
+ 9410 | 0
+ 9420 | 0
+ 9430 | 0
+ 9440 | 0
+ 9450 | 0
+ 9460 | 0
+ 9470 | 0
+ 9480 | 0
+ 9490 | 0
+ 9500 | 1
+ 9510 | 0
+ 9520 | 0
+ 9530 | 0
+ 9540 | 0
+ 9550 | 0
+ 9560 | 0
+ 9570 | 0
+ 9580 | 0
+ 9590 | 0
+ 9600 | 1
+ 9610 | 0
+ 9620 | 0
+ 9630 | 0
+ 9640 | 0
+ 9650 | 0
+ 9660 | 0
+ 9670 | 0
+ 9680 | 0
+ 9690 | 0
+ 9700 | 1
+ 9710 | 0
+ 9720 | 0
+ 9730 | 0
+ 9740 | 0
+ 9750 | 0
+ 9760 | 0
+ 9770 | 0
+ 9780 | 0
+ 9790 | 0
+ 9800 | 1
+ 9810 | 0
+ 9820 | 0
+ 9830 | 0
+ 9840 | 0
+ 9850 | 0
+ 9860 | 0
+ 9870 | 0
+ 9880 | 0
+ 9890 | 0
+ 9900 | 1
+ 9910 | 0
+ 9920 | 0
+ 9930 | 0
+ 9940 | 0
+ 9950 | 0
+ 9960 | 0
+ 9970 | 0
+ 9980 | 0
+ 9990 | 0
+ 10000 | 1
+ 10100 | 1
+ 10200 | 0
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.trunc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.trunc.d
new file mode 100644
index 000000000000..e3db03002c46
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.trunc.d
@@ -0,0 +1,49 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+int i;
+
+tick-10ms
+/i < 100/
+{
+ @[i] = llquantize(i, 10, 1, 2, 10, 150);
+ @[i] = llquantize(i + 1, 10, 1, 2, 10, 150);
+ @[i] = llquantize(i + 2, 10, 1, 2, 10, 150);
+ @[i] = llquantize(i + 3, 10, 1, 2, 10, 150);
+ i++;
+}
+
+tick-10ms
+/i == 100/
+{
+ exit(0);
+}
+
+END
+{
+ trunc(@, 5);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.trunc.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.trunc.d.out
new file mode 100644
index 000000000000..941c62679b07
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/llquantize/tst.trunc.d.out
@@ -0,0 +1,34 @@
+
+ 95
+ value ------------- Distribution ------------- count
+ 80 | 0
+ 90 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 600
+ 100 | 0
+
+ 96
+ value ------------- Distribution ------------- count
+ 80 | 0
+ 90 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 600
+ 100 | 0
+
+ 97
+ value ------------- Distribution ------------- count
+ 80 | 0
+ 90 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 450
+ 100 |@@@@@@@@@@ 150
+ 200 | 0
+
+ 98
+ value ------------- Distribution ------------- count
+ 80 | 0
+ 90 |@@@@@@@@@@@@@@@@@@@@ 300
+ 100 |@@@@@@@@@@@@@@@@@@@@ 300
+ 200 | 0
+
+ 99
+ value ------------- Distribution ------------- count
+ 80 | 0
+ 90 |@@@@@@@@@@ 150
+ 100 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 450
+ 200 | 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mdb/tst.dtracedcmd.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mdb/tst.dtracedcmd.ksh
new file mode 100644
index 000000000000..561f8549d924
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mdb/tst.dtracedcmd.ksh
@@ -0,0 +1,85 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# This script primarily tests that the ::dtrace dcmd is not dumping
+# core. We don't try to make sense of the output of the dcmd nor
+# do we check to see if any output is produced. We merely see if
+# mdb fails with a fatal failure.
+#
+
+script()
+{
+ $dtrace -o $dtraceout -s /dev/stdin <<EOF
+ syscall:::entry
+ {
+ @[probefunc] = count();
+ }
+EOF
+}
+
+mdbdoit()
+{
+ mdb -k <<EOF
+ ::walk dtrace_state | ::dtrace
+EOF
+ status=$?
+ kill $script
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+dtraceout=/tmp/dtrace.out.$$
+script &
+script=$!
+timeout=15
+
+#
+# Sleep while the above script fires into life. To guard against dtrace dying
+# and us sleeping forever we allow 15 secs for this to happen. This should be
+# enough for even the slowest systems.
+#
+while [ ! -f $dtraceout ]; do
+ sleep 1
+ timeout=$(($timeout-1))
+ if [ $timeout -eq 0 ]; then
+ echo "dtrace failed to start. Exiting."
+ exit 1
+ fi
+done
+
+mdbdoit
+
+rm $dtraceout
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.icmp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.icmp.ksh
new file mode 100644
index 000000000000..b1cac20fc8db
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.icmp.ksh
@@ -0,0 +1,79 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that several of the the mib:::icmp* probes fire and fire
+# with a valid args[0].
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ mib:::icmpInEchos
+ {
+ in = args[0];
+ }
+
+ mib:::icmpOutEchoReps
+ {
+ reps = args[0];
+ }
+
+ mib:::icmpOutMsgs
+ {
+ msgs = args[0];
+ }
+
+ profile:::tick-10msec
+ /in && reps && msgs/
+ {
+ exit(0);
+ }
+EOF
+}
+
+pinger()
+{
+ while true; do
+ ping -A inet localhost
+ /usr/bin/sleep 1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+pinger &
+pinger=$!
+script
+status=$?
+
+kill $pinger
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.tcp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.tcp.ksh
new file mode 100644
index 000000000000..ee602e86112c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.tcp.ksh
@@ -0,0 +1,155 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that several of the the mib:::tcp* probes fire and fire
+# with a valid args[0].
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+dtraceout=/tmp/dtrace.out.$$
+timeout=15
+port=2000
+
+if [ -f $dtraceout ]; then
+ rm -f $dtraceout
+fi
+
+script()
+{
+ $dtrace -o $dtraceout -s /dev/stdin <<EOF
+ mib:::tcpActiveOpens
+ {
+ opens = args[0];
+ }
+
+ mib:::tcpOutDataBytes
+ {
+ bytes = args[0];
+ }
+
+ mib:::tcpOutDataSegs
+ {
+ segs = args[0];
+ }
+
+ profile:::tick-10msec
+ /opens && bytes && segs/
+ {
+ exit(0);
+ }
+
+ profile:::tick-1s
+ /n++ >= 10/
+ {
+ exit(1);
+ }
+EOF
+}
+
+server()
+{
+ perl /dev/stdin /dev/stdout << EOF
+ use strict;
+ use Socket;
+
+ socket(S, AF_INET, SOCK_STREAM, getprotobyname('tcp'))
+ or die "socket() failed: \$!";
+
+ setsockopt(S, SOL_SOCKET, SO_REUSEADDR, 1)
+ or die "setsockopt() failed: \$!";
+
+ my \$addr = sockaddr_in($port, INADDR_ANY);
+ bind(S, \$addr) or die "bind() failed: \$!";
+ listen(S, SOMAXCONN) or die "listen() failed: \$!";
+
+ while (1) {
+ next unless my \$raddr = accept(SESSION, S);
+
+ while (<SESSION>) {
+ }
+
+ close SESSION;
+ }
+EOF
+}
+
+client()
+{
+ perl /dev/stdin /dev/stdout <<EOF
+ use strict;
+ use Socket;
+
+ my \$peer = sockaddr_in($port, INADDR_ANY);
+
+ socket(S, AF_INET, SOCK_STREAM, getprotobyname('tcp'))
+ or die "socket() failed: \$!";
+
+ connect(S, \$peer) or die "connect failed: \$!";
+
+ for (my \$i = 0; \$i < 10; \$i++) {
+ send(S, "There!", 0) or die "send() failed: \$!";
+ sleep (1);
+ }
+EOF
+}
+
+script &
+dtrace_pid=$!
+
+#
+# Sleep while the above script fires into life. To guard against dtrace dying
+# and us sleeping forever we allow 15 secs for this to happen. This should be
+# enough for even the slowest systems.
+#
+while [ ! -f $dtraceout ]; do
+ sleep 1
+ timeout=$(($timeout-1))
+ if [ $timeout -eq 0 ]; then
+ echo "dtrace failed to start. Exiting."
+ exit 1
+ fi
+done
+
+server &
+server_pid=$!
+sleep 2
+client &
+client_pid=$!
+
+wait $dtrace_pid
+status=$?
+
+kill $server_pid
+kill $client_pid
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.udp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.udp.ksh
new file mode 100644
index 000000000000..a492124c9c17
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/mib/tst.udp.ksh
@@ -0,0 +1,74 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that several of the the mib:::udp* probes fire and fire
+# with a valid args[0].
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ mib:::udpHCOutDatagrams
+ {
+ out = args[0];
+ }
+
+ mib:::udpHCInDatagrams
+ {
+ in = args[0];
+ }
+
+ profile:::tick-10msec
+ /in && out/
+ {
+ exit(0);
+ }
+EOF
+}
+
+rupper()
+{
+ while true; do
+ rup localhost
+ /usr/bin/sleep 1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+rupper &
+rupper=$!
+script
+status=$?
+
+kill $rupper
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/err.D_PRAGMA_OPTSET.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/err.D_PRAGMA_OPTSET.d
new file mode 100644
index 000000000000..5238e3f3b1ce
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/err.D_PRAGMA_OPTSET.d
@@ -0,0 +1,34 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet=please
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.badopt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.badopt.d
new file mode 100644
index 000000000000..868b756f61d2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.badopt.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ setopt("Nixon");
+ setopt("Harding");
+ setopt("Hoover");
+ setopt("Bush");
+ setopt("quiet", "hell no");
+ setopt("aggrate", "0.5hz");
+ setopt("bufsize", "1m");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.boolopt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.boolopt.d
new file mode 100644
index 000000000000..0755271f7672
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.boolopt.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet=yes
+#pragma D option quiet=YES
+#pragma D option quiet=true
+#pragma D option quiet=enable
+#pragma D option quiet=enabled
+#pragma D option quiet=on
+#pragma D option quiet=set
+#pragma D option quiet=SeT
+
+#pragma D option flowindent=no
+#pragma D option flowindent=NO
+#pragma D option flowindent=false
+#pragma D option flowindent=disable
+#pragma D option flowindent=disabled
+#pragma D option flowindent=off
+#pragma D option flowindent=UnSeT
+
+BEGIN
+{
+ printf(".lived eht si paTmetsyS, lived eht si paTmetsyS\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.boolopt.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.boolopt.d.out
new file mode 100644
index 000000000000..2554be5cd397
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.boolopt.d.out
@@ -0,0 +1,2 @@
+.lived eht si paTmetsyS, lived eht si paTmetsyS
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dofmax.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dofmax.ksh
new file mode 100644
index 000000000000..22c267dcfc39
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dofmax.ksh
@@ -0,0 +1,97 @@
+#
+# 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 (c) 2012, Joyent, Inc. All rights reserved.
+#
+
+let j=8
+
+enable()
+{
+ prog=/var/tmp/dtest.$$.d
+ err=/var/tmp/dtest.$$.err
+
+ nawk -v nprobes=$1 'BEGIN { \
+ for (i = 0; i < nprobes - 1; i++) { \
+ printf("dtrace:::BEGIN,\n"); \
+ } \
+ \
+ printf("dtrace:::BEGIN { exit(0); }\n"); \
+ }' /dev/null > $prog
+
+ dtrace -qs $prog > /dev/null 2> $err
+
+ if [[ "$?" -eq 0 ]]; then
+ return 0
+ else
+ if ! grep "DIF program exceeds maximum program size" $err \
+ 1> /dev/null 2>&1 ; then
+ echo "failed to enable $prog: `cat $err`"
+ exit 1
+ fi
+
+ return 1
+ fi
+}
+
+#
+# First, establish an upper bound
+#
+let upper=1
+
+while enable $upper ; do
+ let lower=upper
+ let upper=upper+upper
+ echo success at $lower, raised to $upper
+done
+
+#
+# Now search for the highest value that can be enabled
+#
+while [[ "$lower" -lt "$upper" ]]; do
+ let guess=$(((lower + upper) / 2))
+ echo "lower is $lower; upper is $upper; guess is $guess\c"
+
+ if enable $guess ; then
+ if [[ $((upper - lower)) -le 2 ]]; then
+ let upper=guess
+ fi
+
+ echo " (success)"
+ let lower=guess
+ else
+ echo " (failure)"
+ let upper=guess
+ fi
+done
+
+let expected=10000
+
+if [[ "$lower" -lt "$expected" ]]; then
+ echo "expected support for enablings of at least $expected probes; \c"
+ echo "found $lower"
+ exit 1
+fi
+
+echo "maximum supported enabled probes found to be $lower"
+exit 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dynopt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dynopt.d
new file mode 100644
index 000000000000..cb98d73375c1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dynopt.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+#pragma D option switchrate=1ms
+#pragma D option aggrate=1ms
+
+tick-100ms
+{
+ i++;
+}
+
+tick-100ms
+/i > 1/
+{
+ setopt("quiet", "no");
+ setopt("quiet");
+ setopt("quiet");
+ setopt("quiet", "yes");
+ @["abc"] = count();
+ printa("%@d\n", @);
+}
+
+tick-100ms
+/i == 5/
+{
+ setopt("switchrate", "5sec");
+ setopt("aggrate", "5sec");
+}
+
+tick-100ms
+/i == 31/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dynopt.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dynopt.d.out
new file mode 100644
index 000000000000..092a0426f7f3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dynopt.d.out
@@ -0,0 +1,31 @@
+1
+2
+3
+4
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+30
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.enablerace.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.enablerace.ksh
new file mode 100644
index 000000000000..b4d56bb6eedd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.enablerace.ksh
@@ -0,0 +1,89 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script attempts to tease out a race when probes are initially enabled.
+#
+script()
+{
+ #
+ # Nauseatingly, the #defines below must be in the 0th column to
+ # satisfy the ancient cpp that -C defaults to.
+ #
+ $dtrace -C -s /dev/stdin <<EOF
+#define PROF1 profile:::profile-4000hz
+#define PROF4 PROF1, PROF1, PROF1, PROF1
+#define PROF16 PROF4, PROF4, PROF4, PROF4
+#define PROF64 PROF16, PROF16, PROF16, PROF16
+#define PROF256 PROF64, PROF64, PROF64, PROF64
+#define PROF512 PROF256, PROF256
+
+ PROF1
+ {
+ this->x = 0;
+ }
+
+ PROF512
+ {
+ this->x++;
+ }
+
+ PROF1
+ /this->x != 512/
+ {
+ printf("failed! x is %d (expected 512)", this->x);
+ exit(1);
+ }
+
+ tick-1sec
+ /secs++/
+ {
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+let i=0
+
+while [ "$i" -lt 20 ]; do
+ script
+ status=$?
+
+ if [ "$status" -ne 0 ]; then
+ exit $status
+ fi
+
+ let i=i+1
+done
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.haslam.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.haslam.d
new file mode 100644
index 000000000000..a0b437b4efaa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.haslam.d
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: test for off-by-one error in the format lookup code
+ *
+ * SECTION: Aggregations/Aggregations; Misc
+ */
+
+/*
+ * A script from Jon Haslam that induced an off-by-one error in the
+ * format lookup code.
+ */
+BEGIN
+{
+ start = timestamp;
+ allocd = 0;
+ numallocs = 0;
+ numfrees = 0;
+ numtids = 0;
+}
+
+syscall:::entry
+{
+ @sys[tid] = sum(tid);
+}
+
+END
+{
+ printf("%s, %s, %s, %d numtids", "hhh", "jjj", "ggg", numtids );
+ printa(@sys);
+}
+
+tick-1sec
+/n++ == 5/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.include.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.include.ksh
new file mode 100644
index 000000000000..9aa0f68bfc86
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.include.ksh
@@ -0,0 +1,129 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+CFLAGS=
+
+doit()
+{
+ file=$1
+ ofile=$2
+ errfile=$3
+ cfile=${TMPDIR:-/tmp}/inc.$$.$file.c
+ cofile=${TMPDIR:-/tmp}/inc.$$.$file
+ cat > $cfile <<EOF
+#include <sys/$file>
+void
+main()
+{}
+EOF
+ if cc $CFLAGS -o $cofile $cfile >/dev/null 2>&1; then
+ $dtrace -xerrtags -C -s /dev/stdin \
+ >/dev/null 2>$errfile <<EOF
+#include <sys/$file>
+BEGIN
+{
+ exit(0);
+}
+EOF
+ if [ $? -ne 0 ]; then
+ echo $inc failed: `cat $errfile | head -1` > $ofile
+ else
+ echo $inc succeeded > $ofile
+ fi
+ rm -f $errfile
+ fi
+
+ rm -f $cofile $cfile 2>/dev/null
+}
+
+concurrency=`psrinfo | wc -l`
+let concurrency=concurrency*4
+let i=0
+
+files=/usr/include/sys/*.h
+
+#
+# There are a few files in /usr/include/sys that are known to be bad -- usually
+# because they include static globals (!) or function bodies (!!) in the header
+# file. Hopefully these remain sufficiently few that the O(#files * #badfiles)
+# algorithm, below, doesn't become a problem. (And yes, writing scripts in
+# something other than ksh1888 would probably be a good idea.) If this script
+# becomes a problem, kindly fix it by reducing the number of bad files! (That
+# is, fix it by fixing the broken file, not the broken script.)
+#
+badfiles="ctype.h eri_msg.h ser_sync.h sbpro.h neti.h hook_event.h \
+ bootconf.h bootstat.h dtrace.h dumphdr.h exacct_impl.h fasttrap.h \
+ kobj.h kobj_impl.h ksyms.h lockstat.h smedia.h stat.h utsname.h"
+
+for inc in $files; do
+ file=`basename $inc`
+ for bad in $badfiles; do
+ if [ "$file" = "$bad" ]; then
+ continue 2
+ fi
+ done
+
+ ofile=${TMPDIR:-/tmp}/inc.$file.$$.out
+ errfile=${TMPDIR:-/tmp}/inc.$file.$$.err
+ doit $file $ofile $errfile &
+ let i=i+1
+
+ if [ $i -eq $concurrency ]; then
+ #
+ # This isn't optimal -- it creates a highly fluctuating load
+ # as we wait for all work to complete -- but it's an easy
+ # way of parallelizing work.
+ #
+ wait
+ let i=0
+ fi
+done
+
+wait
+
+bigofile=${TMPDIR:-/tmp}/inc.$$.out
+
+for inc in $files; do
+ file=`basename $inc`
+ ofile=${TMPDIR:-/tmp}/inc.$file.$$.out
+
+ if [ -f $ofile ]; then
+ cat $ofile >> $bigofile
+ rm $ofile
+ fi
+done
+
+status=$(grep "failed:" $bigofile | wc -l)
+cat $bigofile
+rm -f $bigofile
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.macroglob.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.macroglob.ksh
new file mode 100644
index 000000000000..1afc62159a35
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.macroglob.ksh
@@ -0,0 +1,42 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -ln 'syscall:freebsd:*$1:entry' read | \
+ awk '{print $(NF-1),$NF}' | grep -v -E 'compat.\.' | sort
+$dtrace -ln 'syscall:freebsd:$1*:entry' read | awk '{print $(NF-1),$NF}' | sort
+$dtrace -ln 'syscall:freebsd:re$1*:entry' ad | awk '{print $(NF-1),$NF}' | sort
+$dtrace -ln 'syscall:freebsd:$1l*:entry' read | awk '{print $(NF-1),$NF}' | sort
+$dtrace -ln 'syscall:freebsd:w$1[0-9]:entry' ait | \
+ awk '{print $(NF-1),$NF}' | sort
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.macroglob.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.macroglob.ksh.out
new file mode 100644
index 000000000000..db7134cefe77
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.macroglob.ksh.out
@@ -0,0 +1,22 @@
+FUNCTION NAME
+aio_read entry
+obs_vread entry
+pread entry
+read entry
+rtprio_thread entry
+FUNCTION NAME
+read entry
+readlink entry
+readlinkat entry
+readv entry
+FUNCTION NAME
+read entry
+readlink entry
+readlinkat entry
+readv entry
+FUNCTION NAME
+readlink entry
+readlinkat entry
+FUNCTION NAME
+wait4 entry
+wait6 entry
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.roch.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.roch.d
new file mode 100644
index 000000000000..cf209efbab1f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.roch.d
@@ -0,0 +1,93 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: test for assertion failure in the ring buffer code
+ *
+ * SECTION: Buffers and Buffering/ring Policy; Misc
+ */
+
+#pragma ident "@(#)tst.roch.d 1.2 03/08/11 SMI"
+
+/*
+ * A script from Roch Bourbonnais that induced an assertion failure in the
+ * ring buffer code.
+ */
+#pragma D option strsize=16
+#pragma D option bufsize=10K
+#pragma D option bufpolicy=ring
+
+fbt:::entry
+/(self->done == 0) && (curthread->t_cpu->cpu_intr_actv == 0) /
+{
+ self->done = 1;
+ printf(" %u 0x%llX %d %d comm:%s csathr:%lld", timestamp,
+ (long long)curthread, pid, tid,
+ execname, (long long)stackdepth);
+ stack(20);
+}
+
+fbt:::return
+/(self->done == 0) && (curthread->t_cpu->cpu_intr_actv == 0) /
+{
+ self->done = 1;
+ printf(" %u 0x%llX %d %d comm:%s csathr:%lld", timestamp,
+ (long long) curthread, pid, tid,
+ execname, (long long) stackdepth);
+ stack(20);
+}
+
+fbt:::entry
+{
+ printf(" %u 0x%llX %d %d ", timestamp,
+ (long long)curthread, pid, tid);
+}
+
+fbt:::return
+{
+ printf(" %u 0x%llX %d %d tag:%d off:%d ", timestamp,
+ (long long)curthread, pid, tid, (int)arg1, (int)arg0);
+}
+
+mtx_lock:adaptive-acquire
+{
+ printf(" %u 0x%llX %d %d lock:0x%llX", timestamp,
+ (long long)curthread, pid, tid, arg0);
+}
+
+mtx_unlock:adaptive-release
+{
+ printf(" %u 0x%llX %d %d lock:0x%llX", timestamp,
+ (long long) curthread, pid, tid, arg0);
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.schrock.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.schrock.ksh
new file mode 100644
index 000000000000..197bd8dd5f32
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.schrock.ksh
@@ -0,0 +1,79 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+#
+# /usr/ccs/bin/nm execs a 64-bit version of itself. DTrace uses libproc
+# (which uses /proc) to find out when the traced process exits, but a
+# 32-bit process can't examine a 64-bit one with libproc. The
+# LD_NOEXEC_64 variable prevents nm from re-execing itself.
+#
+LD_NOEXEC_64=tomeeisrad $dtrace -F -s /dev/stdin -c \
+ '/usr/bin/nm /bin/ls' stat <<EOF
+
+pid\$target::\$1:entry
+{
+ self->start = vtimestamp;
+}
+
+pid\$target:::entry
+/self->start/
+{
+ trace(vtimestamp - self->start);
+}
+
+pid\$target:::return
+/self->start/
+{
+ trace(vtimestamp - self->start);
+}
+
+pid\$target::\$1:return
+/self->start/
+{
+ self->start = 0;
+ exit(0);
+}
+
+syscall:::
+/self->start/
+{
+ trace(vtimestamp - self->start);
+}
+
+fbt:::
+/self->start/
+{
+ trace(vtimestamp - self->start);
+}
+EOF
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/err.D_PRINTA_AGGKEY.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/err.D_PRINTA_AGGKEY.d
new file mode 100644
index 000000000000..8074e6e37151
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/err.D_PRINTA_AGGKEY.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ @foo[123] = sum(123);
+ @bar = sum(456);
+
+ printa("%10d %@10d %@10d\n", @foo, @bar);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/err.D_PRINTA_AGGPROTO.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/err.D_PRINTA_AGGPROTO.d
new file mode 100644
index 000000000000..dc65947aa397
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/err.D_PRINTA_AGGPROTO.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ @foo[123] = sum(123);
+ @bar["fooey"] = sum(456);
+
+ printa("%10d %@10d %@10d\n", @foo, @bar);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.many.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.many.d
new file mode 100644
index 000000000000..00588c66d789
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.many.d
@@ -0,0 +1,311 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option destructive
+#pragma D option quiet
+
+BEGIN
+/0/
+{
+ @agg996[996] = quantize(998);
+ @agg997[997] = count();
+ @agg998[998] = min(998);
+ @agg999[999] = lquantize(0, -10, 10, 1);
+}
+
+BEGIN
+{
+ @agg0[0] = sum(0);
+ @agg1[1] = sum(1);
+ @agg2[2] = sum(2);
+ @agg3[3] = sum(3);
+ @agg4[4] = sum(4);
+ @agg5[5] = sum(5);
+ @agg6[6] = sum(6);
+ @agg7[7] = sum(7);
+ @agg8[8] = sum(8);
+ @agg9[9] = sum(9);
+ @agg10[10] = sum(10);
+ @agg11[11] = sum(11);
+ @agg12[12] = sum(12);
+ @agg13[13] = sum(13);
+ @agg14[14] = sum(14);
+ @agg15[15] = sum(15);
+ @agg16[16] = sum(16);
+ @agg17[17] = sum(17);
+ @agg18[18] = sum(18);
+ @agg19[19] = sum(19);
+ @agg20[20] = sum(20);
+ @agg21[21] = sum(21);
+ @agg22[22] = sum(22);
+ @agg23[23] = sum(23);
+ @agg24[24] = sum(24);
+ @agg25[25] = sum(25);
+ @agg26[26] = sum(26);
+ @agg27[27] = sum(27);
+ @agg28[28] = sum(28);
+ @agg29[29] = sum(29);
+ @agg30[30] = sum(30);
+ @agg31[31] = sum(31);
+ @agg32[32] = sum(32);
+ @agg33[33] = sum(33);
+ @agg34[34] = sum(34);
+ @agg35[35] = sum(35);
+ @agg36[36] = sum(36);
+ @agg37[37] = sum(37);
+ @agg38[38] = sum(38);
+ @agg39[39] = sum(39);
+ @agg40[40] = sum(40);
+ @agg41[41] = sum(41);
+ @agg42[42] = sum(42);
+ @agg43[43] = sum(43);
+ @agg44[44] = sum(44);
+ @agg45[45] = sum(45);
+ @agg46[46] = sum(46);
+ @agg47[47] = sum(47);
+ @agg48[48] = sum(48);
+ @agg49[49] = sum(49);
+ @agg50[50] = sum(50);
+ @agg51[51] = sum(51);
+ @agg52[52] = sum(52);
+ @agg53[53] = sum(53);
+ @agg54[54] = sum(54);
+ @agg55[55] = sum(55);
+ @agg56[56] = sum(56);
+ @agg57[57] = sum(57);
+ @agg58[58] = sum(58);
+ @agg59[59] = sum(59);
+ @agg60[60] = sum(60);
+ @agg61[61] = sum(61);
+ @agg62[62] = sum(62);
+ @agg63[63] = sum(63);
+ @agg64[64] = sum(64);
+ @agg65[65] = sum(65);
+ @agg66[66] = sum(66);
+ @agg67[67] = sum(67);
+ @agg68[68] = sum(68);
+ @agg69[69] = sum(69);
+ @agg70[70] = sum(70);
+ @agg71[71] = sum(71);
+ @agg72[72] = sum(72);
+ @agg73[73] = sum(73);
+ @agg74[74] = sum(74);
+ @agg75[75] = sum(75);
+ @agg76[76] = sum(76);
+ @agg77[77] = sum(77);
+ @agg78[78] = sum(78);
+ @agg79[79] = sum(79);
+ @agg80[80] = sum(80);
+ @agg81[81] = sum(81);
+ @agg82[82] = sum(82);
+ @agg83[83] = sum(83);
+ @agg84[84] = sum(84);
+ @agg85[85] = sum(85);
+ @agg86[86] = sum(86);
+ @agg87[87] = sum(87);
+ @agg88[88] = sum(88);
+ @agg89[89] = sum(89);
+ @agg90[90] = sum(90);
+ @agg91[91] = sum(91);
+ @agg92[92] = sum(92);
+ @agg93[93] = sum(93);
+ @agg94[94] = sum(94);
+ @agg95[95] = sum(95);
+ @agg96[96] = sum(96);
+ @agg97[97] = sum(97);
+ @agg98[98] = sum(98);
+ @agg99[99] = sum(99);
+ @agg100[100] = sum(100);
+ @agg101[101] = sum(101);
+ @agg102[102] = sum(102);
+ @agg103[103] = sum(103);
+ @agg104[104] = sum(104);
+ @agg105[105] = sum(105);
+ @agg106[106] = sum(106);
+ @agg107[107] = sum(107);
+ @agg108[108] = sum(108);
+ @agg109[109] = sum(109);
+ @agg110[110] = sum(110);
+ @agg111[111] = sum(111);
+ @agg112[112] = sum(112);
+ @agg113[113] = sum(113);
+ @agg114[114] = sum(114);
+ @agg115[115] = sum(115);
+ @agg116[116] = sum(116);
+ @agg117[117] = sum(117);
+ @agg118[118] = sum(118);
+ @agg119[119] = sum(119);
+ @agg120[120] = sum(120);
+ @agg121[121] = sum(121);
+ @agg122[122] = sum(122);
+ @agg123[123] = sum(123);
+ @agg124[124] = sum(124);
+ @agg125[125] = sum(125);
+ @agg126[126] = sum(126);
+ @agg127[127] = sum(127);
+ @agg128[128] = sum(128);
+ @agg129[129] = sum(129);
+ @agg130[130] = sum(130);
+ @agg131[131] = sum(131);
+ @agg132[132] = sum(132);
+ @agg133[133] = sum(133);
+ @agg134[134] = sum(134);
+ @agg135[135] = sum(135);
+ @agg136[136] = sum(136);
+ @agg137[137] = sum(137);
+ @agg138[138] = sum(138);
+ @agg139[139] = sum(139);
+ @agg140[140] = sum(140);
+ @agg141[141] = sum(141);
+ @agg142[142] = sum(142);
+ @agg143[143] = sum(143);
+ @agg144[144] = sum(144);
+ @agg145[145] = sum(145);
+ @agg146[146] = sum(146);
+ @agg147[147] = sum(147);
+ @agg148[148] = sum(148);
+ @agg149[149] = sum(149);
+ @agg150[150] = sum(150);
+ @agg151[151] = sum(151);
+ @agg152[152] = sum(152);
+ @agg153[153] = sum(153);
+ @agg154[154] = sum(154);
+ @agg155[155] = sum(155);
+ @agg156[156] = sum(156);
+ @agg157[157] = sum(157);
+ @agg158[158] = sum(158);
+ @agg159[159] = sum(159);
+ @agg160[160] = sum(160);
+ @agg161[161] = sum(161);
+ @agg162[162] = sum(162);
+ @agg163[163] = sum(163);
+ @agg164[164] = sum(164);
+ @agg165[165] = sum(165);
+ @agg166[166] = sum(166);
+ @agg167[167] = sum(167);
+ @agg168[168] = sum(168);
+ @agg169[169] = sum(169);
+ @agg170[170] = sum(170);
+ @agg171[171] = sum(171);
+ @agg172[172] = sum(172);
+ @agg173[173] = sum(173);
+ @agg174[174] = sum(174);
+ @agg175[175] = sum(175);
+ @agg176[176] = sum(176);
+ @agg177[177] = sum(177);
+ @agg178[178] = sum(178);
+ @agg179[179] = sum(179);
+ @agg180[180] = sum(180);
+ @agg181[181] = sum(181);
+ @agg182[182] = sum(182);
+ @agg183[183] = sum(183);
+ @agg184[184] = sum(184);
+ @agg185[185] = sum(185);
+ @agg186[186] = sum(186);
+ @agg187[187] = sum(187);
+ @agg188[188] = sum(188);
+ @agg189[189] = sum(189);
+ @agg190[190] = sum(190);
+ @agg191[191] = sum(191);
+ @agg192[192] = sum(192);
+ @agg193[193] = sum(193);
+ @agg194[194] = sum(194);
+ @agg195[195] = sum(195);
+ @agg196[196] = sum(196);
+ @agg197[197] = sum(197);
+ @agg198[198] = sum(198);
+ @agg199[199] = sum(199);
+ @agg200[200] = sum(200);
+ @agg201[201] = sum(201);
+ @agg202[202] = sum(202);
+ @agg203[203] = sum(203);
+ @agg204[204] = sum(204);
+ @agg205[205] = sum(205);
+ @agg206[206] = sum(206);
+ @agg207[207] = sum(207);
+ @agg208[208] = sum(208);
+ @agg209[209] = sum(209);
+ @agg210[210] = sum(210);
+ @agg211[211] = sum(211);
+ @agg212[212] = sum(212);
+ @agg213[213] = sum(213);
+ @agg214[214] = sum(214);
+ @agg215[215] = sum(215);
+ @agg216[216] = sum(216);
+ @agg217[217] = sum(217);
+ @agg218[218] = sum(218);
+ @agg219[219] = sum(219);
+ @agg220[220] = sum(220);
+ @agg221[221] = sum(221);
+ @agg222[222] = sum(222);
+ @agg223[223] = sum(223);
+ @agg224[224] = sum(224);
+ @agg225[225] = sum(225);
+ @agg226[226] = sum(226);
+ @agg227[227] = sum(227);
+ @agg228[228] = sum(228);
+ @agg229[229] = sum(229);
+ @agg230[230] = sum(230);
+ @agg231[231] = sum(231);
+ @agg232[232] = sum(232);
+ @agg233[233] = sum(233);
+ @agg234[234] = sum(234);
+ @agg235[235] = sum(235);
+ @agg236[236] = sum(236);
+ @agg237[237] = sum(237);
+ @agg238[238] = sum(238);
+ @agg239[239] = sum(239);
+ @agg240[240] = sum(240);
+ @agg241[241] = sum(241);
+ @agg242[242] = sum(242);
+ @agg243[243] = sum(243);
+ @agg244[244] = sum(244);
+ @agg245[245] = sum(245);
+ @agg246[246] = sum(246);
+
+ printa("%8d %8@d %8@d\n", @agg0, @agg1);
+ printf("\n");
+
+ printa("%8d %8@d %8@d\n", @agg0, @agg996);
+ printf("\n");
+
+ printa("%4d %4@d %4@d %4@d %4@d %4@d %4@d %4@d %4@d %4@d %4@d %4@d\n",
+ @agg12, @agg3, @agg73, @agg997,
+ @agg9, @agg9, @agg4, @agg998,
+ @agg11, @agg23, @agg69);
+
+ printf("\n");
+
+ printa("%8d %8@d %8@d\n", @agg245, @agg246);
+ printf("\n");
+
+ printa("%8d %8@d %8@d\n", @agg999, @agg246);
+ printf("\n");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.many.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.many.d.out
new file mode 100644
index 000000000000..e048d4321e0a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.many.d.out
@@ -0,0 +1,265 @@
+ 0 0 0
+ 1 0 1
+
+ 0 0
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+
+ 69 0 0 0 0 0 0 0 0 0 0 69
+ 23 0 0 0 0 0 0 0 0 0 23 0
+ 11 0 0 0 0 0 0 0 0 11 0 0
+ 4 0 0 0 0 0 0 4 0 0 0 0
+ 9 0 0 0 0 9 9 0 0 0 0 0
+ 73 0 0 73 0 0 0 0 0 0 0 0
+ 3 0 3 0 0 0 0 0 0 0 0 0
+ 12 12 0 0 0 0 0 0 0 0 0 0
+
+ 246 0 246
+ 245 245 0
+
+ 246
+ value ------------- Distribution ------------- count
+ < -10 | 0
+ -10 | 0
+ -9 | 0
+ 246
+
+
+ 2 2
+ 5 5
+ 6 6
+ 7 7
+ 8 8
+ 10 10
+ 13 13
+ 14 14
+ 15 15
+ 16 16
+ 17 17
+ 18 18
+ 19 19
+ 20 20
+ 21 21
+ 22 22
+ 24 24
+ 25 25
+ 26 26
+ 27 27
+ 28 28
+ 29 29
+ 30 30
+ 31 31
+ 32 32
+ 33 33
+ 34 34
+ 35 35
+ 36 36
+ 37 37
+ 38 38
+ 39 39
+ 40 40
+ 41 41
+ 42 42
+ 43 43
+ 44 44
+ 45 45
+ 46 46
+ 47 47
+ 48 48
+ 49 49
+ 50 50
+ 51 51
+ 52 52
+ 53 53
+ 54 54
+ 55 55
+ 56 56
+ 57 57
+ 58 58
+ 59 59
+ 60 60
+ 61 61
+ 62 62
+ 63 63
+ 64 64
+ 65 65
+ 66 66
+ 67 67
+ 68 68
+ 70 70
+ 71 71
+ 72 72
+ 74 74
+ 75 75
+ 76 76
+ 77 77
+ 78 78
+ 79 79
+ 80 80
+ 81 81
+ 82 82
+ 83 83
+ 84 84
+ 85 85
+ 86 86
+ 87 87
+ 88 88
+ 89 89
+ 90 90
+ 91 91
+ 92 92
+ 93 93
+ 94 94
+ 95 95
+ 96 96
+ 97 97
+ 98 98
+ 99 99
+ 100 100
+ 101 101
+ 102 102
+ 103 103
+ 104 104
+ 105 105
+ 106 106
+ 107 107
+ 108 108
+ 109 109
+ 110 110
+ 111 111
+ 112 112
+ 113 113
+ 114 114
+ 115 115
+ 116 116
+ 117 117
+ 118 118
+ 119 119
+ 120 120
+ 121 121
+ 122 122
+ 123 123
+ 124 124
+ 125 125
+ 126 126
+ 127 127
+ 128 128
+ 129 129
+ 130 130
+ 131 131
+ 132 132
+ 133 133
+ 134 134
+ 135 135
+ 136 136
+ 137 137
+ 138 138
+ 139 139
+ 140 140
+ 141 141
+ 142 142
+ 143 143
+ 144 144
+ 145 145
+ 146 146
+ 147 147
+ 148 148
+ 149 149
+ 150 150
+ 151 151
+ 152 152
+ 153 153
+ 154 154
+ 155 155
+ 156 156
+ 157 157
+ 158 158
+ 159 159
+ 160 160
+ 161 161
+ 162 162
+ 163 163
+ 164 164
+ 165 165
+ 166 166
+ 167 167
+ 168 168
+ 169 169
+ 170 170
+ 171 171
+ 172 172
+ 173 173
+ 174 174
+ 175 175
+ 176 176
+ 177 177
+ 178 178
+ 179 179
+ 180 180
+ 181 181
+ 182 182
+ 183 183
+ 184 184
+ 185 185
+ 186 186
+ 187 187
+ 188 188
+ 189 189
+ 190 190
+ 191 191
+ 192 192
+ 193 193
+ 194 194
+ 195 195
+ 196 196
+ 197 197
+ 198 198
+ 199 199
+ 200 200
+ 201 201
+ 202 202
+ 203 203
+ 204 204
+ 205 205
+ 206 206
+ 207 207
+ 208 208
+ 209 209
+ 210 210
+ 211 211
+ 212 212
+ 213 213
+ 214 214
+ 215 215
+ 216 216
+ 217 217
+ 218 218
+ 219 219
+ 220 220
+ 221 221
+ 222 222
+ 223 223
+ 224 224
+ 225 225
+ 226 226
+ 227 227
+ 228 228
+ 229 229
+ 230 230
+ 231 231
+ 232 232
+ 233 233
+ 234 234
+ 235 235
+ 236 236
+ 237 237
+ 238 238
+ 239 239
+ 240 240
+ 241 241
+ 242 242
+ 243 243
+ 244 244
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.same.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.same.d
new file mode 100644
index 000000000000..0e675579e53d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.same.d
@@ -0,0 +1,37 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ @ = sum(90904);
+ printa("%@d %@d %@d\n", @, @, @);
+ printa("%@d %@d %@d\n", @);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.same.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.same.d.out
new file mode 100644
index 000000000000..b382c35a3cae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.same.d.out
@@ -0,0 +1,3 @@
+90904 90904 90904
+90904 90904 90904
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sort.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sort.d
new file mode 100644
index 000000000000..7bfd9e5781d6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sort.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+tick-1ms
+{
+ i++;
+ @a[i] = sum(100 - (i / 2));
+ @b[i] = sum(100 - (i / 4));
+ @c[i] = sum(100 - (i / 8));
+ @d[i] = sum(100 - (i / 16));
+}
+
+tick-1ms
+/i == 100/
+{
+ printa("%10d %@10d %@10d %@10d %@10d\n", @a, @b, @c, @d);
+ printa("%10d %@10d %@10d %@10d %@10d\n", @d, @c, @b, @a);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sort.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sort.d.out
new file mode 100644
index 000000000000..8c79190f10fc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sort.d.out
@@ -0,0 +1,201 @@
+ 100 50 75 88 94
+ 98 51 76 88 94
+ 99 51 76 88 94
+ 96 52 76 88 94
+ 97 52 76 88 94
+ 94 53 77 89 95
+ 95 53 77 89 95
+ 92 54 77 89 95
+ 93 54 77 89 95
+ 90 55 78 89 95
+ 91 55 78 89 95
+ 88 56 78 89 95
+ 89 56 78 89 95
+ 86 57 79 90 95
+ 87 57 79 90 95
+ 84 58 79 90 95
+ 85 58 79 90 95
+ 82 59 80 90 95
+ 83 59 80 90 95
+ 80 60 80 90 95
+ 81 60 80 90 95
+ 78 61 81 91 96
+ 79 61 81 91 96
+ 76 62 81 91 96
+ 77 62 81 91 96
+ 74 63 82 91 96
+ 75 63 82 91 96
+ 72 64 82 91 96
+ 73 64 82 91 96
+ 70 65 83 92 96
+ 71 65 83 92 96
+ 68 66 83 92 96
+ 69 66 83 92 96
+ 66 67 84 92 96
+ 67 67 84 92 96
+ 64 68 84 92 96
+ 65 68 84 92 96
+ 62 69 85 93 97
+ 63 69 85 93 97
+ 60 70 85 93 97
+ 61 70 85 93 97
+ 58 71 86 93 97
+ 59 71 86 93 97
+ 56 72 86 93 97
+ 57 72 86 93 97
+ 54 73 87 94 97
+ 55 73 87 94 97
+ 52 74 87 94 97
+ 53 74 87 94 97
+ 50 75 88 94 97
+ 51 75 88 94 97
+ 48 76 88 94 97
+ 49 76 88 94 97
+ 46 77 89 95 98
+ 47 77 89 95 98
+ 44 78 89 95 98
+ 45 78 89 95 98
+ 42 79 90 95 98
+ 43 79 90 95 98
+ 40 80 90 95 98
+ 41 80 90 95 98
+ 38 81 91 96 98
+ 39 81 91 96 98
+ 36 82 91 96 98
+ 37 82 91 96 98
+ 34 83 92 96 98
+ 35 83 92 96 98
+ 32 84 92 96 98
+ 33 84 92 96 98
+ 30 85 93 97 99
+ 31 85 93 97 99
+ 28 86 93 97 99
+ 29 86 93 97 99
+ 26 87 94 97 99
+ 27 87 94 97 99
+ 24 88 94 97 99
+ 25 88 94 97 99
+ 22 89 95 98 99
+ 23 89 95 98 99
+ 20 90 95 98 99
+ 21 90 95 98 99
+ 18 91 96 98 99
+ 19 91 96 98 99
+ 16 92 96 98 99
+ 17 92 96 98 99
+ 14 93 97 99 100
+ 15 93 97 99 100
+ 12 94 97 99 100
+ 13 94 97 99 100
+ 10 95 98 99 100
+ 11 95 98 99 100
+ 8 96 98 99 100
+ 9 96 98 99 100
+ 6 97 99 100 100
+ 7 97 99 100 100
+ 4 98 99 100 100
+ 5 98 99 100 100
+ 2 99 100 100 100
+ 3 99 100 100 100
+ 1 100 100 100 100
+ 100 94 88 75 50
+ 98 94 88 76 51
+ 99 94 88 76 51
+ 96 94 88 76 52
+ 97 94 88 76 52
+ 94 95 89 77 53
+ 95 95 89 77 53
+ 92 95 89 77 54
+ 93 95 89 77 54
+ 90 95 89 78 55
+ 91 95 89 78 55
+ 88 95 89 78 56
+ 89 95 89 78 56
+ 86 95 90 79 57
+ 87 95 90 79 57
+ 84 95 90 79 58
+ 85 95 90 79 58
+ 82 95 90 80 59
+ 83 95 90 80 59
+ 80 95 90 80 60
+ 81 95 90 80 60
+ 78 96 91 81 61
+ 79 96 91 81 61
+ 76 96 91 81 62
+ 77 96 91 81 62
+ 74 96 91 82 63
+ 75 96 91 82 63
+ 72 96 91 82 64
+ 73 96 91 82 64
+ 70 96 92 83 65
+ 71 96 92 83 65
+ 68 96 92 83 66
+ 69 96 92 83 66
+ 66 96 92 84 67
+ 67 96 92 84 67
+ 64 96 92 84 68
+ 65 96 92 84 68
+ 62 97 93 85 69
+ 63 97 93 85 69
+ 60 97 93 85 70
+ 61 97 93 85 70
+ 58 97 93 86 71
+ 59 97 93 86 71
+ 56 97 93 86 72
+ 57 97 93 86 72
+ 54 97 94 87 73
+ 55 97 94 87 73
+ 52 97 94 87 74
+ 53 97 94 87 74
+ 50 97 94 88 75
+ 51 97 94 88 75
+ 48 97 94 88 76
+ 49 97 94 88 76
+ 46 98 95 89 77
+ 47 98 95 89 77
+ 44 98 95 89 78
+ 45 98 95 89 78
+ 42 98 95 90 79
+ 43 98 95 90 79
+ 40 98 95 90 80
+ 41 98 95 90 80
+ 38 98 96 91 81
+ 39 98 96 91 81
+ 36 98 96 91 82
+ 37 98 96 91 82
+ 34 98 96 92 83
+ 35 98 96 92 83
+ 32 98 96 92 84
+ 33 98 96 92 84
+ 30 99 97 93 85
+ 31 99 97 93 85
+ 28 99 97 93 86
+ 29 99 97 93 86
+ 26 99 97 94 87
+ 27 99 97 94 87
+ 24 99 97 94 88
+ 25 99 97 94 88
+ 22 99 98 95 89
+ 23 99 98 95 89
+ 20 99 98 95 90
+ 21 99 98 95 90
+ 18 99 98 96 91
+ 19 99 98 96 91
+ 16 99 98 96 92
+ 17 99 98 96 92
+ 14 100 99 97 93
+ 15 100 99 97 93
+ 12 100 99 97 94
+ 13 100 99 97 94
+ 10 100 99 98 95
+ 11 100 99 98 95
+ 8 100 99 98 96
+ 9 100 99 98 96
+ 6 100 100 99 97
+ 7 100 100 99 97
+ 4 100 100 99 98
+ 5 100 100 99 98
+ 2 100 100 100 99
+ 3 100 100 100 99
+ 1 100 100 100 100
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sortpos.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sortpos.d
new file mode 100644
index 000000000000..ddb297f9ce18
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sortpos.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ j = 0;
+}
+
+tick-1ms
+/i < 100/
+{
+ i++;
+ @a[i] = sum(i);
+ @b[i] = sum((25 + i) % 100);
+ @c[i] = sum((50 + i) % 100);
+ @d[i] = sum((75 + i) % 100);
+}
+
+tick-1ms
+/i == 100 && j < 10/
+{
+ printf("Sorted at position %d:\n", j);
+ setopt("aggsortpos", lltostr(j));
+ printa("%9d %@9d %@9d %@9d %@9d %@9d %@9d\n", @a, @b, @c, @a, @d, @a);
+ printf("\n");
+ j++;
+}
+
+tick-1ms
+/i == 100 && j == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sortpos.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sortpos.d.out
new file mode 100644
index 000000000000..ce175391fc14
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.sortpos.d.out
@@ -0,0 +1,1021 @@
+Sorted at position 0:
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+
+Sorted at position 1:
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+
+Sorted at position 2:
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+
+Sorted at position 3:
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+
+Sorted at position 4:
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+
+Sorted at position 5:
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+
+Sorted at position 6:
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+
+Sorted at position 7:
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+
+Sorted at position 8:
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+
+Sorted at position 9:
+ 1 1 26 51 1 76 1
+ 2 2 27 52 2 77 2
+ 3 3 28 53 3 78 3
+ 4 4 29 54 4 79 4
+ 5 5 30 55 5 80 5
+ 6 6 31 56 6 81 6
+ 7 7 32 57 7 82 7
+ 8 8 33 58 8 83 8
+ 9 9 34 59 9 84 9
+ 10 10 35 60 10 85 10
+ 11 11 36 61 11 86 11
+ 12 12 37 62 12 87 12
+ 13 13 38 63 13 88 13
+ 14 14 39 64 14 89 14
+ 15 15 40 65 15 90 15
+ 16 16 41 66 16 91 16
+ 17 17 42 67 17 92 17
+ 18 18 43 68 18 93 18
+ 19 19 44 69 19 94 19
+ 20 20 45 70 20 95 20
+ 21 21 46 71 21 96 21
+ 22 22 47 72 22 97 22
+ 23 23 48 73 23 98 23
+ 24 24 49 74 24 99 24
+ 25 25 50 75 25 0 25
+ 26 26 51 76 26 1 26
+ 27 27 52 77 27 2 27
+ 28 28 53 78 28 3 28
+ 29 29 54 79 29 4 29
+ 30 30 55 80 30 5 30
+ 31 31 56 81 31 6 31
+ 32 32 57 82 32 7 32
+ 33 33 58 83 33 8 33
+ 34 34 59 84 34 9 34
+ 35 35 60 85 35 10 35
+ 36 36 61 86 36 11 36
+ 37 37 62 87 37 12 37
+ 38 38 63 88 38 13 38
+ 39 39 64 89 39 14 39
+ 40 40 65 90 40 15 40
+ 41 41 66 91 41 16 41
+ 42 42 67 92 42 17 42
+ 43 43 68 93 43 18 43
+ 44 44 69 94 44 19 44
+ 45 45 70 95 45 20 45
+ 46 46 71 96 46 21 46
+ 47 47 72 97 47 22 47
+ 48 48 73 98 48 23 48
+ 49 49 74 99 49 24 49
+ 50 50 75 0 50 25 50
+ 51 51 76 1 51 26 51
+ 52 52 77 2 52 27 52
+ 53 53 78 3 53 28 53
+ 54 54 79 4 54 29 54
+ 55 55 80 5 55 30 55
+ 56 56 81 6 56 31 56
+ 57 57 82 7 57 32 57
+ 58 58 83 8 58 33 58
+ 59 59 84 9 59 34 59
+ 60 60 85 10 60 35 60
+ 61 61 86 11 61 36 61
+ 62 62 87 12 62 37 62
+ 63 63 88 13 63 38 63
+ 64 64 89 14 64 39 64
+ 65 65 90 15 65 40 65
+ 66 66 91 16 66 41 66
+ 67 67 92 17 67 42 67
+ 68 68 93 18 68 43 68
+ 69 69 94 19 69 44 69
+ 70 70 95 20 70 45 70
+ 71 71 96 21 71 46 71
+ 72 72 97 22 72 47 72
+ 73 73 98 23 73 48 73
+ 74 74 99 24 74 49 74
+ 75 75 0 25 75 50 75
+ 76 76 1 26 76 51 76
+ 77 77 2 27 77 52 77
+ 78 78 3 28 78 53 78
+ 79 79 4 29 79 54 79
+ 80 80 5 30 80 55 80
+ 81 81 6 31 81 56 81
+ 82 82 7 32 82 57 82
+ 83 83 8 33 83 58 83
+ 84 84 9 34 84 59 84
+ 85 85 10 35 85 60 85
+ 86 86 11 36 86 61 86
+ 87 87 12 37 87 62 87
+ 88 88 13 38 88 63 88
+ 89 89 14 39 89 64 89
+ 90 90 15 40 90 65 90
+ 91 91 16 41 91 66 91
+ 92 92 17 42 92 67 92
+ 93 93 18 43 93 68 93
+ 94 94 19 44 94 69 94
+ 95 95 20 45 95 70 95
+ 96 96 21 46 96 71 96
+ 97 97 22 47 97 72 97
+ 98 98 23 48 98 73 98
+ 99 99 24 49 99 74 99
+ 100 100 25 50 100 75 100
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.tuplecompat.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.tuplecompat.d
new file mode 100644
index 000000000000..ebb916a0192d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.tuplecompat.d
@@ -0,0 +1,37 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ @one["foo", 789, "bar", curthread] = sum(123);
+ @two["foo", 789, "bar", curthread] = sum(456);
+ printa("%10s %10d %10s %@10d %@10d\n", @one, @two);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.tuplecompat.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.tuplecompat.d.out
new file mode 100644
index 000000000000..002f5aa13f8b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.tuplecompat.d.out
@@ -0,0 +1,2 @@
+ foo 789 bar 123 456
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero.d
new file mode 100644
index 000000000000..5a57b2b01ab5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+/0/
+{
+ @bop[345] = quantize(0);
+ @baz[345] = lquantize(0, -10, 10, 1);
+}
+
+BEGIN
+{
+ @foo[123] = sum(123);
+ @bar[456] = sum(456);
+
+ @foo[789] = sum(789);
+ @bar[789] = sum(789);
+
+ printa("%10d %@10d %@10d\n", @foo, @bar);
+ printa("%10d %@10d %@10d %@10d\n", @foo, @bar, @bop);
+ printa("%10d %@10d %@10d %@10d %@10d\n", @foo, @bar, @bop, @baz);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero.d.out
new file mode 100644
index 000000000000..dde9e41c21ac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero.d.out
@@ -0,0 +1,55 @@
+ 456 0 456
+ 123 123 0
+ 789 789 789
+ 456 0 456
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ 123 123 0
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ 789 789 789
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ 456 0 456
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ value ------------- Distribution ------------- count
+ < -10 | 0
+ -10 | 0
+ -9 | 0
+
+ 123 123 0
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ value ------------- Distribution ------------- count
+ < -10 | 0
+ -10 | 0
+ -9 | 0
+
+ 789 789 789
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ value ------------- Distribution ------------- count
+ < -10 | 0
+ -10 | 0
+ -9 | 0
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero2.d
new file mode 100644
index 000000000000..79e756bdbf7e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero2.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ @bop[345] = quantize(0, 0);
+ @baz[345] = lquantize(0, -10, 10, 1, 0);
+}
+
+BEGIN
+{
+ @foo[123] = sum(123);
+ @bar[456] = sum(456);
+
+ @foo[789] = sum(789);
+ @bar[789] = sum(789);
+
+ printa("%10d %@10d %@10d\n", @foo, @bar);
+ printa("%10d %@10d %@10d %@10d\n", @foo, @bar, @bop);
+ printa("%10d %@10d %@10d %@10d %@10d\n", @foo, @bar, @bop, @baz);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero2.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero2.d.out
new file mode 100644
index 000000000000..9b28d8e7e299
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero2.d.out
@@ -0,0 +1,72 @@
+ 456 0 456
+ 123 123 0
+ 789 789 789
+ 345 0 0
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ 456 0 456
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ 123 123 0
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ 789 789 789
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ 345 0 0
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ value ------------- Distribution ------------- count
+ < -10 | 0
+ -10 | 0
+ -9 | 0
+
+ 456 0 456
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ value ------------- Distribution ------------- count
+ < -10 | 0
+ -10 | 0
+ -9 | 0
+
+ 123 123 0
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ value ------------- Distribution ------------- count
+ < -10 | 0
+ -10 | 0
+ -9 | 0
+
+ 789 789 789
+ value ------------- Distribution ------------- count
+ -1 | 0
+ 0 | 0
+ 1 | 0
+
+ value ------------- Distribution ------------- count
+ < -10 | 0
+ -10 | 0
+ -9 | 0
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero3.d
new file mode 100644
index 000000000000..bc17bc962a4d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero3.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+/0/
+{
+ @bop[345] = quantize(0, 0);
+ @baz[345] = lquantize(0, -10, 10, 1, 0);
+}
+
+BEGIN
+{
+ printa(@bop);
+ printa(@baz);
+ printa("%@10d %@10d\n", @bop, @baz);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero3.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero3.d.out
new file mode 100644
index 000000000000..b28b04f64312
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/multiaggs/tst.zero3.d.out
@@ -0,0 +1,3 @@
+
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call.c
new file mode 100644
index 000000000000..6194c5802237
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call.c
@@ -0,0 +1,120 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <strings.h>
+#include <rpc/rpc.h>
+
+#include "rpcsvc/nfs4_prot.h"
+
+int nfs4_skip_bytes;
+
+/*
+ * The waiting() function returns the value passed in, until something
+ * external modifies it. In this case, the D script tst.call.d will
+ * modify the value of *a, and thus break the while loop in dotest().
+ *
+ * This serves the purpose of not making the RPC calls until tst.call.d
+ * is active. Thus, the probes in tst.call.d can fire as a result of
+ * the RPC call in dotest().
+ */
+
+int
+waiting(volatile int *a)
+{
+ return (*a);
+}
+
+int
+dotest(void)
+{
+ CLIENT *client;
+ AUTH *auth;
+ COMPOUND4args args;
+ COMPOUND4res res;
+ enum clnt_stat status;
+ struct timeval timeout;
+ nfs_argop4 arg[1];
+ char *tag = "dtrace test";
+ volatile int a = 0;
+
+ while (waiting(&a) == 0)
+ continue;
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+
+ client = clnt_create("localhost", NFS4_PROGRAM, NFS_V4, "tcp");
+ if (client == NULL) {
+ clnt_pcreateerror("test");
+ return (1);
+ }
+ auth = authsys_create_default();
+ client->cl_auth = auth;
+ args.minorversion = 0;
+ args.tag.utf8string_len = strlen(tag);
+ args.tag.utf8string_val = tag;
+ args.argarray.argarray_len = sizeof (arg) / sizeof (nfs_argop4);
+ args.argarray.argarray_val = arg;
+
+ arg[0].argop = OP_PUTROOTFH;
+ /* no need to manipulate nfs_argop4_u */
+
+ bzero(&res, sizeof (res));
+
+ status = clnt_call(client, NFSPROC4_COMPOUND,
+ xdr_COMPOUND4args, (caddr_t)&args,
+ xdr_COMPOUND4res, (caddr_t)&res,
+ timeout);
+ if (status != RPC_SUCCESS) {
+ clnt_perror(client, "test");
+ return (2);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+main(int argc, char **argv)
+{
+ char shareline[BUFSIZ], unshareline[BUFSIZ];
+ int rc;
+
+ (void) snprintf(shareline, sizeof (shareline),
+ "mkdir /tmp/nfsv4test.%d ; share /tmp/nfsv4test.%d", getpid(),
+ getpid());
+ (void) snprintf(unshareline, sizeof (unshareline),
+ "unshare /tmp/nfsv4test.%d ; rmdir /tmp/nfsv4test.%d", getpid(),
+ getpid());
+
+ (void) system(shareline);
+ rc = dotest();
+ (void) system(unshareline);
+
+ return (rc);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call.d
new file mode 100644
index 000000000000..15cf8bc0dc4e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call.d
@@ -0,0 +1,70 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Make sure nfs provider probes are firing
+ *
+ * SECTION: nfs4 provider
+ */
+
+#pragma D option destructive
+#pragma D option quiet
+
+pid$1:a.out:waiting:entry
+{
+ this->value = (int *)alloca(sizeof (int));
+ *this->value = 1;
+ copyout(this->value, arg0, sizeof (int));
+}
+
+nfsv4:::compound-start
+{
+ cstart++;
+}
+
+nfsv4:::op-putrootfh-start
+{
+ opstart++;
+}
+
+nfsv4:::op-putrootfh-done
+{
+ opdone++;
+}
+
+nfsv4:::compound-done
+/cstart && opstart && opdone/
+{
+ exit(0);
+}
+
+tick-1s
+/tick++ == 3/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call3.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call3.c
new file mode 100644
index 000000000000..dda3ef28c0b0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call3.c
@@ -0,0 +1,442 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <strings.h>
+#include <rpc/rpc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <rpcsvc/mount.h>
+
+#include "rpcsvc/nfs_prot.h"
+
+char sharedpath[MAXPATHLEN];
+fhandle3 *rootfh;
+
+/*
+ * The waiting() function returns the value passed in, until something
+ * external modifies it. In this case, the D script tst.call.d will
+ * modify the value of *a, and thus break the while loop in dotest().
+ *
+ * This serves the purpose of not making the RPC calls until tst.call.d
+ * is active. Thus, the probes in tst.call.d can fire as a result of
+ * the RPC call in dotest().
+ */
+
+int
+waiting(volatile int *a)
+{
+ return (*a);
+}
+
+static void
+getattr_arginit(void *argp)
+{
+ GETATTR3args *args = argp;
+
+ args->object.data.data_len = rootfh->fhandle3_len;
+ args->object.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+setattr_arginit(void *argp)
+{
+ SETATTR3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->object.data.data_len = rootfh->fhandle3_len;
+ args->object.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+lookup_arginit(void *argp)
+{
+ LOOKUP3args *args = argp;
+
+ args->what.name = "giant-skunk";
+ args->what.dir.data.data_len = rootfh->fhandle3_len;
+ args->what.dir.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+access_arginit(void *argp)
+{
+ ACCESS3args *args = argp;
+
+ args->object.data.data_len = rootfh->fhandle3_len;
+ args->object.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+commit_arginit(void *argp)
+{
+ COMMIT3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->file.data.data_len = rootfh->fhandle3_len;
+ args->file.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+create_arginit(void *argp)
+{
+ CREATE3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->where.name = "pinky-blue";
+ args->where.dir.data.data_len = rootfh->fhandle3_len;
+ args->where.dir.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+fsinfo_arginit(void *argp)
+{
+ FSINFO3args *args = argp;
+
+ args->fsroot.data.data_len = rootfh->fhandle3_len;
+ args->fsroot.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+fsstat_arginit(void *argp)
+{
+ FSSTAT3args *args = argp;
+
+ args->fsroot.data.data_len = rootfh->fhandle3_len;
+ args->fsroot.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+link_arginit(void *argp)
+{
+ LINK3args *args = argp;
+
+ args->file.data.data_len = rootfh->fhandle3_len;
+ args->file.data.data_val = rootfh->fhandle3_val;
+ args->link.dir.data.data_len = rootfh->fhandle3_len;
+ args->link.dir.data.data_val = rootfh->fhandle3_val;
+ args->link.name = "samf";
+}
+
+static void
+mkdir_arginit(void *argp)
+{
+ MKDIR3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->where.dir.data.data_len = rootfh->fhandle3_len;
+ args->where.dir.data.data_val = rootfh->fhandle3_val;
+ args->where.name = "cookie";
+}
+
+static void
+mknod_arginit(void *argp)
+{
+ MKNOD3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->where.dir.data.data_len = rootfh->fhandle3_len;
+ args->where.dir.data.data_val = rootfh->fhandle3_val;
+ args->where.name = "pookie";
+}
+
+static void
+null_arginit(void *argp)
+{
+}
+
+static void
+pathconf_arginit(void *argp)
+{
+ PATHCONF3args *args = argp;
+
+ args->object.data.data_len = rootfh->fhandle3_len;
+ args->object.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+read_arginit(void *argp)
+{
+ READ3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->file.data.data_len = rootfh->fhandle3_len;
+ args->file.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+readdir_arginit(void *argp)
+{
+ READDIR3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->dir.data.data_len = rootfh->fhandle3_len;
+ args->dir.data.data_val = rootfh->fhandle3_val;
+ args->count = 1024;
+}
+
+static void
+readdirplus_arginit(void *argp)
+{
+ READDIRPLUS3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->dir.data.data_len = rootfh->fhandle3_len;
+ args->dir.data.data_val = rootfh->fhandle3_val;
+ args->dircount = 1024;
+ args->maxcount = 1024;
+}
+
+static void
+readlink_arginit(void *argp)
+{
+ READLINK3args *args = argp;
+
+ args->symlink.data.data_len = rootfh->fhandle3_len;
+ args->symlink.data.data_val = rootfh->fhandle3_val;
+}
+
+static void
+remove_arginit(void *argp)
+{
+ REMOVE3args *args = argp;
+
+ args->object.dir.data.data_len = rootfh->fhandle3_len;
+ args->object.dir.data.data_val = rootfh->fhandle3_val;
+ args->object.name = "antelope";
+}
+
+static void
+rename_arginit(void *argp)
+{
+ RENAME3args *args = argp;
+
+ args->from.dir.data.data_len = rootfh->fhandle3_len;
+ args->from.dir.data.data_val = rootfh->fhandle3_val;
+ args->from.name = "walter";
+ args->to.dir.data.data_len = rootfh->fhandle3_len;
+ args->to.dir.data.data_val = rootfh->fhandle3_val;
+ args->to.name = "wendy";
+}
+
+static void
+rmdir_arginit(void *argp)
+{
+ RMDIR3args *args = argp;
+
+ args->object.dir.data.data_len = rootfh->fhandle3_len;
+ args->object.dir.data.data_val = rootfh->fhandle3_val;
+ args->object.name = "bunny";
+}
+
+static void
+symlink_arginit(void *argp)
+{
+ SYMLINK3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->where.dir.data.data_len = rootfh->fhandle3_len;
+ args->where.dir.data.data_val = rootfh->fhandle3_val;
+ args->where.name = "parlor";
+ args->symlink.symlink_data = "interior";
+}
+
+static void
+write_arginit(void *argp)
+{
+ WRITE3args *args = argp;
+
+ bzero(args, sizeof (*args));
+ args->file.data.data_len = rootfh->fhandle3_len;
+ args->file.data.data_val = rootfh->fhandle3_val;
+}
+
+typedef void (*call3_arginit_t)(void *);
+
+typedef struct {
+ call3_arginit_t arginit;
+ rpcproc_t proc;
+ xdrproc_t xdrargs;
+ size_t argsize;
+ xdrproc_t xdrres;
+ size_t ressize;
+} call3_test_t;
+call3_test_t call3_tests[] = {
+ {getattr_arginit, NFSPROC3_GETATTR, xdr_GETATTR3args,
+ sizeof (GETATTR3args), xdr_GETATTR3res, sizeof (GETATTR3res)},
+ {setattr_arginit, NFSPROC3_SETATTR, xdr_SETATTR3args,
+ sizeof (SETATTR3args), xdr_SETATTR3res, sizeof (SETATTR3res)},
+ {lookup_arginit, NFSPROC3_LOOKUP, xdr_LOOKUP3args,
+ sizeof (LOOKUP3args), xdr_LOOKUP3res, sizeof (LOOKUP3res)},
+ {access_arginit, NFSPROC3_ACCESS, xdr_ACCESS3args,
+ sizeof (ACCESS3args), xdr_ACCESS3res, sizeof (ACCESS3res)},
+ {commit_arginit, NFSPROC3_COMMIT, xdr_COMMIT3args,
+ sizeof (COMMIT3args), xdr_COMMIT3res, sizeof (COMMIT3res)},
+ {create_arginit, NFSPROC3_CREATE, xdr_CREATE3args,
+ sizeof (CREATE3args), xdr_CREATE3res, sizeof (CREATE3res)},
+ {fsinfo_arginit, NFSPROC3_FSINFO, xdr_FSINFO3args,
+ sizeof (FSINFO3args), xdr_FSINFO3res, sizeof (FSINFO3res)},
+ {fsstat_arginit, NFSPROC3_FSSTAT, xdr_FSSTAT3args,
+ sizeof (FSSTAT3args), xdr_FSSTAT3res, sizeof (FSSTAT3res)},
+ {link_arginit, NFSPROC3_LINK, xdr_LINK3args,
+ sizeof (LINK3args), xdr_LINK3res, sizeof (LINK3res)},
+ {mkdir_arginit, NFSPROC3_MKDIR, xdr_MKDIR3args,
+ sizeof (MKDIR3args), xdr_MKDIR3res, sizeof (MKDIR3res)},
+ {mknod_arginit, NFSPROC3_MKNOD, xdr_MKNOD3args,
+ sizeof (MKNOD3args), xdr_MKNOD3res, sizeof (MKNOD3res)},
+ /*
+ * NULL proc is special. Rather than special case its zero-sized
+ * args/results, we give it a small nonzero size, so as to not
+ * make realloc() do the wrong thing.
+ */
+ {null_arginit, NFSPROC3_NULL, xdr_void, sizeof (int), xdr_void,
+ sizeof (int)},
+ {pathconf_arginit, NFSPROC3_PATHCONF, xdr_PATHCONF3args,
+ sizeof (PATHCONF3args), xdr_PATHCONF3res, sizeof (PATHCONF3res)},
+ {read_arginit, NFSPROC3_READ, xdr_READ3args,
+ sizeof (READ3args), xdr_READ3res, sizeof (READ3res)},
+ {readdir_arginit, NFSPROC3_READDIR, xdr_READDIR3args,
+ sizeof (READDIR3args), xdr_READDIR3res, sizeof (READDIR3res)},
+ {readdirplus_arginit, NFSPROC3_READDIRPLUS, xdr_READDIRPLUS3args,
+ sizeof (READDIRPLUS3args), xdr_READDIRPLUS3res,
+ sizeof (READDIRPLUS3res)},
+ {readlink_arginit, NFSPROC3_READLINK, xdr_READLINK3args,
+ sizeof (READLINK3args), xdr_READLINK3res, sizeof (READLINK3res)},
+ {remove_arginit, NFSPROC3_REMOVE, xdr_REMOVE3args,
+ sizeof (REMOVE3args), xdr_REMOVE3res, sizeof (REMOVE3res)},
+ {rename_arginit, NFSPROC3_RENAME, xdr_RENAME3args,
+ sizeof (RENAME3args), xdr_RENAME3res, sizeof (RENAME3res)},
+ {rmdir_arginit, NFSPROC3_RMDIR, xdr_RMDIR3args,
+ sizeof (RMDIR3args), xdr_RMDIR3res, sizeof (RMDIR3res)},
+ {symlink_arginit, NFSPROC3_SYMLINK, xdr_SYMLINK3args,
+ sizeof (SYMLINK3args), xdr_SYMLINK3res, sizeof (SYMLINK3res)},
+ {write_arginit, NFSPROC3_WRITE, xdr_WRITE3args,
+ sizeof (WRITE3args), xdr_WRITE3res, sizeof (WRITE3res)},
+ {NULL}
+};
+
+int
+dotest(void)
+{
+ CLIENT *client, *mountclient;
+ AUTH *auth;
+ struct timeval timeout;
+ caddr_t args, res;
+ enum clnt_stat status;
+ rpcproc_t proc;
+ call3_test_t *test;
+ void *argbuf = NULL;
+ void *resbuf = NULL;
+ struct mountres3 mountres3;
+ char *sp;
+ volatile int a = 0;
+
+ while (waiting(&a) == 0)
+ continue;
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+
+ mountclient = clnt_create("localhost", MOUNTPROG, MOUNTVERS3, "tcp");
+ if (mountclient == NULL) {
+ clnt_pcreateerror("clnt_create mount");
+ return (1);
+ }
+ auth = authsys_create_default();
+ mountclient->cl_auth = auth;
+ sp = sharedpath;
+ bzero(&mountres3, sizeof (mountres3));
+ status = clnt_call(mountclient, MOUNTPROC_MNT,
+ xdr_dirpath, (char *)&sp,
+ xdr_mountres3, (char *)&mountres3,
+ timeout);
+ if (status != RPC_SUCCESS) {
+ clnt_perror(mountclient, "mnt");
+ return (1);
+ }
+ if (mountres3.fhs_status != 0) {
+ fprintf(stderr, "MOUNTPROG/MOUNTVERS3 failed %d\n",
+ mountres3.fhs_status);
+ return (1);
+ }
+ rootfh = &mountres3.mountres3_u.mountinfo.fhandle;
+
+ client = clnt_create("localhost", NFS3_PROGRAM, NFS_V3, "tcp");
+ if (client == NULL) {
+ clnt_pcreateerror("clnt_create");
+ return (1);
+ }
+ client->cl_auth = auth;
+
+ for (test = call3_tests; test->arginit; ++test) {
+ argbuf = realloc(argbuf, test->argsize);
+ resbuf = realloc(resbuf, test->ressize);
+ if ((argbuf == NULL) || (resbuf == NULL)) {
+ perror("realloc() failed");
+ return (1);
+ }
+ (test->arginit)(argbuf);
+ bzero(resbuf, test->ressize);
+ status = clnt_call(client, test->proc,
+ test->xdrargs, argbuf,
+ test->xdrres, resbuf,
+ timeout);
+ if (status != RPC_SUCCESS)
+ clnt_perror(client, "call");
+ }
+
+ status = clnt_call(mountclient, MOUNTPROC_UMNT,
+ xdr_dirpath, (char *)&sp,
+ xdr_void, NULL,
+ timeout);
+ if (status != RPC_SUCCESS)
+ clnt_perror(mountclient, "umnt");
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+main(int argc, char **argv)
+{
+ char shareline[BUFSIZ], unshareline[BUFSIZ];
+ int rc;
+
+ (void) snprintf(sharedpath, sizeof (sharedpath),
+ "/tmp/nfsv3test.%d", getpid());
+ (void) snprintf(shareline, sizeof (shareline),
+ "mkdir %s ; share %s", sharedpath, sharedpath);
+ (void) snprintf(unshareline, sizeof (unshareline),
+ "unshare %s ; rmdir %s", sharedpath, sharedpath);
+
+ (void) system(shareline);
+ rc = dotest();
+ (void) system(unshareline);
+
+ return (rc);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call3.d
new file mode 100644
index 000000000000..b635b1662db9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/nfs/tst.call3.d
@@ -0,0 +1,91 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Make sure nfsv3 provider probes are firing, and that the
+ * arguments are properly visible.
+ *
+ * SECTION: nfs3 provider
+ */
+
+#pragma D option destructive
+#pragma D option quiet
+
+pid$1:a.out:waiting:entry
+{
+ this->value = (int *)alloca(sizeof (int));
+ *this->value = 1;
+ copyout(this->value, arg0, sizeof (int));
+}
+
+nfsv3:::op-getattr-start
+{
+ printf("ci_local: %s\n", args[0]->ci_local);
+ printf("ci_remote: %s\n", args[0]->ci_remote);
+ printf("ci_protocol: %s\n", args[0]->ci_protocol);
+
+ printf("noi_xid: %d\n", args[1]->noi_xid);
+ printf("noi_cred->cr_uid: %d\n", args[1]->noi_cred->cr_uid);
+ printf("noi_curpath: %s\n", args[1]->noi_curpath);
+
+ printf("fh3_flags: %d\n", args[2]->object.fh3_flags);
+}
+
+nfsv3:::op-getattr-done
+{
+ printf("ci_local: %s\n", args[0]->ci_local);
+ printf("ci_remote: %s\n", args[0]->ci_remote);
+ printf("ci_protocol: %s\n", args[0]->ci_protocol);
+
+ printf("noi_xid: %d\n", args[1]->noi_xid);
+ printf("noi_cred->cr_uid: %d\n", args[1]->noi_cred->cr_uid);
+ printf("noi_curpath: %s\n", args[1]->noi_curpath);
+
+ printf("status: %d\n", args[2]->status);
+}
+
+nfsv3:::*-done
+/seen[probename] == 0/
+{
+ ++numberseen;
+ seen[probename] = 1;
+ printf("%d ops seen, latest op is %s\n", numberseen, probename);
+}
+
+nfsv3:::*-done
+/numberseen == 22/
+{
+ exit(0);
+}
+
+tick-1s
+/tick++ == 10/
+{
+ printf("%d nfsv3 ops seen; should be 22\n", numberseen);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_BITFIELD.bitfield.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_BITFIELD.bitfield.d
new file mode 100644
index 000000000000..cc4884637dcd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_BITFIELD.bitfield.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Test invocation of offsetof() with a member that is a bit-field.
+ * This should fail at compile time.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ * NOTES:
+ *
+ */
+
+struct foo {
+ int a:1;
+ int b:3;
+};
+
+BEGIN
+{
+ trace(offsetof(struct foo, b));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_TYPE.badtype.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_TYPE.badtype.d
new file mode 100644
index 000000000000..4e8a8858f1ac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_TYPE.badtype.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Test invocation of offsetof() with an invalid type.
+ * This should fail at compile time.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ * NOTES:
+ *
+ */
+
+BEGIN
+{
+ trace(offsetof(struct no_such_type, x));
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_TYPE.notsou.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_TYPE.notsou.d
new file mode 100644
index 000000000000..84209530b20c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_OFFSETOF_TYPE.notsou.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ *
+ * Test invocation of offsetof() with a type that is not a struct or union.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ * NOTES:
+ *
+ */
+
+BEGIN
+{
+ trace(offsetof(int, x));
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_UNKNOWN.OffsetofNULL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_UNKNOWN.OffsetofNULL.d
new file mode 100644
index 000000000000..5a341a3342d3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_UNKNOWN.OffsetofNULL.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Querying the offsetof an non-member variable of a struct throws
+ * a D_UNKNOWN error.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ */
+#pragma D option quiet
+
+struct record {
+ int a;
+ int b;
+ int c : 4;
+};
+
+BEGIN
+{
+ printf("offsetof (struct record, NULL): %d\n",
+ offsetof (struct record, NULL));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_UNKNOWN.badmemb.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_UNKNOWN.badmemb.d
new file mode 100644
index 000000000000..67d4bd9e1b1a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/err.D_UNKNOWN.badmemb.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Test invocation of offsetof() with an invalid member.
+ * This should fail at compile time.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ * NOTES:
+ *
+ */
+
+BEGIN
+{
+ trace(offsetof(struct vnode, v_no_such_member));
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofAlias.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofAlias.d
new file mode 100644
index 000000000000..c7494d20992a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofAlias.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test invocation of offsetof() with a struct type alias.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+typedef struct record {
+ char c;
+ int x;
+ int y;
+} record_t;
+
+BEGIN
+{
+ printf("offsetof(record_t, c) = %d\n", offsetof(record_t, c));
+ printf("offsetof(record_t, x) = %d\n", offsetof(record_t, x));
+ printf("offsetof(record_t, y) = %d\n", offsetof(record_t, y));
+ exit(0);
+}
+
+END
+/(8 != offsetof(record_t, y)) || (4 != offsetof(record_t, x)) ||
+ (0 != offsetof(record_t, c))/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofArith.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofArith.d
new file mode 100644
index 000000000000..7e2b33087940
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofArith.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: offsetof can be used anywhere in a D program that an integer
+ * constant can be used.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+typedef struct record {
+ char c;
+ int x;
+ int y;
+} record_t;
+
+BEGIN
+{
+
+ add = offsetof(record_t, c) + offsetof(record_t, x) +
+ offsetof(record_t, y);
+ sub = offsetof(record_t, y) - offsetof(record_t, x);
+ mul = offsetof(record_t, x) * offsetof(record_t, c);
+ div = offsetof(record_t, y) / offsetof(record_t, x);
+
+ printf("offsetof(record_t, c) = %d\n", offsetof(record_t, c));
+ printf("offsetof(record_t, x) = %d\n", offsetof(record_t, x));
+ printf("offsetof(record_t, y) = %d\n", offsetof(record_t, y));
+
+ printf("Addition of offsets (c+x+y)= %d\n", add);
+ printf("Subtraction of offsets (y-x)= %d\n", sub);
+ printf("Multiplication of offsets (x*c) = %d\n", mul);
+ printf("Division of offsets (y/x) = %d\n", div);
+
+ exit(0);
+}
+
+END
+/(8 != offsetof(record_t, y)) || (4 != offsetof(record_t, x)) ||
+ (0 != offsetof(record_t, c)) || (12 != add) || (4 != sub) || (0 != mul)
+ || (2 != div)/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofUnion.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofUnion.d
new file mode 100644
index 000000000000..de1a5fabd66e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.OffsetofUnion.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test invocation of offsetof() with a union type alias.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+union record {
+ int x;
+ int y;
+ char c;
+};
+
+BEGIN
+{
+ printf("offsetof(record, x) = %d\n", offsetof(union D`record, x));
+ printf("offsetof(record, y) = %d\n", offsetof(union D`record, y));
+ printf("offsetof(record, c) = %d\n", offsetof(union D`record, c));
+ exit(0);
+}
+
+END
+/(0 != offsetof(union D`record, y)) && (0 != offsetof(union D`record, x)) &&
+ (0 != offsetof(union D`record, c))/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.struct.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.struct.d
new file mode 100644
index 000000000000..60b88637e0aa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.struct.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test invocation of offsetof() with a struct type.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+struct s {
+ int x;
+ int y;
+};
+
+BEGIN
+{
+ printf("offsetof(s, y) = %d\n", offsetof(struct D`s, y));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.struct.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.struct.d.out
new file mode 100644
index 000000000000..04b666e2d553
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.struct.d.out
@@ -0,0 +1,2 @@
+offsetof(s, y) = 4
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.union.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.union.d
new file mode 100644
index 000000000000..1b37c4c102c5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.union.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test invocation of offsetof() with a union type.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+union s {
+ int x;
+ int y;
+};
+
+BEGIN
+{
+ printf("offsetof(s, y) = %d\n", offsetof(union D`s, y));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.union.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.union.d.out
new file mode 100644
index 000000000000..e3918bef1e34
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/offsetof/tst.union.d.out
@@ -0,0 +1,2 @@
+offsetof(s, y) = 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/operators/tst.ternary.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/operators/tst.ternary.d
new file mode 100644
index 000000000000..cd3751951b10
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/operators/tst.ternary.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the ternary operator. Test left-hand side true, right-hand side true,
+ * and multiple nested instances of the ternary operator.
+ *
+ * SECTION: Types, Operators, and Expressions/Conditional Expressions
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ x = 0;
+ printf("x is %s\n", x == 0 ? "zero" : "one");
+ x = 1;
+ printf("x is %s\n", x == 0 ? "zero" : "one");
+ x = 2;
+ printf("x is %s\n", x == 0 ? "zero" : x == 1 ? "one" : "two");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/operators/tst.ternary.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/operators/tst.ternary.d.out
new file mode 100644
index 000000000000..ec30800e4a79
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/operators/tst.ternary.d.out
@@ -0,0 +1,4 @@
+x is zero
+x is one
+x is two
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badlib.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badlib.d
new file mode 100644
index 000000000000..a3fa24ffe623
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badlib.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: can't specify a bogus library name
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ */
+
+pid$1:libbmc_sucks.so.1::entry
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badlib.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badlib.exe
new file mode 100644
index 000000000000..e360d25b465b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badlib.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 1000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badproc1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badproc1.d
new file mode 100644
index 000000000000..3f3ca22d4c50
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PDESC_ZERO.badproc1.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Verify that we don't grab bogus process IDs.
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ */
+
+pidgin:::entry
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_BADPID.badproc2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_BADPID.badproc2.d
new file mode 100644
index 000000000000..8e01b060c3f3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_BADPID.badproc2.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Make sure we can't grab pid 0
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ */
+
+pid0:::entry
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_CREATEFAIL.many.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_CREATEFAIL.many.d
new file mode 100644
index 000000000000..dabcd9c6439f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_CREATEFAIL.many.d
@@ -0,0 +1,36 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+pid$1:::
+{
+}
+
+BEGIN
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_CREATEFAIL.many.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_CREATEFAIL.many.exe
new file mode 100644
index 000000000000..7a6d6f23eefa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_CREATEFAIL.many.exe
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 1000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_FUNC.badfunc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_FUNC.badfunc.d
new file mode 100644
index 000000000000..f1c44e866499
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_FUNC.badfunc.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Can't specify a bogus function name (if the module is specified)
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ * NOTES:
+ *
+ */
+
+pid$1:a.out:ahl_r00lz:entry
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_FUNC.badfunc.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_FUNC.badfunc.exe
new file mode 100644
index 000000000000..e360d25b465b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_FUNC.badfunc.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 1000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_LIB.libdash.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_LIB.libdash.d
new file mode 100644
index 000000000000..dd905303c16a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_LIB.libdash.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test that the '-' function doesn't work with random modules
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ */
+
+pid$1:libc:-:800
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_LIB.libdash.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_LIB.libdash.exe
new file mode 100644
index 000000000000..e360d25b465b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_LIB.libdash.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 1000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.alldash.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.alldash.d
new file mode 100644
index 000000000000..6acf8aa0c747
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.alldash.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Verify that you can't enable "all" '-' function probes
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ */
+
+pid$1::-:
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.alldash.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.alldash.exe
new file mode 100644
index 000000000000..e360d25b465b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.alldash.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 1000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.badname.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.badname.d
new file mode 100644
index 000000000000..a27d72105f28
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.badname.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Only entry, return and offsets are valid names
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ */
+
+pid$1:a.out::beginning
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.badname.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.badname.exe
new file mode 100644
index 000000000000..e360d25b465b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.badname.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 1000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.globdash.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.globdash.d
new file mode 100644
index 000000000000..36bf9d6e2371
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.globdash.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Verify that you can't glob the probe name with the '-' function
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ */
+
+pid$1::-:10*
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.globdash.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.globdash.exe
new file mode 100644
index 000000000000..e360d25b465b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_NAME.globdash.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 1000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_OFF.toobig.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_OFF.toobig.d
new file mode 100644
index 000000000000..60e5a8c6edc6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_OFF.toobig.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Can't have an offset that's outside of a function
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ * NOTES: If _exit(2) becomes _way_ more complex this could fail...
+ *
+ */
+
+pid$1::_exit:100
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_OFF.toobig.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_OFF.toobig.exe
new file mode 100644
index 000000000000..e360d25b465b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/err.D_PROC_OFF.toobig.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 1000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.addprobes.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.addprobes.ksh
new file mode 100644
index 000000000000..6c269ca21899
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.addprobes.ksh
@@ -0,0 +1,61 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# This test verifies that it's possible to add new pid probes to an existing
+# pid provider.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+sleep 60 &
+pid=$!
+
+$dtrace -n pid$pid:libc::entry -n 'tick-1s{exit(0);}'
+status=$?
+
+if [ $status -gt 0 ]; then
+ exit $status;
+fi
+
+$dtrace -n pid$pid:libc::return -n 'tick-1s{exit(0);}'
+status=$?
+
+if [ $status -gt 0 ]; then
+ exit $status;
+fi
+
+kill $pid
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.c
new file mode 100644
index 000000000000..e26485005271
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.c
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+go(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6,
+ long arg7, long arg8, long arg9)
+{
+ return (arg1);
+}
+
+static void
+handle(int sig)
+{
+ go(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ (void) signal(SIGUSR1, handle);
+ for (;;)
+ getpid();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.d
new file mode 100644
index 000000000000..a3ad6c9a54ab
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.d
@@ -0,0 +1,75 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: test that all 10 arguments are what we expect them to be.
+ *
+ * SECTION: pid provider
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the first call to getpid(2).
+ */
+ timeout = timestamp + 1000000000;
+}
+
+syscall::getpid:return
+/pid == $1/
+{
+ i = 0;
+ raise(SIGUSR1);
+ /*
+ * Wait half a second after raising the signal.
+ */
+ timeout = timestamp + 500000000;
+}
+
+pid$1:a.out:go:entry
+/arg0 == 0 && arg1 == 1 && arg2 == 2 && arg3 == 3 && arg4 == 4 &&
+arg5 == 5 && arg6 == 6 && arg7 == 7 && arg8 == 8 && arg9 == 9/
+{
+ exit(0);
+}
+
+pid$1:a.out:go:entry
+{
+ printf("wrong args: %d %d %d %d %d %d %d %d %d %d", arg0, arg1, arg2,
+ arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+ exit(1);
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.coverage.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.coverage.d
new file mode 100644
index 000000000000..d3d568e7237b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.coverage.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: test that we can trace every instruction safely
+ *
+ * SECTION: pid provider
+ *
+ */
+
+BEGIN
+{
+ /*
+ * Let's just do this for 2 seconds.
+ */
+ timeout = timestamp + 2000000000;
+}
+
+pid$1:a.out::
+{}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.coverage.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.coverage.exe
new file mode 100644
index 000000000000..ddd0f60f63ce
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.coverage.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+while true; do env > /dev/null; done
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.d
new file mode 100644
index 000000000000..e0fada86c7b9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: the stack() action should be empty for all pid probes
+ *
+ * SECTION: pid provider
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ /*
+ * Monitor the program for two seconds.
+ */
+ timeout = timestamp + 1000000000 * 2;
+}
+
+pid$1:::return
+{
+ @[stack()] = sum(0);
+}
+
+pid$1:a.out::
+{
+ @[stack()] = sum(0);
+}
+
+pid$1:::entry
+{
+ @[stack()] = sum(0);
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.d.out
new file mode 100644
index 000000000000..2304a615122f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.d.out
@@ -0,0 +1,3 @@
+
+
+ 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.exe
new file mode 100644
index 000000000000..6369bc561412
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.emptystack.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+exec find / > /dev/null 2>&1
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.float.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.float.c
new file mode 100644
index 000000000000..450c6aae7ac2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.float.c
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+
+volatile double c = 1.2;
+
+int
+main(int argc, char **argv)
+{
+ double a = 1.56;
+ double b = (double)argc;
+
+ for (;;) {
+ c *= a;
+ c += b;
+ (void) usleep(1000);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.float.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.float.d
new file mode 100644
index 000000000000..4e11ee33b103
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.float.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Make sure we can work on processes that use the FPU
+ *
+ * SECTION: pid provider
+ */
+
+BEGIN
+{
+ /*
+ * Let's just do this for 5 seconds.
+ */
+ timeout = timestamp + 5000000000;
+}
+
+pid$1:a.out:main:
+{}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.fork.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.fork.c
new file mode 100644
index 000000000000..8c2772396a1b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.fork.c
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+
+int
+waiting(volatile int *a)
+{
+ return (*a);
+}
+
+int
+go(void)
+{
+ int i, j, total = 0;
+
+ for (i = 0; i < 10; i++) {
+ for (j = 0; j < 10; j++) {
+ total += i * j;
+ }
+ }
+
+ return (total);
+}
+
+int
+main(int argc, char **argv)
+{
+ volatile int a = 0;
+
+ while (waiting(&a) == 0)
+ continue;
+
+ (void) fork();
+ (void) go();
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.fork.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.fork.d
new file mode 100644
index 000000000000..5be6d301d23f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.fork.d
@@ -0,0 +1,86 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: make sure fork(2) is okay
+ *
+ * SECTION: pid provider
+ */
+
+#pragma D option destructive
+
+pid$1:a.out:waiting:entry
+{
+ this->value = (int *)alloca(sizeof (int));
+ *this->value = 1;
+ copyout(this->value, arg0, sizeof (int));
+}
+
+proc:::create
+/pid == $1/
+{
+ child = args[0]->p_pid;
+ trace(pid);
+}
+
+pid$1:a.out:go:
+/pid == child/
+{
+ trace("wrong pid");
+ exit(1);
+}
+
+proc:::exit
+/pid == $1 || pid == child/
+{
+ out++;
+ trace(pid);
+}
+
+proc:::exit
+/out == 2/
+{
+ exit(0);
+}
+
+
+BEGIN
+{
+ /*
+ * Let's just do this for 5 seconds.
+ */
+ timeout = timestamp + 5000000000;
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.gcc.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.gcc.c
new file mode 100644
index 000000000000..b3959c35e8b3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.gcc.c
@@ -0,0 +1,66 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <spawn.h>
+#include <signal.h>
+#include <stdio.h>
+
+void
+go(void)
+{
+ pid_t pid;
+
+ (void) posix_spawn(&pid, "/bin/ls", NULL, NULL, NULL, NULL);
+
+ (void) waitpid(pid, NULL, 0);
+}
+
+void
+intr(int sig)
+{
+}
+
+int
+main(int argc, char **argv)
+{
+ struct sigaction sa;
+
+ sa.sa_handler = intr;
+ sigfillset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ (void) sigaction(SIGUSR1, &sa, NULL);
+
+ for (;;) {
+ go();
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.gcc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.gcc.d
new file mode 100644
index 000000000000..f119098f03b1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.gcc.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: test that we can trace every instruction safely for gcc
+ * compiled apps.
+ *
+ * SECTION: pid provider
+ *
+ */
+
+BEGIN
+{
+ /*
+ * Let's just do this for 2 seconds.
+ */
+ timeout = timestamp + 2000000000;
+}
+
+pid$1:a.out::
+{}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.killonerror.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.killonerror.ksh
new file mode 100644
index 000000000000..587878c3fc2a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.killonerror.ksh
@@ -0,0 +1,41 @@
+#!/bin/ksh -p
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+#
+# Make sure we kill a process if the dtrace(1M) command fails.
+#
+
+rc=`$dtrace -c date -n jarod 2>/dev/null | /usr/bin/wc -l`
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.main.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.main.ksh
new file mode 100644
index 000000000000..b3b996014027
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.main.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+#
+# Make sure we can trace main:entry properly -- this was problematic because
+# we also set a breakpoint on the same spot in libdtrace.
+#
+
+$dtrace -c date -s /dev/stdin <<EOF
+ BEGIN
+ {
+ status = 1;
+ }
+
+ pid\$target::main:entry
+ {
+ status = 0;
+ }
+
+ END
+ {
+ exit(status);
+ }
+EOF
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.manypids.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.manypids.ksh
new file mode 100644
index 000000000000..ce29cd406bde
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.manypids.ksh
@@ -0,0 +1,70 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+set -A pids
+
+for lib in `ls -1 /lib/lib*.so.1 | grep -v ld.so.1`; do
+ preload=$lib:${preload}
+done
+
+export LD_PRELOAD=$preload
+
+let numkids=100
+let i=0
+
+tmpfile=/tmp/dtest.$$
+
+while [ "$i" -lt "$numkids" ]; do
+ sleep 500 &
+ pids[$i]=$!
+ let i=i+1
+done
+
+export LD_PRELOAD=
+
+let i=0
+
+echo "tick-1sec\n{\n\texit(0);\n}\n" > $tmpfile
+
+while [ "$i" -lt "$numkids" ]; do
+ echo "pid${pids[$i]}::malloc:entry\n{}\n" >> $tmpfile
+ let i=i+1
+done
+
+$dtrace -s $tmpfile
+status=$?
+
+rm $tmpfile
+pkill -P $$ sleep
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh
new file mode 100644
index 000000000000..35f0391ba87d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh
@@ -0,0 +1,62 @@
+#!/bin/ksh -p
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -wZq -x switchrate=100ms -s /dev/stdin <<EOF
+pid*:date::
+{
+ printf("%s:%s\n", probefunc, probename);
+}
+
+tick-1s
+/i++ > 5/
+{
+ exit(0);
+}
+
+tick-1s
+/(i % 2) == 0/
+{
+ system("dtrace -c date -ln 'pid\$target::main:entry' >/dev/null");
+}
+
+tick-1s
+/(i % 2) == 1/
+{
+ system("dtrace -c date -ln 'pid\$target::main:return' >/dev/null");
+}
+EOF
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh.out
new file mode 100644
index 000000000000..b2742c47f91b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh.out
@@ -0,0 +1,7 @@
+main:return
+main:entry
+main:return
+main:entry
+main:return
+main:entry
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.probemod.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.probemod.ksh
new file mode 100644
index 000000000000..326fd1ab9f83
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.probemod.ksh
@@ -0,0 +1,54 @@
+#!/bin/ksh -p
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+#
+# Let's see if we can successfully specify a module using partial
+# matches as well as the full module name. We'll use 'libc.so.1'
+# (and therefore 'libc' and 'libc.so') as it's definitely there.
+#
+
+for lib in libc libc.so libc.so.1 'lib[c]*'; do
+ sleep 60 &
+ pid=$!
+ dtrace -n "pid$pid:$lib::entry" -n 'tick-2s{exit(0);}'
+ status=$?
+
+ kill $pid
+
+ if [ $status -gt 0 ]; then
+ exit $status
+ fi
+done
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex1.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex1.ksh
new file mode 100644
index 000000000000..7b0824eedd7c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex1.ksh
@@ -0,0 +1,93 @@
+#!/bin/ksh -p
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This test verifies that specifying a glob in a pid provider name
+# (e.g., p*d$target) works.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=${TMPDIR:-/tmp}/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > Makefile <<EOF
+all: main
+
+main: main.o
+ cc -o main main.o
+
+main.o: main.c
+ cc -c main.c
+EOF
+
+cat > main.c <<EOF
+void
+go(void)
+{
+}
+
+int
+main(int argc, char **argv)
+{
+ go();
+
+ return (0);
+}
+EOF
+
+make > /dev/null
+if [ $? -ne 0 ]; then
+ print -u2 "failed to build"
+ exit 1
+fi
+
+cat > main.d <<'EOF'
+p*d$target::go:entry
+{
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+}
+EOF
+
+script() {
+ $dtrace -q -s ./main.d -c ./main
+}
+
+script
+status=$?
+
+cd /tmp
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex2.ksh
new file mode 100644
index 000000000000..867fa36a9c15
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex2.ksh
@@ -0,0 +1,131 @@
+#!/bin/ksh -p
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This test verifies that probes will be picked up after a dlopen(3C)
+# when the pid provider is specified as a glob (e.g., p*d$target.)
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=${TMPDIR:-/tmp}/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > Makefile <<EOF
+all: main altlib.so
+
+main: main.o
+ cc -o main main.o
+
+main.o: main.c
+ cc -c main.c
+
+altlib.so: altlib.o
+ cc -shared -o altlib.so altlib.o -lc
+
+altlib.o: altlib.c
+ cc -c altlib.c
+EOF
+
+cat > altlib.c <<EOF
+void
+go(void)
+{
+}
+EOF
+
+cat > main.c <<EOF
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdio.h>
+
+void
+go(void)
+{
+}
+
+int
+main(int argc, char **argv)
+{
+ void *alt;
+ void *alt_go;
+
+ go();
+
+ if ((alt = dlopen("./altlib.so", RTLD_LAZY | RTLD_LOCAL))
+ == NULL) {
+ printf("dlopen of altlib.so failed: %s\n", dlerror());
+ return (1);
+ }
+
+ if ((alt_go = dlsym(alt, "go")) == NULL) {
+ printf("failed to lookup 'go' in altlib.so\n");
+ return (1);
+ }
+
+ ((void (*)(void))alt_go)();
+
+ return (0);
+}
+EOF
+
+make > /dev/null
+if [ $? -ne 0 ]; then
+ print -u2 "failed to build"
+ exit 1
+fi
+
+cat > main.d <<'EOF'
+p*d$target::go:entry
+{
+ @foo[probemod, probefunc, probename] = count();
+}
+
+END
+{
+ printa("%s:%s:%s %@u\n",@foo);
+}
+EOF
+
+script() {
+ $dtrace -q -s ./main.d -c ./main
+}
+
+script
+status=$?
+
+cd /tmp
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex2.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex2.ksh.out
new file mode 100644
index 000000000000..824d89856131
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex2.ksh.out
@@ -0,0 +1,3 @@
+altlib.so:go:entry 1
+main:go:entry 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex3.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex3.ksh
new file mode 100644
index 000000000000..b179169e7dfc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex3.ksh
@@ -0,0 +1,102 @@
+#!/bin/ksh -p
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This test verifies that a regex in the provider name will match
+# USDT probes as well as pid probes (e.g., p*d$target matches both
+# pid$target and pyramid$target.)
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=${TMPDIR:-/tmp}/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > Makefile <<EOF
+all: main
+
+main: main.o prov.o
+ cc -o main main.o prov.o
+
+main.o: main.c prov.h
+ cc -c main.c
+
+prov.h: prov.d
+ $dtrace -h -s prov.d
+
+prov.o: prov.d main.o
+ $dtrace -G -s prov.d main.o
+EOF
+
+cat > prov.d <<EOF
+provider pyramid {
+ probe entry();
+};
+EOF
+
+cat > main.c <<EOF
+#include <sys/sdt.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ PYRAMID_ENTRY();
+}
+EOF
+
+make > /dev/null
+if [ $? -ne 0 ]; then
+ print -u2 "failed to build"
+ exit 1
+fi
+
+cat > main.d <<'EOF'
+p*d$target::main:entry
+{
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+}
+EOF
+
+script() {
+ $dtrace -q -s ./main.d -c ./main
+}
+
+script
+status=$?
+
+cd /tmp
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex3.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex3.ksh.out
new file mode 100644
index 000000000000..5a8938fe02d9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex3.ksh.out
@@ -0,0 +1,3 @@
+main:main:entry
+main:main:entry
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex4.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex4.ksh
new file mode 100644
index 000000000000..26fb02596485
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex4.ksh
@@ -0,0 +1,154 @@
+#!/bin/ksh -p
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This test verifies that USDT probes will be picked up after a dlopen(3C)
+# when a regex in the provider name matches both USDT probes and pid probes
+# (e.g., p*d$target matches both pid$target and pyramid$target.)
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=${TMPDIR:-/tmp}/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > Makefile <<EOF
+all: main altlib.so
+
+main: main.o provmain.o
+ cc -o main main.o provmain.o
+
+main.o: main.c prov.h
+ cc -c main.c
+
+prov.h: prov.d
+ $dtrace -h -s prov.d
+
+provmain.o: prov.d main.o
+ $dtrace -G -32 -o provmain.o -s prov.d main.o
+
+altlib.so: altlib.o provalt.o
+ cc -shared -o altlib.so altlib.o provalt.o -lc
+
+altlib.o: altlib.c prov.h
+ cc -c altlib.c
+
+provalt.o: prov.d altlib.o
+ $dtrace -G -32 -o provalt.o -s prov.d altlib.o
+EOF
+
+cat > prov.d <<EOF
+provider pyramid {
+ probe entry();
+};
+EOF
+
+cat > altlib.c <<EOF
+#include <sys/sdt.h>
+#include "prov.h"
+
+void
+go(void)
+{
+ PYRAMID_ENTRY();
+}
+EOF
+
+cat > main.c <<EOF
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/sdt.h>
+#include "prov.h"
+
+void
+go(void)
+{
+ PYRAMID_ENTRY();
+}
+
+int
+main(int argc, char **argv)
+{
+ void *alt;
+ void *alt_go;
+
+ go();
+
+ if ((alt = dlopen("./altlib.so", RTLD_LAZY | RTLD_LOCAL))
+ == NULL) {
+ printf("dlopen of altlib.so failed: %s\n", dlerror());
+ return (1);
+ }
+
+ if ((alt_go = dlsym(alt, "go")) == NULL) {
+ printf("failed to lookup 'go' in altlib.so\n");
+ return (1);
+ }
+
+ ((void (*)(void))alt_go)();
+
+ return (0);
+}
+EOF
+
+make > /dev/null
+if [ $? -ne 0 ]; then
+ print -u2 "failed to build"
+ exit 1
+fi
+
+cat > main.d <<'EOF'
+p*d$target::go:entry
+{
+ @foo[probemod, probefunc, probename] = count();
+}
+
+END
+{
+ printa("%s:%s:%s %@u\n",@foo);
+}
+EOF
+
+script() {
+ $dtrace -q -s ./main.d -c ./main
+}
+
+script
+status=$?
+
+cd /tmp
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex4.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex4.ksh.out
new file mode 100644
index 000000000000..f4715384f926
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.provregex4.ksh.out
@@ -0,0 +1,3 @@
+altlib.so:go:entry 2
+main:go:entry 2
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret1.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret1.c
new file mode 100644
index 000000000000..12b3f724cb17
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret1.c
@@ -0,0 +1,65 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * The canonical name should be 'go' since we prefer symbol names with fewer
+ * leading underscores.
+ */
+
+int a = 100;
+
+int
+help(void)
+{
+ return (a);
+}
+
+int
+go(void)
+{
+ return (help() + 1);
+}
+
+static void
+handle(int sig)
+{
+ go();
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ (void) signal(SIGUSR1, handle);
+ for (;;)
+ getpid();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret1.d
new file mode 100644
index 000000000000..0305d09868a1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret1.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: test that we get the right return value from non-leaf returns
+ *
+ * SECTION: pid provider
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the first call to getpid(2).
+ */
+ timeout = timestamp + 1000000000;
+}
+
+syscall::getpid:return
+/pid == $1/
+{
+ i = 0;
+ raise(SIGUSR1);
+ /*
+ * Wait half a second after raising the signal.
+ */
+ timeout = timestamp + 500000000;
+}
+
+pid$1:a.out:go:return
+/arg1 == 101/
+{
+ exit(0);
+}
+
+pid$1:a.out:go:return
+{
+ printf("wrong return value: %d", arg1);
+ exit(1);
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret2.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret2.c
new file mode 100644
index 000000000000..ea5394e120f5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret2.c
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * The canonical name should be 'go' since we prefer symbol names with fewer
+ * leading underscores.
+ */
+
+int a = 100;
+
+int
+go(void)
+{
+ return (a);
+}
+
+static void
+handle(int sig)
+{
+ go();
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ (void) signal(SIGUSR1, handle);
+ for (;;)
+ getpid();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret2.d
new file mode 100644
index 000000000000..0232948cc3a3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.ret2.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: test that we get the right return value from leaf returns
+ *
+ * SECTION: pid provider
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the first call to getpid(2).
+ */
+ timeout = timestamp + 1000000000;
+}
+
+syscall::getpid:return
+/pid == $1/
+{
+ i = 0;
+ raise(SIGUSR1);
+ /*
+ * Wait half a second after raising the signal.
+ */
+ timeout = timestamp + 500000000;
+}
+
+pid$1:a.out:go:return
+/arg1 == 100/
+{
+ exit(0);
+}
+
+pid$1:a.out:go:return
+{
+ printf("wrong return value: %d", arg1);
+ exit(1);
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.vfork.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.vfork.c
new file mode 100644
index 000000000000..76fa711a425a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.vfork.c
@@ -0,0 +1,65 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+
+int
+waiting(volatile int *a)
+{
+ return (*a);
+}
+
+int
+go(void)
+{
+ int i, j, total = 0;
+
+ for (i = 0; i < 10; i++) {
+ for (j = 0; j < 10; j++) {
+ total += i * j;
+ }
+ }
+
+ return (total);
+}
+
+int
+main(int argc, char **argv)
+{
+ volatile int a = 0;
+
+ while (waiting(&a) == 0)
+ continue;
+
+ if (vfork() == 0) {
+ int ret = go();
+ (void) _exit(ret);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.vfork.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.vfork.d
new file mode 100644
index 000000000000..e8fc9b4dfba1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.vfork.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: make sure probes called from a vfork(2) child fire in the parent
+ *
+ * SECTION: pid provider
+ */
+
+#pragma D option destructive
+
+pid$1:a.out:waiting:entry
+{
+ this->value = (int *)alloca(sizeof (int));
+ *this->value = 1;
+ copyout(this->value, arg0, sizeof (int));
+}
+
+proc:::create
+/pid == $1/
+{
+ child = args[0]->p_pid;
+}
+
+pid$1:a.out:go:
+/child != pid/
+{
+ printf("wrong pid (%d %d)", pid, child);
+ exit(1);
+}
+
+syscall::exit:entry
+/pid == $1/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak1.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak1.c
new file mode 100644
index 000000000000..765c285dd964
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak1.c
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * The canonical name should be 'go' since we prefer symbol names with fewer
+ * leading underscores.
+ */
+
+#pragma weak _go = go
+
+int
+go(int a)
+{
+ return (a + 1);
+}
+
+static void
+handle(int sig)
+{
+ _go(1);
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ (void) signal(SIGUSR1, handle);
+ for (;;)
+ getpid();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak1.d
new file mode 100644
index 000000000000..458eada0c0ad
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak1.d
@@ -0,0 +1,83 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: test that we prefer symbols with fewer underscores
+ *
+ * SECTION: pid provider
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the first call to getpid(2).
+ */
+ timeout = timestamp + 1000000000;
+}
+
+syscall::getpid:return
+/pid == $1/
+{
+ i = 0;
+ raise(SIGUSR1);
+ /*
+ * Wait half a second after raising the signal.
+ */
+ timeout = timestamp + 500000000;
+}
+
+pid$1:a.out:go:entry,
+pid$1:a.out:_go:entry
+/probefunc == "go"/
+{
+ i++;
+}
+
+pid$1:a.out:go:entry,
+pid$1:a.out:_go:entry
+/probefunc == "_go"/
+{
+ trace("resolved to '_go' rather than 'go'");
+ exit(1);
+}
+
+pid$1:a.out:go:entry,
+pid$1:a.out:_go:entry
+/i == 2/
+{
+ exit(0);
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.c
new file mode 100644
index 000000000000..756745d99b1f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.c
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * The canonical name should be 'go' since we prefer symbol names with fewer
+ * leading underscores.
+ */
+
+static int
+go(int a)
+{
+ return (a + 1);
+}
+
+#pragma weak _go = go
+
+static void
+handle(int sig)
+{
+ _go(1);
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ (void) signal(SIGUSR1, handle);
+ for (;;)
+ getpid();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.d
new file mode 100644
index 000000000000..e3688b56c1fd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.d
@@ -0,0 +1,83 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: check that we prefer weak symbols to local ones
+ *
+ * SECTION: pid provider
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the first call to getpid(2).
+ */
+ timeout = timestamp + 1000000000;
+}
+
+syscall::getpid:return
+/pid == $1/
+{
+ i = 0;
+ raise(SIGUSR1);
+ /*
+ * Wait half a second after raising the signal.
+ */
+ timeout = timestamp + 500000000;
+}
+
+pid$1:a.out:go:entry,
+pid$1:a.out:_go:entry
+/probefunc == "_go"/
+{
+ i++;
+}
+
+pid$1:a.out:go:entry,
+pid$1:a.out:_go:entry
+/probefunc == "go"/
+{
+ trace("resolved to '_go' rather than 'go'");
+ exit(1);
+}
+
+pid$1:a.out:go:entry,
+pid$1:a.out:_go:entry
+/i == 2/
+{
+ exit(0);
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.available.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.available.d
new file mode 100644
index 000000000000..6fc9f2ff36f9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.available.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: make sure the plockstat probes are present in libc.
+ */
+
+plockstat$1:libc.so.1::
+{}
+
+profile:::tick-1
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.available.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.available.exe
new file mode 100644
index 000000000000..c767848bb25d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.available.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 100000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.libmap.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.libmap.d
new file mode 100644
index 000000000000..5f755b3fd2f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.libmap.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: make sure the plockstat probes are present in libc.
+ */
+
+plockstat$1:libc::
+{}
+
+profile:::tick-1
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.libmap.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.libmap.exe
new file mode 100644
index 000000000000..c767848bb25d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/plockstat/tst.libmap.exe
@@ -0,0 +1,29 @@
+#!/usr/bin/env ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 100000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.BadAlign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.BadAlign.d
new file mode 100644
index 000000000000..3923cd910a14
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.BadAlign.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION: This test reproduces the alignment error.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ x = (int *)64;
+ y = *x;
+ trace(y);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.ArrayVar.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.ArrayVar.d
new file mode 100644
index 000000000000..b68320876d32
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.ArrayVar.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Trying to access the address of a user defined array variable should throw
+ * a D_ADDROF_VAR error.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Address Spaces
+ */
+
+#pragma D option quiet
+
+int a[5];
+int *p;
+
+BEGIN
+{
+ p = &a;
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.DynamicVar.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.DynamicVar.d
new file mode 100644
index 000000000000..028a30a4c108
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.DynamicVar.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Trying to access the address of a user defined dynamic variable should throw
+ * a D_ADDROF_VAR error.
+ *
+ * SECTION: Pointers and Arrays/Generic Pointers
+ * SECTION: Pointers and Arrays/Pointers to Dtrace Objects
+ */
+
+#pragma D option quiet
+
+int i;
+int *p;
+
+BEGIN
+{
+ i = 10;
+ p = &i;
+
+ printf("Integer: %d, Pointer: %d\n", i, *p);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.agg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.agg.d
new file mode 100644
index 000000000000..8b5926200e8f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_ADDROF_VAR.agg.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test that the & operator fails with D_ADDROF_VAR if its operand
+ * is a dynamic variable such as an aggregation.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Addresses
+ * SECTION: Pointers and Arrays/Pointers to Dtrace Objects
+ */
+
+BEGIN
+{
+ @a = count();
+ trace(&@a);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_DEREF_NONPTR.noptr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_DEREF_NONPTR.noptr.d
new file mode 100644
index 000000000000..96d25b40dd9b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_DEREF_NONPTR.noptr.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Can not dereference non-pointers
+ *
+ * SECTION: Pointers and Arrays/Pointer Safety
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+int x;
+
+BEGIN
+{
+ b = *x;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_DEREF_VOID.VoidPointerDeref.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_DEREF_VOID.VoidPointerDeref.d
new file mode 100644
index 000000000000..f2fa5b31cb97
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_DEREF_VOID.VoidPointerDeref.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Cannot dereference a void * pointer.
+ *
+ * SECTION: Pointers and Arrays/Generic Pointers
+ */
+
+#pragma D option quiet
+
+void *p;
+
+int array[3];
+
+BEGIN
+{
+ array[0] = 234;
+ array[1] = 334;
+ array[2] = 434;
+
+ p = &array[0];
+
+ printf("array[0]: %d, p: %d\n", array[0], *p);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_ARRFUN.ArrayAssignment.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_ARRFUN.ArrayAssignment.d
new file mode 100644
index 000000000000..94814a7b7aae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_ARRFUN.ArrayAssignment.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Arrays may not be assigned as a whole in D.
+ *
+ * SECTION: Pointers and Arrays/Pointer and Array Relationship
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+int array1[3];
+int array2[3];
+
+BEGIN
+{
+ array1[0] = 200;
+ array1[1] = 400;
+ array1[2] = 600;
+
+ array2[0] = 300;
+ array2[1] = 500;
+ array2[2] = 700;
+
+ array2 = array1;
+
+ printf("array1[0]: %d\tarray2[0]: %d\n", array1[0], array2[0]);
+ printf("array1[1]: %d\tarray2[1]: %d\n", array1[1], array2[1]);
+ printf("array1[2]: %d\tarray2[2]: %d\n", array1[2], array2[2]);
+
+ exit(0);
+
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_INCOMPAT.VoidPointerArith.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_INCOMPAT.VoidPointerArith.d
new file mode 100644
index 000000000000..e81c2bd86cc0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_INCOMPAT.VoidPointerArith.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * May not apply pointer arithmetic to an object of type void *
+ *
+ * SECTION: Pointers and Arrays/Generic Pointers
+ */
+
+#pragma D option quiet
+
+void *p;
+
+BEGIN
+{
+ printf("p: %d\n", (int) p);
+ printf("p+1: %d\n", (int) (p+1));
+ printf("p+2: %d\n", (int) (p+2));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_LVAL.AddressChange.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_LVAL.AddressChange.d
new file mode 100644
index 000000000000..9828240221a9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_LVAL.AddressChange.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: D pointers do not allow invalid address changes.
+ *
+ * SECTION: Pointers and Arrays/Pointer Safety
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ &`kmem_flags = (int *) 0x185ede4;
+ printf("Address of kmem_flags: %d\n", (int) kmemAddress);
+ printf("Value of kmem_flags: %d\n", `kmem_flags);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_PTR.NonPointerAccess.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_PTR.NonPointerAccess.d
new file mode 100644
index 000000000000..6f2532770ddf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_PTR.NonPointerAccess.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Accessing the members of a struct using the pointer notation using a
+ * nonpointer variable throws a D_OP_PTR error.
+ *
+ * SECTION: Structs and Unions/Pointers to Structs
+ *
+ */
+
+#pragma D option quiet
+
+struct myinput_struct {
+ int i;
+ char c;
+};
+
+struct myinput_struct f;
+
+BEGIN
+{
+ f.i = 10;
+ f.c = 'c';
+
+ printf("f->i: %d\tf->c: %c\n", f->i, f->c);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_PTR.badpointer.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_PTR.badpointer.d
new file mode 100644
index 000000000000..b1524e539ae1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_PTR.badpointer.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * -> can only be used with pointer operands.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Address Spaces
+ */
+
+#pragma D option quiet
+
+struct teststruct {
+ int a;
+ int b;
+};
+
+struct teststruct xyz;
+
+BEGIN
+{
+ xyz->a = 1;
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_SOU.BadPointerAccess.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_SOU.BadPointerAccess.d
new file mode 100644
index 000000000000..75635773a6b8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_SOU.BadPointerAccess.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Accessing a pointer to a struct like a non pointer throws a D_OP_SOU.
+ *
+ * SECTION: Structs and Unions/Pointers to Structs
+ *
+ */
+
+#pragma D option quiet
+
+struct myinput_struct {
+ int i;
+ char c;
+};
+
+struct myinput_struct *f;
+BEGIN
+{
+ f.i = 10;
+ f.c = 'c';
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_SOU.badpointer.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_SOU.badpointer.d
new file mode 100644
index 000000000000..1b351f3451c9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.D_OP_SOU.badpointer.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * -> can only be used with pointer to structs and unions.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Address Spaces
+ */
+
+#pragma D option quiet
+
+int *abc;
+
+BEGIN
+{
+ abc->a = 1;
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress1.d
new file mode 100644
index 000000000000..9c9d2f0f905b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress1.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: D pointers do not allow invalid pointer accesses.
+ *
+ * SECTION: Pointers and Arrays/Pointer Safety
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ kmemAddress = &`kmem_flags;
+ *kmemAddress = 20;
+ printf("Address of kmem_flags: %d\n", (int) kmemAddress);
+ printf("Value of kmem_flags: %d\n", `kmem_flags);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress2.d
new file mode 100644
index 000000000000..6c79bfa42016
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress2.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION: D pointers do not allow invalid pointer accesses.
+ *
+ * SECTION: Pointers and Arrays/Pointer Safety
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ x = (int *)alloca(sizeof (int));
+ trace(x);
+ y = (int *) (x - 3300778156056);
+ *y = 3;
+ trace(*y);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress3.d
new file mode 100644
index 000000000000..66c203061d00
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress3.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION: D pointers do not allow invalid pointer accesses.
+ *
+ * SECTION: Pointers and Arrays/Pointer Safety
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ y = (int *)-33007;
+ *y = 3;
+ trace(*y);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress4.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress4.d
new file mode 100644
index 000000000000..f5f49e966fcf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress4.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION: Demonstrating valid memory access.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Addresses
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ x = (int *)alloca(sizeof (int));
+ printf("Address x: %x\n", (int)x);
+ y = (int *)(x - 2);
+ *y = 3;
+ printf("Address y: %x\tValue: %d\n", (int)y, *y);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress5.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress5.d
new file mode 100644
index 000000000000..c4d35e9e3f56
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/err.InvalidAddress5.d
@@ -0,0 +1,84 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * Using integer arithmetic providing a non-aligned memory address will throw
+ * a runtime error.
+ *
+ * SECTION: Pointers and Arrays/Generic Pointers
+ */
+
+#pragma D option quiet
+
+#if defined(__i386) || defined(__amd64)
+#define __x86 1
+#endif
+
+int array[2];
+char *ptr;
+int *p;
+int *q;
+int *r;
+
+BEGIN
+{
+ array[0] = 0x12345678;
+ array[1] = 0xabcdefff;
+
+ ptr = (char *) &array[0];
+
+ p = (int *) (ptr);
+ q = (int *) (ptr + 2);
+ r = (int *) (ptr + 3);
+
+ printf("*p: 0x%x\n", *p);
+ printf("*q: 0x%x\n", *q);
+ printf("*r: 0x%x\n", *r);
+
+ /*
+ * On x86, the above unaligned memory accesses are allowed and should
+ * not result in the ERROR probe firing.
+ */
+#ifdef __x86
+ exit(1);
+#else
+ exit(0);
+#endif
+}
+
+ERROR
+{
+#ifdef __x86
+ exit(0);
+#else
+ exit(1);
+#endif
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer1.d
new file mode 100644
index 000000000000..fb9db752cf76
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer1.d
@@ -0,0 +1,174 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Declare arrays of different data types and verify that the
+ * addresses of the individual elements differ by an amount equal to the number
+ * elements separating them multiplied by the size of each element.
+ *
+ * SECTION: Pointers and Arrays/Array Declarations and Storage;
+ * Pointers and Arrays/Pointer Arithmetic
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+char char_array[5];
+short short_array[5];
+int int_array[5];
+long long_array[5];
+long long long_long_array[5];
+int8_t int8_array[5];
+int16_t int16_array[5];
+int32_t int32_array[5];
+int64_t int64_array[5];
+intptr_t intptr_array[5];
+uint8_t uint8_array[5];
+uint16_t uint16_array[5];
+uint32_t uint32_array[5];
+uint64_t uint64_array[5];
+uintptr_t uintptr_array[5];
+
+/*
+float float_array[5];
+double double_array[5];
+long double long_double_array[5];
+
+string string_array[5];
+*/
+
+struct record {
+ char ch;
+ int in;
+} struct_array[5];
+
+struct {
+ char ch;
+ int in;
+} anon_struct_array[5];
+
+union record {
+ char ch;
+ int in;
+} union_array[5];
+
+union {
+ char ch;
+ int in;
+} anon_union_array[5];
+
+enum colors {
+ RED,
+ GREEN,
+ BLUE
+} enum_array[5];
+
+BEGIN
+{
+ char_var0 = &char_array[0]; char_var2 = &char_array[2];
+ short_var0 = &short_array[0]; short_var3 = &short_array[3];
+ int_var3 = &int_array[3]; int_var5 = &int_array[5];
+
+ long_var0 = &long_array[0]; long_var4 = &long_array[4];
+ long_long_var0 = &long_long_array[0];
+ long_long_var2 = &long_long_array[2];
+ int8_var3 = &int8_array[3]; int8_var5 = &int8_array[5];
+
+ int16_var0 = &int16_array[0]; int16_var4 = &int16_array[4];
+ int32_var0 = &int32_array[0]; int32_var3 = &int32_array[3];
+ int64_var0 = &int64_array[0]; int64_var1 = &int64_array[1];
+
+ uintptr_var0 = &uintptr_array[0]; uintptr_var2 = &uintptr_array[2];
+ struct_var0 = &struct_array[0]; struct_var2 = &struct_array[2];
+ anon_struct_var3 = &anon_struct_array[3];
+ anon_struct_var5 = &anon_struct_array[5];
+
+ union_var0 = &union_array[0]; union_var3 = &union_array[3];
+ anon_union_var0 = &anon_union_array[0];
+ anon_union_var4 = &anon_union_array[4];
+ enum_var0 = &enum_array[0]; enum_var2 = &enum_array[2];
+
+ printf("char_var2 - char_var0: %d\n",
+ (int) char_var2 - (int) char_var0);
+ printf("short_var3 - short_var0: %d\n",
+ (int) short_var3 - (int) short_var0);
+ printf("int_var5 - int_var3: %d\n", (int) int_var5 - (int) int_var3);
+
+ printf("long_var4 - long_var0: %d\n",
+ (int) long_var4 - (int) long_var0);
+ printf("long_long_var2 - long_long_var0: %d\n",
+ (int) long_long_var2 - (int) long_long_var0);
+ printf("int8_var5 - int8_var3: %d\n",
+ (int) int8_var5 - (int) int8_var3);
+
+ printf("int16_var4 - int16_var0: %d\n",
+ (int) int16_var4 - (int) int16_var0);
+ printf("int32_var3 - int32_var0: %d\n",
+ (int) int32_var3 - (int) int32_var0);
+ printf("int64_var1 - int64_var0: %d\n",
+ (int) int64_var1 - (int) int64_var0);
+
+ printf("uintptr_var2 - uintptr_var0: %d\n",
+ (int) uintptr_var2 - (int) uintptr_var0);
+ printf("struct_var2 - struct_var0: %d\n",
+ (int) struct_var2 - (int) struct_var0);
+ printf("anon_struct_var5 - anon_struct_var3: %d\n",
+ (int) anon_struct_var5 - (int) anon_struct_var3);
+
+ printf("union_var3 - union_var0: %d\n",
+ (int) union_var3 - (int) union_var0);
+ printf("anon_union_var4 - anon_union_var0: %d\n",
+ (int) anon_union_var4 - (int) anon_union_var0);
+ printf("enum_var2 - enum_var0: %d\n",
+ (int) enum_var2 - (int) enum_var0);
+ exit(0);
+}
+
+END
+/(2 != ((int) char_var2 - (int) char_var0)) ||
+ (6 != ((int) short_var3 - (int) short_var0)) ||
+ (8 != ((int) int_var5 - (int) int_var3)) ||
+ ((32 != ((int) long_var4 - (int) long_var0)) &&
+ (16 != ((int) long_var4 - (int) long_var0))) ||
+ (16 != ((int) long_long_var2 - (int) long_long_var0)) ||
+ (2 != ((int) int8_var5 - (int) int8_var3))
+ || (8 != ((int) int16_var4 - (int) int16_var0)) ||
+ (12 != ((int) int32_var3 - (int) int32_var0)) ||
+ (8 != ((int) int64_var1 - (int) int64_var0)) ||
+ ((16 != ((int) uintptr_var2 - (int) uintptr_var0))
+ && (8 != ((int) uintptr_var2 - (int) uintptr_var0))) ||
+ (16 != ((int) struct_var2 - (int) struct_var0)) ||
+ (16 != ((int) anon_struct_var5 - (int) anon_struct_var3))
+ || (12 != ((int) union_var3 - (int) union_var0)) ||
+ (16 != ((int) anon_union_var4 - (int) anon_union_var0)) ||
+ (8 != ((int) enum_var2 - (int) enum_var0))/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer2.d
new file mode 100644
index 000000000000..bf645398797e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer2.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: D permits the use of array [] index notation with both pointer
+ * variables and array variables.
+ *
+ * SECTION: Pointers and Arrays/Pointer and Array Relationship
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+int array[5];
+BEGIN
+{
+ array[0] = 100;
+ array[1] = 200;
+ array[2] = 300;
+ array[3] = 400;
+ array[4] = 500;
+
+ p = &array[0];
+
+ printf("array[0]: %d\tp[0]: %d\n", array[0], p[0]);
+ printf("array[1]: %d\tp[1]: %d\n", array[1], p[1]);
+ printf("array[2]: %d\tp[2]: %d\n", array[2], p[2]);
+ printf("array[3]: %d\tp[3]: %d\n", array[3], p[3]);
+ printf("array[4]: %d\tp[4]: %d\n", array[4], p[4]);
+
+ exit(0);
+
+}
+
+END
+/(array[0] != p[0]) || (array[1] != p[1]) || (array[2] != p[2]) ||
+ (array[3] != p[3]) || (array[4] != p[4])/
+{
+ printf("Error");
+ exit(1);
+}
+
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer3.d
new file mode 100644
index 000000000000..a0be13069785
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ArrayPointer3.d
@@ -0,0 +1,72 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: In D, the an array variable can be assigned to a pointer.
+ *
+ * SECTION: Pointers and Arrays/Pointer and Array Relationship
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+int array[5];
+int *p;
+
+BEGIN
+{
+ array[0] = 100;
+ array[1] = 200;
+ array[2] = 300;
+ array[3] = 400;
+ array[4] = 500;
+
+ p = array;
+
+ printf("array[0]: %d\tp[0]: %d\n", array[0], p[0]);
+ printf("array[1]: %d\tp[1]: %d\n", array[1], p[1]);
+ printf("array[2]: %d\tp[2]: %d\n", array[2], p[2]);
+ printf("array[3]: %d\tp[3]: %d\n", array[3], p[3]);
+ printf("array[4]: %d\tp[4]: %d\n", array[4], p[4]);
+
+ exit(0);
+
+}
+
+END
+/(array[0] != p[0]) || (array[1] != p[1]) || (array[2] != p[2]) ||
+ (array[3] != p[3]) || (array[4] != p[4])/
+{
+ printf("Error");
+ exit(1);
+}
+
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.GlobalVar.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.GlobalVar.d
new file mode 100644
index 000000000000..8b7f36e395a0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.GlobalVar.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Pointer declarations are global.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Addresses
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+ kmemAddress = &`kmem_flags;
+ kmemValue = *kmemAddress;
+ printf("Address of kmem_flags: %x\n", (int) kmemAddress);
+ printf("Value of kmem_flags: %d\n", kmemValue);
+}
+
+profile:::tick-1sec
+/(i < 1) && (&`kmem_flags == kmemAddress) && (*kmemAddress == kmemValue)/
+{
+ exit(1);
+}
+
+END
+/(&`kmem_flags == kmemAddress) && (*kmemAddress == kmemValue)/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.IntegerArithmetic1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.IntegerArithmetic1.d
new file mode 100644
index 000000000000..99cbd7e5ee2a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.IntegerArithmetic1.d
@@ -0,0 +1,72 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Integer arithmetic can be performed on pointers by casting to uintptr_t.
+ *
+ * SECTION: Pointers and Arrays/Generic Pointers
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+int array[3];
+uintptr_t uptr;
+int *p;
+int *q;
+int *r;
+
+BEGIN
+{
+ array[0] = 20;
+ array[1] = 40;
+ array[2] = 80;
+
+ uptr = (uintptr_t) &array[0];
+
+ p = (int *) (uptr);
+ q = (int *) (uptr + 4);
+ r = (int *) (uptr + 8);
+
+ printf("array[0]: %d\t*p: %d\n", array[0], *p);
+ printf("array[1]: %d\t*q: %d\n", array[1], *q);
+ printf("array[2]: %d\t*r: %d\n", array[2], *r);
+
+ exit(0);
+}
+
+END
+/(20 != *p) || (40 != *q) || (80 != *r)/
+{
+ printf("Error");
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic1.d
new file mode 100644
index 000000000000..3a96832530e6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic1.d
@@ -0,0 +1,58 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Pointer arithmetic implicitly adjusts the underlying address by
+ * multiplying or dividing the operands by the size of the type referenced
+ * by the pointer.
+ *
+ * SECTION: Pointers and Arrays/Pointer Arithmetic
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+int *x;
+
+BEGIN
+{
+ printf("x: %x\n", (int) x);
+ printf("x + 1: %x\n", (int) (x+1));
+ printf("x + 2: %x\n", (int) (x+2));
+ exit(0);
+}
+
+END
+/(0 != (int) x) || (4 != (int) (x+1)) || (8 != (int) (x+2))/
+{
+ printf("Error");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic2.d
new file mode 100644
index 000000000000..ac55eb448cbf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic2.d
@@ -0,0 +1,72 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * D pointers can be used to refer to consecutive storage locations like
+ * arrays.
+ *
+ * SECTION: Pointers and Arrays/Pointer and Array Relationship
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+int array[5];
+BEGIN
+{
+ array[0] = 100;
+ array[1] = 200;
+ array[2] = 300;
+ array[3] = 400;
+ array[4] = 500;
+
+ p = &array[0];
+
+ printf("array[0]: %d\t*p: %d\n", array[0], *p);
+ printf("array[1]: %d\t*(p+1): %d\n", array[1], *(p+1));
+ printf("array[2]: %d\t*(p+2): %d\n", array[2], *(p+2));
+ printf("array[3]: %d\t*(p+3): %d\n", array[3], *(p+3));
+ printf("array[4]: %d\t*(p+4): %d\n", array[4], *(p+4));
+
+ exit(0);
+
+}
+
+END
+/(array[0] != *p) || (array[1] != *(p+1)) || (array[2] != *(p+2))
+ || (array[3] != *(p+3)) || (array[4] != *(p+4))/
+{
+ printf("Error");
+ exit(1);
+}
+
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic3.d
new file mode 100644
index 000000000000..a4f4bfc4834d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerArithmetic3.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Pointer arithmetic implicitly adjusts the underlying address by
+ * multiplying or dividing the operands by the size of the type referenced
+ * by the pointer.
+ *
+ * SECTION: Pointers and Arrays/Pointer Arithmetic
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+int *x;
+int *y;
+int a[5];
+
+BEGIN
+{
+ x = &a[0];
+ y = &a[2];
+
+ printf("y-x: %x\n", (int) (y-x));
+ exit(0);
+}
+
+END
+/(2 != (int) (y-x)) /
+{
+ printf("Error");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerAssignment.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerAssignment.d
new file mode 100644
index 000000000000..3a4968695dcf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.PointerAssignment.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Pointers assignment simply copies over the pointer address in the
+ * variable on the right hand side into the variable on the left hand side.
+ *
+ * SECTION: Pointers and Arrays/Pointer and Array Relationship
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+int array[3];
+int *ptr1;
+int *ptr2;
+
+BEGIN
+{
+ array[0] = 200;
+ array[1] = 400;
+ array[2] = 600;
+
+ ptr1 = array;
+ ptr2 = ptr1;
+
+ ptr2[0] = 400;
+ ptr2[1] = 800;
+ ptr2[2] = 1200;
+
+ printf("array[0]: %d\tptr2[0]: %d\n", array[0], ptr2[0]);
+ printf("array[1]: %d\tptr2[1]: %d\n", array[1], ptr2[1]);
+ printf("array[2]: %d\tptr2[2]: %d\n", array[2], ptr2[2]);
+
+ exit(0);
+
+}
+
+END
+/(array[0] != 400) || (array[1] != 800) || (array[2] != 1200)/
+{
+ printf("Error");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ValidPointer1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ValidPointer1.d
new file mode 100644
index 000000000000..5d9db388cbb3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ValidPointer1.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Demonstrating valid memory access.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Addresses
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ x = (int *)alloca(sizeof (int));
+ printf("Address x: %x\n", (int) x);
+ y = (int *) (x);
+ *y = 3;
+ printf("Address y: %x\tValue: %d\n", (int) y, *y);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ValidPointer2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ValidPointer2.d
new file mode 100644
index 000000000000..26d698aea3b2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.ValidPointer2.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Demonstrating valid memory access.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Addresses
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ x = (int *)alloca(sizeof (int));
+ printf("Address x: %x\n", (int) x);
+ y = (int *) (x + 2);
+ *y = 3;
+ printf("Address y: %x\tValue: %d\n", (int) y, *y);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.VoidCast.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.VoidCast.d
new file mode 100644
index 000000000000..296fdf408fc7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.VoidCast.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Can dereference a void * pointer only by casting it to another type.
+ *
+ * SECTION: Pointers and Arrays/Generic Pointers
+ */
+
+#pragma D option quiet
+
+void *p;
+
+int array[3];
+
+BEGIN
+{
+ array[0] = 234;
+ array[1] = 334;
+ array[2] = 434;
+
+ p = &array[0];
+ newp = (int *) p;
+
+ printf("array[0]: %d, newp: %d\n", array[0], *newp);
+ exit(0);
+}
+
+END
+/234 != *newp/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.basic1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.basic1.d
new file mode 100644
index 000000000000..bf3154a0d2cf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.basic1.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Pointers can be stored in variables.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Addresses
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ kmemAddress = &`kmem_flags;
+ kmemValue = *kmemAddress;
+ printf("Address of kmem_flags: %x\n", (int) kmemAddress);
+ printf("Value of kmem_flags: %d\n", kmemValue);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.basic2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.basic2.d
new file mode 100644
index 000000000000..6b72b632e53d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pointers/tst.basic2.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Pointers can be stored in associative arrays.
+ *
+ * SECTION: Pointers and Arrays/Pointers and Addresses
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ assoc_array["kmemAddress"] = &`kmem_flags;
+ kmemValue = *(assoc_array["kmemAddress"]);
+ printf("Address of kmem_flags: %x\n", (int) assoc_array["kmemAddress"]);
+ printf("Value of kmem_flags: %d\n", kmemValue);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGERR.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGERR.d
new file mode 100644
index 000000000000..863ddc863a17
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGERR.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify pragma errors
+ *
+ * SECTION: Pragmas
+ */
+
+
+#pragma D error "this is an error message"
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_DEPEND.main.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_DEPEND.main.d
new file mode 100644
index 000000000000..0b5a3402b874
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_DEPEND.main.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * It isn't permitted for a main program to contain a depends_on imperative.
+ */
+
+#pragma D depends_on library net.d
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_INVAL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_INVAL.d
new file mode 100644
index 000000000000..c6fd1471bad1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_INVAL.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify invalid attributes
+ *
+ * SECTION: Pragmas;
+ * Stabilty/Interface Attributes
+ */
+
+
+inline int foo
+
+#pragma D attributes incorrect_attr foo
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_MALFORM.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_MALFORM.d
new file mode 100644
index 000000000000..7f0ba2329b98
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_MALFORM.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify malformed pragma argument list
+ *
+ * SECTION: Pragmas
+ */
+
+
+#pragma D attributes incorrect_attr
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_UNUSED.UnusedPragma.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_UNUSED.UnusedPragma.d
new file mode 100644
index 000000000000..da2336bc2b69
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.D_PRAGMA_UNUSED.UnusedPragma.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Unused pragmas throw error D_PRAGMA_UNUSED
+ *
+ * SECTION: Errtags/D_PRAGMA_UNUSED
+ *
+ */
+
+void func(int, int);
+
+#pragma D option quiet
+#pragma D attributes Stable/Stable/Common func;
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.circlibdep.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.circlibdep.ksh
new file mode 100644
index 000000000000..6fbace8d1a87
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.circlibdep.ksh
@@ -0,0 +1,58 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+libdir=${TMPDIR:-/tmp}/libdep.$$
+dtrace=$1
+
+setup_libs()
+{
+ mkdir $libdir
+ cat > $libdir/liba.$$.d <<EOF
+#pragma D depends_on library libb.$$.d
+EOF
+ cat > $libdir/libb.$$.d <<EOF
+#pragma D depends_on library libc.$$.d
+EOF
+ cat > $libdir/libc.$$.d <<EOF
+#pragma D depends_on library liba.$$.d
+EOF
+}
+
+
+setup_libs
+
+$dtrace -L$libdir -e
+
+status=$?
+rm -rf $libdir
+return $status
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.invalidlibdep.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.invalidlibdep.ksh
new file mode 100644
index 000000000000..b05ae3dcf877
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/err.invalidlibdep.ksh
@@ -0,0 +1,57 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+libdir=${TMPDIR:-/tmp}/libdep.$$
+dtrace=$1
+
+setup_libs()
+{
+ mkdir $libdir
+ cat > $libdir/liba.$$.d <<EOF
+#pragma D depends_on library libnotthere.$$.d
+EOF
+ cat > $libdir/libb.$$.d <<EOF
+#pragma D depends_on library libc.$$.d
+EOF
+ cat > $libdir/libc.$$.d <<EOF
+#pragma D depends_on library liba.$$.d
+EOF
+}
+
+
+setup_libs
+
+$dtrace -L$libdir -e
+
+status=$?
+rm -rf $libdir
+return $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libchain.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libchain.ksh
new file mode 100644
index 000000000000..7c92243f25f1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libchain.ksh
@@ -0,0 +1,58 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+libdir=${TMPDIR:-/tmp}/libdep.$$
+dtrace=$1
+
+setup_libs()
+{
+ mkdir $libdir
+ cat > $libdir/liba.$$.d <<EOF
+#pragma D depends_on library libb.$$.d
+
+inline int foo = bar;
+EOF
+ cat > $libdir/libb.$$.d <<EOF
+#pragma D depends_on module doogle_knows_all_probes
+
+inline int bar = 0xd0061e;
+EOF
+}
+
+
+setup_libs
+
+$dtrace -L$libdir -e
+
+status=$?
+rm -rf $libdir
+return $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdep.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdep.ksh
new file mode 100644
index 000000000000..38b34606c6ff
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdep.ksh
@@ -0,0 +1,66 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+libdir=${TMPDIR:-/tmp}/libdep.$$
+dtrace=$1
+
+setup_libs()
+{
+ mkdir $libdir
+ cat > $libdir/liba.$$.d <<EOF
+#pragma D depends_on library libb.$$.d
+#pragma D depends_on library libc.$$.d
+#pragma D depends_on library libd.$$.d
+EOF
+ cat > $libdir/libb.$$.d <<EOF
+#pragma D depends_on library libc.$$.d
+EOF
+ cat > $libdir/libc.$$.d <<EOF
+EOF
+ cat > $libdir/libd.$$.d <<EOF
+EOF
+ cat > $libdir/libe.$$.d <<EOF
+#pragma D depends_on library liba.$$.d
+EOF
+ cat > $libdir/libf.$$.d <<EOF
+EOF
+}
+
+
+setup_libs
+
+$dtrace -L$libdir -e
+
+status=$?
+rm -rf $libdir
+return $status
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdepfullyconnected.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdepfullyconnected.ksh
new file mode 100644
index 000000000000..e95de696dd23
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdepfullyconnected.ksh
@@ -0,0 +1,100 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This test verifies that we can generate the correct ordering for
+# a given dependency specification. All files either have a dependency
+# on another file or are the dependent of another file. In this way we
+# guarantee consistent ordering as no nodes in the dependency graph will
+# be isolated.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+tmpfile=/tmp/libdeporder.$$
+libdir=${TMPDIR:-/tmp}/libdep.$$
+dtrace=$1
+
+setup_libs()
+{
+ mkdir $libdir
+ cat > $libdir/liba.$$.d <<EOF
+#pragma D depends_on library libd.$$.d
+EOF
+ cat > $libdir/libb.$$.d <<EOF
+EOF
+ cat > $libdir/libc.$$.d <<EOF
+#pragma D depends_on library libe.$$.d
+EOF
+ cat > $libdir/libd.$$.d <<EOF
+#pragma D depends_on library libb.$$.d
+EOF
+ cat > $libdir/libe.$$.d <<EOF
+#pragma D depends_on library liba.$$.d
+EOF
+}
+
+
+setup_libs
+
+DTRACE_DEBUG=1 $dtrace -L$libdir -e >$tmpfile 2>&1
+
+perl /dev/stdin $tmpfile <<EOF
+
+ @order = qw(libc libe liba libd libb);
+
+ while (<>) {
+ if (\$_ =~ /lib[a-e]\.[0-9]+.d/) {
+ \$pos = length \$_;
+ for (\$i=0; \$i<=1;\$i++) {
+ \$pos = rindex(\$_, "/", \$pos);
+ \$pos--;
+ }
+
+ push(@new, substr(\$_, \$pos+2, 4));
+ next;
+ }
+ next;
+ }
+
+ exit 1 if @new != @order;
+
+ while (@new) {
+ exit 1 if pop(@new) ne pop(@order);
+ }
+
+ exit 0;
+EOF
+
+
+status=$?
+rm -rf $libdir
+rm $tmpfile
+return $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdepsepdir.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdepsepdir.ksh
new file mode 100644
index 000000000000..ced65849b98d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.libdepsepdir.ksh
@@ -0,0 +1,76 @@
+#
+# 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 (c) 2011, Joyent Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Test to catch that we properly look for libraries dependencies in
+# our full library parth
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+libdira=${TMPDIR:-/tmp}/libdepa.$$
+libdirb=${TMPDIR:-/tmp}/libdepb.$$
+libdirc=${TMPDIR:-/tmp}/libdepc.$$
+dtrace=$1
+
+setup_libs()
+{
+ mkdir $libdira
+ mkdir $libdirb
+ mkdir $libdirc
+ cat > $libdira/liba.$$.d <<EOF
+#pragma D depends_on library libb.$$.d
+#pragma D depends_on library libc.$$.d
+#pragma D depends_on library libd.$$.d
+EOF
+ cat > $libdirb/libb.$$.d <<EOF
+#pragma D depends_on library libc.$$.d
+EOF
+ cat > $libdirb/libc.$$.d <<EOF
+EOF
+ cat > $libdirb/libd.$$.d <<EOF
+EOF
+ cat > $libdirc/libe.$$.d <<EOF
+#pragma D depends_on library liba.$$.d
+EOF
+ cat > $libdirc/libf.$$.d <<EOF
+EOF
+}
+
+
+setup_libs
+
+$dtrace -L$libdira -L$libdirb -L$libdirc -e
+
+status=$?
+rm -rf $libdira
+rm -rf $libdirb
+rm -rf $libdirc
+return $status
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh
new file mode 100644
index 000000000000..f09c71fa59c7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh
@@ -0,0 +1,106 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+############################################################################
+# ASSERTION:
+# temporal option causes output to be sorted
+#
+# SECTION: Pragma
+#
+# NOTES: The temporal option has no effect on a single-CPU system, so
+# this needs to be run on a multi-CPU system to effectively test the
+# temporal option.
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+file=/tmp/out.$$
+
+rm -f $file
+
+$dtrace -o $file -c 'sleep 3' -s /dev/stdin <<EOF
+ #pragma D option quiet
+ #pragma D option temporal
+
+ BEGIN
+ {
+ @lines = count();
+ printf("0 begin\n");
+ }
+
+ END
+ {
+ /* Bump @lines every time we print a line. */
+ @lines = count();
+ printf("%u end\n", timestamp);
+ @lines = count();
+ printa("99999999999999999 lines %@u\n", @lines);
+ }
+
+ profile-97hz
+ {
+ @lines = count();
+ printf("%u\n", timestamp);
+ }
+EOF
+
+status=$?
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+ exit $status
+fi
+
+# dtrace outputs a blank line at the end, which will sort to the beginning,
+# so use sed to remove the blank line.
+sed '$d' $file > $file.2
+
+sort -n $file.2 | diff $file.2 -
+status=$?
+if [ "$status" -ne 0 ]; then
+ echo $tst: output is not sorted
+ exit $status
+fi
+
+head -n 1 $file.2 | grep begin >/dev/null
+status=$?
+if [ "$status" -ne 0 ]; then
+ echo $tst: begin probe did not fire
+ exit $status
+fi
+
+tail -n 2 $file.2 | grep end >/dev/null
+status=$?
+if [ "$status" -ne 0 ]; then
+ echo $tst: end probe did not fire
+ exit $status
+fi
+
+if [ $(tail -n 1 $file.2 | cut -f3 -d ' ') -ne \
+ $(wc -l $file.2) ]; then
+ echo $tst: incorrect number of lines output
+ exit 1
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal2.ksh
new file mode 100644
index 000000000000..05b078a7d216
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal2.ksh
@@ -0,0 +1,102 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+############################################################################
+# ASSERTION:
+# temporal option causes output to be sorted, even when some
+# buffers are empty
+#
+# SECTION: Pragma
+#
+# NOTES: The temporal option has no effect on a single-CPU system, so
+# this needs to be run on a multi-CPU system to effectively test the
+# temporal option.
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+file=/tmp/out.$$
+
+rm -f $file
+
+$dtrace -o $file -s /dev/stdin <<EOF
+ #pragma D option quiet
+ #pragma D option destructive
+ #pragma D option temporal
+ #pragma D option switchrate=1000hz
+
+ /*
+ * Use two enablings of the same probe, so that cpu 0 will always
+ * record its data just a little bit before the other cpus.
+ * We don't want to use the chill() action in the same enabling
+ * that we record the timestamp, because chill() causes the
+ * timestamp to be re-read, and thus not match the timestamp
+ * which libdtrace uses to sort the records.
+ */
+
+ profile-401
+ /cpu == 0/
+ {
+ printf("%d\n", timestamp);
+ }
+
+ profile-401
+ /cpu != 0/
+ {
+ chill(1000); /* one microsecond */
+ }
+
+ profile-401
+ /cpu != 0/
+ {
+ printf("%d\n", timestamp);
+ }
+
+ tick-1s
+ /k++ == 10/
+ {
+ printf("%d\n", timestamp);
+ exit(0);
+ }
+EOF
+
+status=$?
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+ exit $status
+fi
+
+# dtrace outputs a blank line at the end, which will sort to the beginning,
+# so use sed to remove the blank line.
+sed '$d' $file > $file.2
+
+sort -n $file.2 | diff $file.2 -
+status=$?
+if [ "$status" -ne 0 ]; then
+ echo $tst: output is not sorted
+ exit $status
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal3.d
new file mode 100644
index 000000000000..b4c0e557bea1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pragma/tst.temporal3.d
@@ -0,0 +1,48 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * This test excercises the "remnant" handling of the temporal option.
+ * At the end of one pass of retrieving and printing data from all CPUs,
+ * some unprocessed data will remain, because its timestamp is after the
+ * time covered by all CPUs' buffers. This unprocessed data is
+ * rearranged in a more space-efficient manner. If this is done
+ * incorrectly, an alignment error may occur. To test this, we use a
+ * high-frequency probe so that data will be recorded in subsequent
+ * CPU's buffers after the first CPU's buffer is obtained. The
+ * combination of data traced here (a 8-byte value and a 4-byte value)
+ * is effective to cause alignment problems with an incorrect
+ * implementation.
+ *
+ * This test needs to be run on a multi-CPU system to be effective.
+ */
+
+#pragma D option quiet
+#pragma D option temporal
+
+profile-4997
+{
+ printf("%u %u", 1ULL, 2);
+}
+
+tick-1
+/i++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_PRED_SCALAR.NonScalarPred.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_PRED_SCALAR.NonScalarPred.d
new file mode 100644
index 000000000000..5f02b7a49225
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_PRED_SCALAR.NonScalarPred.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Predicate result must be of scalar type.
+ *
+ * SECTION: Errtags/ D_PRED_SCALAR
+ *
+ */
+
+#pragma D option quiet
+int a[4];
+
+BEGIN
+/a/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_SYNTAX.invalid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_SYNTAX.invalid.d
new file mode 100644
index 000000000000..391d4256f793
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_SYNTAX.invalid.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple if,then operation test.
+ * Call invalid conditions and make sure it gives compilation error.
+ *
+ * SECTION: Program Structure/Predicates
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile-1
+/i < != > 10/
+{
+ i++;
+ trace(i);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_SYNTAX.operr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_SYNTAX.operr.d
new file mode 100644
index 000000000000..8ffab279aa31
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/err.D_SYNTAX.operr.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple if,then operations test.
+ * Call impossible conditions and make sure compilation fails.
+ *
+ * SECTION: Program Structure/Predicates
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile-1
+/i != 0 && >= 5 || <= 10/
+{
+ i++;
+ trace(i);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.argsnotcached.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.argsnotcached.d
new file mode 100644
index 000000000000..f461c5ddfaf3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.argsnotcached.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+int schedules;
+int executes;
+
+/*
+ * This script is a bit naughty: it's assuming the implementation of the
+ * VM system's page scanning. If this implementation changes -- either by
+ * changing the function that scans pages or by making that scanning
+ * multithreaded -- this script will break.
+ */
+fbt::timeout:entry
+/args[0] == (void *)&genunix`schedpaging/
+{
+ schedules++;
+}
+
+fbt::schedpaging:entry
+/executes == 10/
+{
+ printf("%d schedules, %d executes\n", schedules, executes);
+ exit(executes == schedules ? 0 : 1);
+}
+
+fbt::schedpaging:entry
+{
+ executes++;
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.basics.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.basics.d
new file mode 100644
index 000000000000..9b43b6198a17
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.basics.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple if,then operations test.
+ * Call simple expressions and make sure test satisfy conditions.
+ * Match expected output in tst.basics.d.out
+ *
+ * SECTION: Program Structure/Predicates
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i < 10/
+{
+ i++;
+ trace(i);
+}
+
+tick-10ms
+/i == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.basics.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.basics.d.out
new file mode 100644
index 000000000000..2a5b99aac6cd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.basics.d.out
@@ -0,0 +1 @@
+12345678910
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.complex.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.complex.d
new file mode 100644
index 000000000000..d08543f06013
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.complex.d
@@ -0,0 +1,126 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Complex operations and if,then test.
+ * Call 'n' permutation and combination of operations over if,then.
+ * Match expected output in tst.complex.d.out
+ *
+ * SECTION: Program Structure/Predicates
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+ j = 0;
+}
+
+tick-10ms
+/i < 10/
+{
+ i++;
+ j++;
+ printf("\n\n%d\n------\n", i);
+}
+
+tick-10ms
+/i == 5 || i == 10/
+{
+ printf("i == 5 (or) i == 10\n");
+}
+
+tick-10ms
+/i <= 5/
+{
+ printf("i <= 5\n");
+}
+
+tick-10ms
+/j >= 5/
+{
+ printf("j >= 5\n");
+}
+
+tick-10ms
+/j >= 5 || i <= 5/
+{
+ printf("i >= 5 || j >= 5\n");
+}
+
+tick-10ms
+/j >= 5 && i <= 5/
+{
+ printf("j >= 5 && i <= 55\n");
+}
+
+tick-10ms
+/i < 5/
+{
+ printf("i < 5\n");
+}
+
+tick-10ms
+/i == 2 || j == 2/
+{
+ printf("i == 2 (or) j == 2\n");
+}
+
+tick-10ms
+/i == 2 && j == 2/
+{
+ printf("i == 2 (and) j == 2\n");
+}
+
+tick-10ms
+/j != 10/
+{
+ printf("j != 10\n");
+}
+
+tick-10ms
+/j == 5 || i == 2/
+{
+ printf("j == 5 || i == 2\n");
+}
+
+tick-10ms
+/j == 5 && i == 2/
+{
+ printf("j == 5 && i == 2\n");
+}
+
+tick-10ms
+/i == 10/
+{
+ printf("i == 10\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.complex.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.complex.d.out
new file mode 100644
index 000000000000..5f16dbdbcc13
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.complex.d.out
@@ -0,0 +1,83 @@
+
+
+1
+------
+i <= 5
+i >= 5 || j >= 5
+i < 5
+j != 10
+
+
+2
+------
+i <= 5
+i >= 5 || j >= 5
+i < 5
+i == 2 (or) j == 2
+i == 2 (and) j == 2
+j != 10
+j == 5 || i == 2
+
+
+3
+------
+i <= 5
+i >= 5 || j >= 5
+i < 5
+j != 10
+
+
+4
+------
+i <= 5
+i >= 5 || j >= 5
+i < 5
+j != 10
+
+
+5
+------
+i == 5 (or) i == 10
+i <= 5
+j >= 5
+i >= 5 || j >= 5
+j >= 5 && i <= 55
+j != 10
+j == 5 || i == 2
+
+
+6
+------
+j >= 5
+i >= 5 || j >= 5
+j != 10
+
+
+7
+------
+j >= 5
+i >= 5 || j >= 5
+j != 10
+
+
+8
+------
+j >= 5
+i >= 5 || j >= 5
+j != 10
+
+
+9
+------
+j >= 5
+i >= 5 || j >= 5
+j != 10
+
+
+10
+------
+i == 5 (or) i == 10
+j >= 5
+i >= 5 || j >= 5
+i == 10
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.predcache.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.predcache.ksh
new file mode 100644
index 000000000000..f06edcb5a4ec
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/predicates/tst.predcache.ksh
@@ -0,0 +1,197 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+unload()
+{
+ #
+ # Get the list of services whose processes have USDT probes. Ideally
+ # it would be possible to unload the fasttrap provider while USDT
+ # probes exist -- once that fix is integrated, this hack can go away
+ # We create two lists -- one of regular SMF services and one of legacy
+ # services -- since each must be enabled and disabled using a specific
+ # mechanism.
+ #
+ pids=$(dtrace -l | \
+ perl -ne 'print "$1\n" if (/^\s*\S+\s+\S*\D(\d+)\s+/);' | \
+ sort | uniq | tr '\n' ',')
+
+ ctids=$(ps -p $pids -o ctid | tail +2 | sort | uniq)
+ svcs=
+ lrcs=
+
+ for ct in $ctids
+ do
+ line=$(svcs -o fmri,ctid | grep " $ct\$")
+ svc=$(echo $line | cut -d' ' -f1)
+
+ if [[ $(svcs -Ho STA $svc) == "LRC" ]]; then
+ lrc=$(svcs -Ho SVC $svc | tr _ '?')
+ lrcs="$lrcs $lrc"
+ else
+ svcs="$svcs $svc"
+ fi
+ done
+
+ for svc in $svcs
+ do
+ svcadm disable -ts $svc
+ done
+
+ for lrc in $lrcs
+ do
+ #
+ # Does it seem a little paternalistic that lsvcrun requires
+ # this environment variable to be set? I'd say so...
+ #
+ SMF_RESTARTER=svc:/system/svc/restarter:default \
+ /lib/svc/bin/lsvcrun $lrc stop
+ done
+
+ modunload -i 0
+ modunload -i 0
+ modunload -i 0
+ modinfo | grep dtrace
+ success=$?
+
+ for svc in $svcs
+ do
+ svcadm enable -ts $svc
+ done
+
+ for lrc in $lrcs
+ do
+ SMF_RESTARTER=svc:/system/svc/restarter:default \
+ /lib/svc/bin/lsvcrun $lrc start
+ done
+
+ if [ ! $success ]; then
+ echo $tst: could not unload dtrace
+ exit 1
+ fi
+}
+
+script1()
+{
+ $dtrace -s /dev/stdin <<EOF
+ syscall:::entry
+ /pid != $ppid/
+ {
+ @a[probefunc] = count();
+ }
+
+ tick-1sec
+ /i++ == 5/
+ {
+ exit(0);
+ }
+EOF
+}
+
+script2()
+{
+ $dtrace -s /dev/stdin <<EOF
+
+ #pragma D option statusrate=1ms
+
+ syscall:::entry
+ /pid == $ppid/
+ {
+ ttl++;
+ }
+
+ tick-1sec
+ /i++ == 5/
+ {
+ exit(2);
+ }
+
+ END
+ /ttl/
+ {
+ printf("success; ttl is %d", ttl);
+ exit(0);
+ }
+
+ END
+ /ttl == 0/
+ {
+ printf("error -- total should be non-zero");
+ exit(1);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+ppid=$$
+dtrace=$1
+
+unload
+script1 &
+child=$!
+
+let waited=0
+
+while [ "$waited" -lt 5 ]; do
+ seconds=`date +%S`
+
+ if [ "$seconds" -ne "$last" ]; then
+ last=$seconds
+ let waited=waited+1
+ fi
+done
+
+wait $child
+status=$?
+
+if [ "$status" -ne 0 ]; then
+ echo $tst: first dtrace failed
+ exit $status
+fi
+
+unload
+script2 &
+child=$!
+
+let waited=0
+
+while [ "$waited" -lt 10 ]; do
+ seconds=`date +%S`
+
+ if [ "$seconds" -ne "$last" ]; then
+ last=$seconds
+ let waited=waited+1
+ fi
+done
+
+wait $child
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_IDENT_UNDEF.afterprobe.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_IDENT_UNDEF.afterprobe.d
new file mode 100644
index 000000000000..ac63b43e3409
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_IDENT_UNDEF.afterprobe.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ *
+ * Declare 'ifdef' statements after probe clause definition and
+ * attempt to print the value before that.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
+#if !defined (FLAG)
+#define VALUE 5
+#endif
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_PRAGCTL_INVAL.tabdefine.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_PRAGCTL_INVAL.tabdefine.d
new file mode 100644
index 000000000000..e79ad2e56782
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_PRAGCTL_INVAL.tabdefine.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call #define statement not in first column, just after a tab.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+ #define VALUE 5
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The VALUE is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_SYNTAX.withoutpound.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_SYNTAX.withoutpound.d
new file mode 100644
index 000000000000..aac2bcf92859
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.D_SYNTAX.withoutpound.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Just call a 'define' statement without '#'
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+define VALUE 5
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.defincomp.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.defincomp.d
new file mode 100644
index 000000000000..750ce6dd1c03
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.defincomp.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a incomplete #define statement
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#define
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefelsenotendif.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefelsenotendif.d
new file mode 100644
index 000000000000..6ad696a7b691
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefelsenotendif.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call ifdef statement without endif statement.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined (FLAG)
+#define RETURN 5
+#else
+#define RETURN 10
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", RETURN);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefincomp.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefincomp.d
new file mode 100644
index 000000000000..37c637c91bd2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefincomp.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call a 'if !defined' incomplete statement.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined
+#define VALUE 5
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefnotendif.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefnotendif.d
new file mode 100644
index 000000000000..09fdb170efe5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.ifdefnotendif.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Call a complete '!ifdefine' statement but without 'endif' statement.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined (FLAG)
+#define VALUE 5
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.incompelse.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.incompelse.d
new file mode 100644
index 000000000000..ee92f69cef5c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.incompelse.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Just call a #else statement
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#else
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.mulelse.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.mulelse.d
new file mode 100644
index 000000000000..958f4e2b1757
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/err.mulelse.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Attempt to declare a multiple else 'ifdef' declarations.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined (FLAG)
+#define VALUE 5
+#else
+#define VALUE 10
+#else
+#define VALUE 15
+#else
+#define VALUE 20
+#endif
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifdef.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifdef.d
new file mode 100644
index 000000000000..a17ee0e21f40
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifdef.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple test to test 'if defined' 'defined' 'else' 'endif'
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if defined (FLAG)
+#define VALUE 5
+#else
+#define VALUE 10
+#endif
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifdef.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifdef.d.out
new file mode 100644
index 000000000000..2bde5e931ce2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifdef.d.out
@@ -0,0 +1,2 @@
+The value is 10
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifndef.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifndef.d
new file mode 100644
index 000000000000..b40cf012c372
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifndef.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple test for 'ifndef'.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#ifndef FLAG
+#define FLAG
+#endif
+
+#if defined (FLAG)
+#define VALUE 5
+#else
+#define VALUE 10
+#endif
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifndef.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifndef.d.out
new file mode 100644
index 000000000000..d51d19fc8c60
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifndef.d.out
@@ -0,0 +1,2 @@
+The value is 5
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifnotdef.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifnotdef.d
new file mode 100644
index 000000000000..345a82f7247e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifnotdef.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple if !defined, define, else and endif test
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined (FLAG)
+#define VALUE 5
+#else
+#define VALUE 10
+#endif
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifnotdef.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifnotdef.d.out
new file mode 100644
index 000000000000..d51d19fc8c60
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.ifnotdef.d.out
@@ -0,0 +1,2 @@
+The value is 5
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicaland.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicaland.d
new file mode 100644
index 000000000000..c8ea3481665a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicaland.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple !defined, logical 'and' (&&) test.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined (FLAG) && !defined(STATUS)
+#define VALUE 0
+#else
+#define VALUE 1
+#endif
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicaland.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicaland.d.out
new file mode 100644
index 000000000000..350295cc2516
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicaland.d.out
@@ -0,0 +1,2 @@
+The value is 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalandor.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalandor.d
new file mode 100644
index 000000000000..63637d3cf9fb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalandor.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple !defined logical-or(||) and logical-and(&&) test.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined (FLAG) || !defined(STATUS) && !defined(STATE)
+#define VALUE 0
+#else
+#define VALUE 1
+#endif
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalandor.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalandor.d.out
new file mode 100644
index 000000000000..350295cc2516
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalandor.d.out
@@ -0,0 +1,2 @@
+The value is 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalor.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalor.d
new file mode 100644
index 000000000000..b99ee1dd0359
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalor.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * if !defined (logical-or) usage.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined (FLAG) || !defined(STATUS)
+#define VALUE 0
+#else
+#define VALUE 1
+#endif
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalor.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalor.d.out
new file mode 100644
index 000000000000..350295cc2516
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.logicalor.d.out
@@ -0,0 +1,2 @@
+The value is 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.muland.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.muland.d
new file mode 100644
index 000000000000..9bca2cb07866
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.muland.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * if !defined multiple logical-and(&&) usage.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined (FLAG) && !defined(STATUS) && !defined(STATE)
+#define VALUE 0
+#else
+#define VALUE 1
+#endif
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.muland.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.muland.d.out
new file mode 100644
index 000000000000..350295cc2516
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.muland.d.out
@@ -0,0 +1,2 @@
+The value is 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.mulor.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.mulor.d
new file mode 100644
index 000000000000..1d0c4d974358
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.mulor.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple multiple ifdefined logical-or(||) test.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if !defined (FLAG) || !defined(STATUS) || !defined(STATE)
+#define VALUE 0
+#else
+#define VALUE 1
+#endif
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.mulor.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.mulor.d.out
new file mode 100644
index 000000000000..350295cc2516
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.mulor.d.out
@@ -0,0 +1,2 @@
+The value is 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.precondi.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.precondi.d
new file mode 100644
index 000000000000..1d21d47295ca
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.precondi.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple #define test.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#define value 5
+
+
+#pragma D option quiet
+
+tick-10ms
+/value == 5/
+{
+ printf("The value is %d\n", value);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.precondi.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.precondi.d.out
new file mode 100644
index 000000000000..d51d19fc8c60
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.precondi.d.out
@@ -0,0 +1,2 @@
+The value is 5
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.predicatedeclare.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.predicatedeclare.d
new file mode 100644
index 000000000000..db5e94bb0a79
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.predicatedeclare.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Attempt to declare 'ifdef' statement inbetween probe declaration
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-10ms
+#if !defined (FLAG)
+#define VALUE 5
+#endif
+{
+
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexp.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexp.d
new file mode 100644
index 000000000000..044e5a1ba586
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexp.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple #define and predicates test.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#define MAXVAL 10 * 15
+
+
+#pragma D option quiet
+
+tick-10ms
+/MAXVAL > 5/
+{
+ printf("The value is %d\n", MAXVAL);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexp.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexp.d.out
new file mode 100644
index 000000000000..7ae497954246
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexp.d.out
@@ -0,0 +1,2 @@
+The value is 150
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpelse.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpelse.d
new file mode 100644
index 000000000000..d917d334d3f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpelse.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple ifdefined, define, else, endif test.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#if defined (FLAG)
+#define VALUE 5
+#else
+#define VALUE 10
+#endif
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpelse.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpelse.d.out
new file mode 100644
index 000000000000..2bde5e931ce2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpelse.d.out
@@ -0,0 +1,2 @@
+The value is 10
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpif.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpif.d
new file mode 100644
index 000000000000..b0ae39538821
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpif.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple define, if defined, define and endif tests.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#define FLAG 1
+#if defined (FLAG)
+#define VALUE 5
+#endif
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpif.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpif.d.out
new file mode 100644
index 000000000000..d51d19fc8c60
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpif.d.out
@@ -0,0 +1,2 @@
+The value is 5
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpifelse.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpifelse.d
new file mode 100644
index 000000000000..c6210d09116b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpifelse.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple define, if defined, else, endif test.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+#define FLAG 1
+#if defined (FLAG)
+#define VALUE 5
+#else
+#define VALUE 10
+#endif
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpifelse.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpifelse.d.out
new file mode 100644
index 000000000000..d51d19fc8c60
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.preexpifelse.d.out
@@ -0,0 +1,2 @@
+The value is 5
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.withinprobe.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.withinprobe.d
new file mode 100644
index 000000000000..83a2445b52aa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/preprocessor/tst.withinprobe.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a 'ifdef' section inside a probe clause.
+ *
+ * SECTION: Program Structure/Use of the C Preprocessor
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+
+#if !defined (FLAG)
+#define VALUE 5
+#endif
+
+ printf("The value is %d\n", VALUE);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PRINT_AGG.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PRINT_AGG.bad.d
new file mode 100644
index 000000000000..5479d00126a7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PRINT_AGG.bad.d
@@ -0,0 +1,29 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = count();
+ print(@);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PRINT_VOID.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PRINT_VOID.bad.d
new file mode 100644
index 000000000000..bf2c6da7b18f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PRINT_VOID.bad.d
@@ -0,0 +1,34 @@
+/*
+ * 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 (c) 2012 by Delphix. All rights reserved.
+ */
+
+BEGIN
+{
+ print((void)`proc0);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PROTO_LEN.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PROTO_LEN.bad.d
new file mode 100644
index 000000000000..368caebacb81
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/err.D_PROTO_LEN.bad.d
@@ -0,0 +1,34 @@
+/*
+ * 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 (c) 2012 by Delphix. All rights reserved.
+ */
+
+BEGIN
+{
+ print();
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.array.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.array.d
new file mode 100644
index 000000000000..9650bf7c0f5e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.array.d
@@ -0,0 +1,62 @@
+/*
+ * 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 (c) 2011 by Delphix. All rights reserved.
+ */
+
+#pragma D option quiet
+
+typedef struct bar {
+ int alpha;
+} bar_t;
+
+typedef struct foo {
+ int a[3];
+ char b[30];
+ bar_t c[2];
+ char d[3];
+} foo_t;
+
+BEGIN
+{
+ this->f = (foo_t *)alloca(sizeof (foo_t));
+
+ this->f->a[0] = 1;
+ this->f->a[1] = 2;
+ this->f->a[2] = 3;
+ this->f->b[0] = 'a';
+ this->f->b[1] = 'b';
+ this->f->b[2] = 0;
+ this->f->c[0].alpha = 5;
+ this->f->c[1].alpha = 6;
+ this->f->c[2].alpha = 7;
+ this->f->d[0] = 4;
+ this->f->d[1] = 0;
+ this->f->d[2] = 0;
+
+ print(this->f->a);
+ print(this->f->b);
+ print(this->f->c);
+ print(*this->f);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.array.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.array.d.out
new file mode 100644
index 000000000000..0702d4bb5a80
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.array.d.out
@@ -0,0 +1,23 @@
+int [3] [ 0x1, 0x2, 0x3 ]
+char [30] "ab"
+bar_t [2] [
+ bar_t {
+ int alpha = 0x5
+ },
+ bar_t {
+ int alpha = 0x6
+ }
+]
+foo_t {
+ int [3] a = [ 0x1, 0x2, 0x3 ]
+ char [30] b = [ "ab" ]
+ bar_t [2] c = [
+ bar_t {
+ int alpha = 0x5
+ },
+ bar_t {
+ int alpha = 0x6
+ }
+ ]
+ char [3] d = [ '\004', '\0', '\0' ]
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.bitfield.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.bitfield.d
new file mode 100644
index 000000000000..ff77bb0ec74d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.bitfield.d
@@ -0,0 +1,49 @@
+/*
+ * 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 (c) 2011 by Delphix. All rights reserved.
+ */
+
+#pragma D option quiet
+
+typedef struct forward forward_t;
+
+typedef struct foo {
+ int a:4;
+ int b:7;
+ int c:1;
+ int d:2;
+} foo_t;
+
+BEGIN
+{
+ this->s = (foo_t *)alloca(sizeof (foo_t));
+
+ this->s->a = 1;
+ this->s->b = 5;
+ this->s->c = 0;
+ this->s->d = 2;
+
+ print(*this->s);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.bitfield.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.bitfield.d.out
new file mode 100644
index 000000000000..309444d5c8d4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.bitfield.d.out
@@ -0,0 +1,6 @@
+foo_t {
+ int a :4 = 0x1
+ int b :7 = 0x5
+ int c :1 = 0
+ int d :2 = 0x2
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.dyn.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.dyn.d
new file mode 100644
index 000000000000..f17551facb4e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.dyn.d
@@ -0,0 +1,28 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+BEGIN
+{
+ print(*curpsinfo);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.enum.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.enum.d
new file mode 100644
index 000000000000..f96af108cbea
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.enum.d
@@ -0,0 +1,33 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+enum simpson {
+ homer,
+ marge,
+ bart,
+ lisa,
+ maggie,
+ snowball_ii,
+ santas_little_helper
+};
+
+BEGIN
+{
+ print(bart);
+ print((enum simpson)4);
+ print(snowball_ii);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.enum.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.enum.d.out
new file mode 100644
index 000000000000..979a5b72d716
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.enum.d.out
@@ -0,0 +1,4 @@
+enum simpson bart
+enum simpson maggie
+enum simpson snowball_ii
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.primitive.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.primitive.d
new file mode 100644
index 000000000000..559dab1840c7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.primitive.d
@@ -0,0 +1,45 @@
+/*
+ * 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 (c) 2011 by Delphix. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = (int)'a';
+
+ printf("\n");
+
+ print((char)'a');
+ print((int)-1);
+ print((unsigned int)23);
+ print((short)456);
+ print((unsigned short)789);
+ print((long)1234);
+ print((ulong_t)56789);
+ print((void *)0x1234);
+ print("hello");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.primitive.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.primitive.d.out
new file mode 100644
index 000000000000..f7e4076726ae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.primitive.d.out
@@ -0,0 +1,11 @@
+
+char 'a'
+int 0xffffffff
+unsigned int 0x17
+short 0x1c8
+unsigned short 0x315
+long 0x4d2
+ulong_t 0xddd5
+void * 0x1234
+string "hello"
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.struct.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.struct.d
new file mode 100644
index 000000000000..2fb1c41401e5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.struct.d
@@ -0,0 +1,59 @@
+/*
+ * 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 (c) 2011 by Delphix. All rights reserved.
+ */
+
+#pragma D option quiet
+
+typedef struct forward forward_t;
+
+typedef struct foo {
+ int a;
+ void *b;
+ struct {
+ uint64_t alpha;
+ uint64_t beta;
+ } c;
+ ushort_t d;
+ int e;
+ forward_t *f;
+ void (*g)();
+} foo_t;
+
+BEGIN
+{
+ this->s = (foo_t *)alloca(sizeof (foo_t));
+
+ this->s->a = 1;
+ this->s->b = (void *)2;
+ this->s->c.alpha = 3;
+ this->s->c.beta = 4;
+ this->s->d = 5;
+ this->s->e = 6;
+ this->s->f = (void *)7;
+ this->s->g = (void *)8;
+
+ print(*this->s);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.struct.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.struct.d.out
new file mode 100644
index 000000000000..b7b210837552
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.struct.d.out
@@ -0,0 +1,12 @@
+foo_t {
+ int a = 0x1
+ void *b = 0x2
+ struct c = {
+ uint64_t alpha = 0x3
+ uint64_t beta = 0x4
+ }
+ ushort_t d = 0x5
+ int e = 0x6
+ forward_t *f = 0x7
+ int (*)() g = 0x8
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.xlate.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.xlate.d
new file mode 100644
index 000000000000..6455dd629b8e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.xlate.d
@@ -0,0 +1,42 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#pragma D option quiet
+
+typedef struct pancakes {
+ int i;
+ string s;
+ struct timespec t;
+} pancakes_t;
+
+translator pancakes_t < void *V > {
+ i = 2 * 10;
+ s = strjoin("I like ", "pancakes");
+ t = *(struct timespec *)`dtrace_zero;
+};
+
+BEGIN
+{
+ print(*(xlate < pancakes_t * > ((void *)NULL)));
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.xlate.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.xlate.d.out
new file mode 100644
index 000000000000..ed04f0a1ec72
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/tst.xlate.d.out
@@ -0,0 +1,8 @@
+pancakes_t {
+ int i = 0x14
+ string s = [ "I like pancakes" ]
+ struct timespec t = {
+ time_t tv_sec = 0
+ long tv_nsec = 0
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badagg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badagg.d
new file mode 100644
index 000000000000..817d9ac0871e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badagg.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invokes printa() with a bad aggregation argument.
+ *
+ * SECTION: Output Formatting/printa()
+ *
+ */
+
+BEGIN
+{
+ printa("%d", 123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badfmt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badfmt.d
new file mode 100644
index 000000000000..5a419822e3dd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badfmt.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invokes printa() with a bad format string.
+ *
+ * SECTION: Output Formatting/printa()
+ *
+ */
+
+BEGIN
+{
+ printa(123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badval.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badval.d
new file mode 100644
index 000000000000..e8663ab79f4a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_AGGARG.badval.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invokes printa() with an argument that does not match the aggregation
+ * convertion.
+ *
+ * SECTION: Output Formatting/printa()
+ *
+ */
+
+BEGIN
+{
+ printa("%@d\n", 123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_PROTO.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_PROTO.bad.d
new file mode 100644
index 000000000000..8e202f6d49a0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTA_PROTO.bad.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invokes printa() with a bad aggregation argument.
+ *
+ * SECTION: Output Formatting/printa()
+ *
+ */
+
+BEGIN
+{
+ printa("%d");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.jstack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.jstack.d
new file mode 100644
index 000000000000..09b4b27f0da5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.jstack.d
@@ -0,0 +1,36 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @[jstack()] = count();
+
+ printa("%p\n", @);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.stack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.stack.d
new file mode 100644
index 000000000000..8815ad684ed1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.stack.d
@@ -0,0 +1,36 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @[stack()] = count();
+
+ printa("%p\n", @);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.ustack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.ustack.d
new file mode 100644
index 000000000000..bce1b673865b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/err.D_PRINTF_ARG_TYPE.ustack.d
@@ -0,0 +1,36 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @[ustack()] = count();
+
+ printa("%p\n", @);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.basics.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.basics.d
new file mode 100644
index 000000000000..f5353870808d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.basics.d
@@ -0,0 +1,58 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Test the basic formatting of all the supported kinds of aggregations.
+ *
+ * SECTION: Output Formatting/printa()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a = avg(1);
+ @b = count();
+ @c = lquantize(1, 1, 10);
+ @d = max(1);
+ @e = min(1);
+ @f = sum(1);
+ @g = quantize(1);
+ @h = stddev(1);
+
+ printa("@a = %@u\n", @a);
+ printa("@b = %@u\n", @b);
+ printa("@c = %@d\n", @c);
+ printa("@d = %@u\n", @d);
+ printa("@e = %@u\n", @e);
+ printa("@f = %@u\n", @f);
+ printa("@g = %@d\n", @g);
+ printa("@h = %@d\n", @h);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.basics.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.basics.d.out
new file mode 100644
index 000000000000..ddad2134d1af
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.basics.d.out
@@ -0,0 +1,19 @@
+@a = 1
+@b = 1
+@c =
+ value ------------- Distribution ------------- count
+ < 1 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 2 | 0
+
+@d = 1
+@e = 1
+@f = 1
+@g =
+ value ------------- Distribution ------------- count
+ 0 | 0
+ 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
+ 2 | 0
+
+@h = 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.def.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.def.d
new file mode 100644
index 000000000000..50011e3fa129
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.def.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the printa() default output format.
+ *
+ * SECTION: Output Formatting/printa()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a = count();
+ printa(@a);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.def.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.def.d.out
new file mode 100644
index 000000000000..7cf6701249d7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.def.d.out
@@ -0,0 +1,3 @@
+
+ 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.dynwidth.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.dynwidth.d
new file mode 100644
index 000000000000..f3379c9872f9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.dynwidth.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ /*
+ * Yes, this works. But is it useful? And is it useful to someone
+ * other than jwadams and/or dep?
+ */
+ @[10, 100] = sum(1);
+ @[-10, 200] = sum(2);
+
+ printa("-->%-*d<--\n", @);
+ printa("-->%*d<--\n", @);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.dynwidth.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.dynwidth.d.out
new file mode 100644
index 000000000000..f6c53eb9d42b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.dynwidth.d.out
@@ -0,0 +1,5 @@
+-->100 <--
+-->200 <--
+--> 100<--
+-->200 <--
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.fmt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.fmt.d
new file mode 100644
index 000000000000..8f8cd41b12df
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.fmt.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the printa() format string in its simplest form.
+ *
+ * SECTION: Output Formatting/printa()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a = count();
+ printa("%@u", @a);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.fmt.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.fmt.d.out
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.fmt.d.out
@@ -0,0 +1 @@
+1
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.largeusersym.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.largeusersym.ksh
new file mode 100644
index 000000000000..7d8bd39af74b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.largeusersym.ksh
@@ -0,0 +1,83 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+void
+thequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydog(void)
+{
+ while (1)
+ ;
+}
+
+int
+main(int argc, char *argv[])
+{
+ thequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydogthequickbrownfoxjumpsoverthelazydog();
+}
+EOF
+
+cc -o test test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -c ./test -qs /dev/stdin <<EOF
+ profile:::profile-1001hz
+ /pid == \$target/
+ {
+ @[arg1] = count();
+ }
+
+ tick-1s
+ /n++ > 10/
+ {
+ printa("%A %@d\n", @);
+ exit(0);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.many.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.many.d
new file mode 100644
index 000000000000..5bd3eae7e858
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.many.d
@@ -0,0 +1,76 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=32m
+#pragma D option bufpolicy=fill
+#pragma D option destructive
+#pragma D option quiet
+
+BEGIN
+/0 == 1/
+{
+ @ = count();
+}
+
+BEGIN
+{
+ freopen("/dev/null");
+}
+
+profile-4000hz
+{
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+ printa(@);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.manyval.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.manyval.d
new file mode 100644
index 000000000000..c9fae8436582
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.manyval.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the use of many aggregation results in the same format string.
+ *
+ * SECTION: Output Formatting/printa()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a = count();
+ printa("%@u %@u %@u %@u %@u %@u %@u\n", @a);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.manyval.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.manyval.d.out
new file mode 100644
index 000000000000..f08b797e81f9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.manyval.d.out
@@ -0,0 +1,2 @@
+1 1 1 1 1 1 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.stack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.stack.d
new file mode 100644
index 000000000000..88dbb1a77f8e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.stack.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ @[stack()] = count();
+ @[ustack()] = count();
+ @[jstack()] = count();
+
+ printa("%k\n", @);
+ printa("%-20k\n", @);
+ printa("%60k\n", @);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.tuple.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.tuple.d
new file mode 100644
index 000000000000..0eea887b545a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.tuple.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the use of tuple arguments in the printa() format.
+ *
+ * SECTION: Output Formatting/printa()
+ *
+ * NOTES:
+ * We confirm that we can consume fewer arguments than in the tuple, all
+ * the way up to the exact number.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ @a[1, 2, 3, 4, 5] = count();
+ printf("\n");
+
+ printa("%@u: -\n", @a);
+ printa("%@u: %d\n", @a);
+ printa("%@u: %d %d\n", @a);
+ printa("%@u: %d %d %d\n", @a);
+ printa("%@u: %d %d %d %d\n", @a);
+ printa("%@u: %d %d %d %d %d\n", @a);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.tuple.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.tuple.d.out
new file mode 100644
index 000000000000..928119c9f05d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.tuple.d.out
@@ -0,0 +1,8 @@
+
+1: -
+1: 1
+1: 1 2
+1: 1 2 3
+1: 1 2 3 4
+1: 1 2 3 4 5
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.walltimestamp.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.walltimestamp.ksh
new file mode 100644
index 000000000000..69bf46b5383c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.walltimestamp.ksh
@@ -0,0 +1,62 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+# The output files assumes the timezone is US/Pacific
+export TZ=America/Los_Angeles
+
+$dtrace -s /dev/stdin <<EOF
+#pragma D option quiet
+#pragma D option destructive
+
+BEGIN
+{
+ @foo = min(1075064400 * (hrtime_t)1000000000);
+ @bar = max(walltimestamp);
+ printa("%@T\n", @foo);
+ printa("%@Y\n", @foo);
+
+ freopen("/dev/null");
+ printa("%@T\n", @bar);
+ printa("%@Y\n", @bar);
+
+ exit(0);
+}
+EOF
+
+if [ $? -ne 0 ]; then
+ print -u2 "dtrace failed"
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.walltimestamp.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.walltimestamp.ksh.out
new file mode 100644
index 000000000000..724e45e62291
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printa/tst.walltimestamp.ksh.out
@@ -0,0 +1,3 @@
+Sun, 25 Jan 2004 13:00:00 PST
+2004 Jan 25 13:00:00
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_AGG_CONV.aggfmt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_AGG_CONV.aggfmt.d
new file mode 100644
index 000000000000..9cac625d3ec1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_AGG_CONV.aggfmt.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with a bad aggregation format.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("hello %@d", 123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_EXTRA.toomany.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_EXTRA.toomany.d
new file mode 100644
index 000000000000..de87e8d71839
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_EXTRA.toomany.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with too many arguments.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("x = %d y = %d\n", 123, 456, 789);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_EXTRA.widths.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_EXTRA.widths.d
new file mode 100644
index 000000000000..938128007b6e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_EXTRA.widths.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Negative test to test variety of fixed width formats.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("\n");
+ x = 0;
+
+ printf("%?d\n", x++, 1);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_FMT.badfmt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_FMT.badfmt.d
new file mode 100644
index 000000000000..bf4dc72c1ab3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_FMT.badfmt.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with a bad format string arg.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf(123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_PROTO.novalue.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_PROTO.novalue.d
new file mode 100644
index 000000000000..68f8cf029fe3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_PROTO.novalue.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with a missing value argument.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("%s");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_TYPE.aggarg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_TYPE.aggarg.d
new file mode 100644
index 000000000000..99bb0395028c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_TYPE.aggarg.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Test printf() with a bad aggregation arg.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ @a = count();
+ printf("hello %d %d", 123, @a);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_TYPE.recursive.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_TYPE.recursive.d
new file mode 100644
index 000000000000..3b94ba731721
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_ARG_TYPE.recursive.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invalid recursive printf test.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+ printf("%s\n", printf("test"));
+
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_PROTO.noprec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_PROTO.noprec.d
new file mode 100644
index 000000000000..ba8a1a46d19a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_PROTO.noprec.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with a missing dynamic precision argument.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("%s %.*d\n", "foo");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_PROTO.nowidth.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_PROTO.nowidth.d
new file mode 100644
index 000000000000..4d72c819d435
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_PROTO.nowidth.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with a missing dynamic width argument.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("%s %*d\n", "foo");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_TYPE.badprec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_TYPE.badprec.d
new file mode 100644
index 000000000000..64cf912534c1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_TYPE.badprec.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test a dynamic precision argument of non-integer type.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("%.*d\n", "foo", 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_TYPE.badwidth.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_TYPE.badwidth.d
new file mode 100644
index 000000000000..badc95eeb952
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PRINTF_DYN_TYPE.badwidth.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Tet dynamic width argument of non-integer type.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("%*d\n", "foo", 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PROTO_LEN.toofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PROTO_LEN.toofew.d
new file mode 100644
index 000000000000..32c877ba8ed9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_PROTO_LEN.toofew.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with too few arguments.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv1.d
new file mode 100644
index 000000000000..7add33192a7d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv1.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the unsupported %n$ conversion syntax.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("%3$d", 123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv2.d
new file mode 100644
index 000000000000..5cc32e27e636
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv2.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test an incomplete conversion.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("%3", 123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv3.d
new file mode 100644
index 000000000000..0dedea3d4096
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/err.D_SYNTAX.badconv3.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test an undefined conversion.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ printf("%Z", 123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d
new file mode 100644
index 000000000000..10dc61dab83f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the basics of all the format conversions in the printf dictionary.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ * NOTES:
+ * floats and wchar_t strings missing
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = (int)'a';
+
+ printf("\n");
+
+ printf("%%a = %a\n", &`malloc);
+ printf("%%c = %c\n", i);
+ printf("%%d = %d\n", i);
+ printf("%%hd = %hd\n", (short)i);
+ printf("%%hi = %hi\n", (short)i);
+ printf("%%ho = %ho\n", (ushort_t)i);
+ printf("%%hu = %hu\n", (ushort_t)i);
+ printf("%%hx = %hx\n", (ushort_t)i);
+ printf("%%hX = %hX\n", (ushort_t)i);
+ printf("%%i = %i\n", i);
+ printf("%%lc = %lc\n", i);
+ printf("%%ld = %ld\n", (long)i);
+ printf("%%li = %li\n", (long)i);
+ printf("%%lo = %lo\n", (ulong_t)i);
+ printf("%%lu = %lu\n", (ulong_t)i);
+ printf("%%lx = %lx\n", (ulong_t)i);
+ printf("%%lX = %lX\n", (ulong_t)i);
+ printf("%%o = %o\n", (uint_t)i);
+ printf("%%p = %p\n", (void *)i);
+ printf("%%s = %s\n", "hello");
+ printf("%%u = %u\n", (uint_t)i);
+ printf("%%wc = %wc\n", i);
+ printf("%%x = %x\n", (uint_t)i);
+ printf("%%X = %X\n", (uint_t)i);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out
new file mode 100644
index 000000000000..1d2740578796
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out
@@ -0,0 +1,26 @@
+
+%a = kernel`malloc
+%c = a
+%d = 97
+%hd = 97
+%hi = 97
+%ho = 141
+%hu = 97
+%hx = 61
+%hX = 61
+%i = 97
+%lc = a
+%ld = 97
+%li = 97
+%lo = 141
+%lu = 97
+%lx = 61
+%lX = 61
+%o = 141
+%p = 61
+%s = hello
+%u = 97
+%wc = a
+%x = 61
+%X = 61
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.flags.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.flags.d
new file mode 100644
index 000000000000..0b65315138e6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.flags.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test all of the various formatting flags (except %' because that
+ * requires locale support).
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("\n");
+ printf("# %#8x\n", 0x123);
+ printf("0 %08x\n", 0x123);
+ printf("- %-8x\n", 0x123);
+ printf("+ %+8d\n", 123);
+ printf(" % 8d\n", 123);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.flags.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.flags.d.out
new file mode 100644
index 000000000000..4e5344ee6575
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.flags.d.out
@@ -0,0 +1,7 @@
+
+# 0x123
+0 00000123
+- 123
++ +123
+ 123
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.hello.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.hello.d
new file mode 100644
index 000000000000..d58f6cd7277a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.hello.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple printf() test.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("hello");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.hello.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.hello.d.out
new file mode 100644
index 000000000000..ce013625030b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.hello.d.out
@@ -0,0 +1 @@
+hello
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.ints.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.ints.d
new file mode 100644
index 000000000000..d15236bab0b3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.ints.d
@@ -0,0 +1,87 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with simple integer arguments, using a variety of
+ * sizes and thereby exercise the automatic size extension feature.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("\n%d\n", (char)0x1234567890abcdef);
+ printf("%d\n", (short)0x1234567890abcdef);
+ printf("%d\n", (int)0x1234567890abcdef);
+ printf("%d\n", (long long)0x1234567890abcdef);
+
+ printf("\n%d\n", (unsigned char)0x1234567890abcdef);
+ printf("%d\n", (unsigned short)0x1234567890abcdef);
+ printf("%d\n", (unsigned int)0x1234567890abcdef);
+ printf("%d\n", (unsigned long long)0x1234567890abcdef);
+
+ printf("\n%u\n", (char)0x1234567890abcdef);
+ printf("%u\n", (short)0x1234567890abcdef);
+ printf("%u\n", (int)0x1234567890abcdef);
+ printf("%u\n", (long long)0x1234567890abcdef);
+
+ printf("\n%u\n", (unsigned char)0x1234567890abcdef);
+ printf("%u\n", (unsigned short)0x1234567890abcdef);
+ printf("%u\n", (unsigned int)0x1234567890abcdef);
+ printf("%u\n", (unsigned long long)0x1234567890abcdef);
+
+ printf("\n%x\n", (unsigned char)0x1234567890abcdef);
+ printf("%x\n", (unsigned short)0x1234567890abcdef);
+ printf("%x\n", (unsigned int)0x1234567890abcdef);
+ printf("%x\n", (unsigned long long)0x1234567890abcdef);
+
+ printf("\n%x\n", (char)0x1234567890abcdef);
+ printf("%x\n", (short)0x1234567890abcdef);
+ printf("%x\n", (int)0x1234567890abcdef);
+ printf("%x\n", (long long)0x1234567890abcdef);
+
+ printf("\n%o\n", (unsigned char)0x1234567890abcdef);
+ printf("%o\n", (unsigned short)0x1234567890abcdef);
+ printf("%o\n", (unsigned int)0x1234567890abcdef);
+ printf("%o\n", (unsigned long long)0x1234567890abcdef);
+
+ printf("\n%o\n", (char)0x1234567890abcdef);
+ printf("%o\n", (short)0x1234567890abcdef);
+ printf("%o\n", (int)0x1234567890abcdef);
+ printf("%o\n", (long long)0x1234567890abcdef);
+
+ printf("\n%p\n", (void *)0x12345678);
+ printf("%p\n", (int *)0x90abcdef);
+ printf("%p\n", (uintptr_t)0x67890abc);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.ints.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.ints.d.out
new file mode 100644
index 000000000000..bc7eaed0ec9a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.ints.d.out
@@ -0,0 +1,45 @@
+
+-17
+-12817
+-1867788817
+1311768467294899695
+
+239
+52719
+2427178479
+1311768467294899695
+
+239
+52719
+2427178479
+1311768467294899695
+
+239
+52719
+2427178479
+1311768467294899695
+
+ef
+cdef
+90abcdef
+1234567890abcdef
+
+ef
+cdef
+90abcdef
+1234567890abcdef
+
+357
+146757
+22052746757
+110642547422052746757
+
+357
+146757
+22052746757
+110642547422052746757
+
+12345678
+90abcdef
+67890abc
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.precs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.precs.d
new file mode 100644
index 000000000000..2bfff9ff7040
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.precs.d
@@ -0,0 +1,58 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test a variety of fixed and dynamic format precisions.
+ *
+ * SECTION: Output Formatting/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("\n");
+ x = 0;
+
+ printf("%.0s\n", "hello");
+ printf("%.1s\n", "hello");
+ printf("%.2s\n", "hello");
+ printf("%.3s\n", "hello");
+ printf("%.4s\n", "hello");
+ printf("%.5s\n", "hello");
+
+ printf("%.*s\n", x++, "hello");
+ printf("%.*s\n", x++, "hello");
+ printf("%.*s\n", x++, "hello");
+ printf("%.*s\n", x++, "hello");
+ printf("%.*s\n", x++, "hello");
+ printf("%.*s\n", x++, "hello");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.precs.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.precs.d.out
new file mode 100644
index 000000000000..11a969de02ae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.precs.d.out
@@ -0,0 +1,14 @@
+
+hello
+h
+he
+hel
+hell
+hello
+hello
+h
+he
+hel
+hell
+hello
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.print-f.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.print-f.d
new file mode 100644
index 000000000000..3fe0bac485de
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.print-f.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test %f format printing.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+float f;
+double d;
+
+BEGIN
+{
+ printf("\n");
+
+ printf("%%f = %f\n", f);
+ printf("%%f = %f\n", d);
+
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.print-f.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.print-f.d.out
new file mode 100644
index 000000000000..4d4b8641afc3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.print-f.d.out
@@ -0,0 +1,4 @@
+
+%f = 0.000000
+%f = 0.000000
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printT.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printT.ksh
new file mode 100644
index 000000000000..6d3695711c95
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printT.ksh
@@ -0,0 +1,56 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+# The output files assumes the timezone is US/Pacific
+export TZ=America/Los_Angeles
+
+$dtrace -s /dev/stdin <<EOF
+#pragma D option quiet
+
+inline uint64_t NANOSEC = 1000000000;
+
+BEGIN
+{
+ printf("%T\n%T\n%T", (uint64_t)0, (uint64_t)1062609821 * NANOSEC,
+ (uint64_t)0x7fffffff * NANOSEC);
+ exit(0);
+}
+EOF
+
+if [ $? -ne 0 ]; then
+ print -u2 "dtrace failed"
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printT.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printT.ksh.out
new file mode 100644
index 000000000000..51c84373aacd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printT.ksh.out
@@ -0,0 +1,3 @@
+Wed, 31 Dec 1970 16:00:00 PST
+Wed, 03 Sep 2003 10:23:41 PDT
+Mon, 18 Jan 2038 19:14:07 PST
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printY.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printY.ksh
new file mode 100644
index 000000000000..b8ea2fff2aff
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printY.ksh
@@ -0,0 +1,56 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+# The output files assumes the timezone is US/Pacific
+export TZ=America/Los_Angeles
+
+$dtrace -s /dev/stdin <<EOF
+#pragma D option quiet
+
+inline uint64_t NANOSEC = 1000000000;
+
+BEGIN
+{
+ printf("%Y\n%Y\n%Y", (uint64_t)0, (uint64_t)1062609821 * NANOSEC,
+ (uint64_t)0x7fffffff * NANOSEC);
+ exit(0);
+}
+EOF
+
+if [ $? -ne 0 ]; then
+ print -u2 "dtrace failed"
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printY.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printY.ksh.out
new file mode 100644
index 000000000000..ae8d82f936a7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printY.ksh.out
@@ -0,0 +1,3 @@
+1969 Dec 31 16:00:00
+2003 Sep 3 10:23:41
+2038 Jan 18 19:14:07
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printcont.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printcont.d
new file mode 100644
index 000000000000..ca7e1a931303
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printcont.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test 'uint' continously; like kinda stress.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+uint64_t ts;
+
+BEGIN
+{
+ ts = 53114233149441;
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ printf("%u\n", ts);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printcont.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printcont.d.out
new file mode 100644
index 000000000000..ce33b729a33c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printcont.d.out
@@ -0,0 +1,16 @@
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+53114233149441
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printeE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printeE.d
new file mode 100644
index 000000000000..7aaee2a4bceb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printeE.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test %e, %E format printing.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+float f;
+double d;
+
+BEGIN
+{
+ printf("\n");
+
+ printf("%%e = %e\n", f);
+ printf("%%E = %E\n", f);
+
+ printf("%%e = %e\n", d);
+ printf("%%E = %E\n", d);
+
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printeE.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printeE.d.out
new file mode 100644
index 000000000000..3fa96bc2df79
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printeE.d.out
@@ -0,0 +1,6 @@
+
+%e = 0.000000e+00
+%E = 0.000000E+00
+%e = 0.000000e+00
+%E = 0.000000E+00
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printgG.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printgG.d
new file mode 100644
index 000000000000..9e7e019b9984
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printgG.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test %g, %G format printing.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+float f;
+double d;
+
+BEGIN
+{
+ printf("\n");
+
+ printf("%%g = %g\n", f);
+ printf("%%g = %g\n", d);
+
+ printf("%%G = %G\n", f);
+ printf("%%G = %G\n", d);
+
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printgG.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printgG.d.out
new file mode 100644
index 000000000000..e4175e642d7b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.printgG.d.out
@@ -0,0 +1,6 @@
+
+%g = 0
+%g = 0
+%G = 0
+%G = 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.rawfmt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.rawfmt.d
new file mode 100644
index 000000000000..deb4f8172625
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.rawfmt.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with a fixed string and no actual tracing arguments.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("hello world from BEGIN");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.rawfmt.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.rawfmt.d.out
new file mode 100644
index 000000000000..cb7c7e94870f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.rawfmt.d.out
@@ -0,0 +1 @@
+hello world from BEGIN
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.signs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.signs.d
new file mode 100644
index 000000000000..64e565e267b0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.signs.d
@@ -0,0 +1,38 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * Check %d v. %i v. %u.
+ */
+
+#pragma D option quiet
+
+uint16_t x;
+int16_t y;
+
+BEGIN
+{
+ x = 0xffffffff;
+ y = 0xffffffff;
+
+ printf("%d %i %u\n", x, x, x);
+ printf("%d %i %u\n", y, y, y);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.signs.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.signs.d.out
new file mode 100644
index 000000000000..169ac59b9554
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.signs.d.out
@@ -0,0 +1,3 @@
+65535 -1 65535
+-1 -1 65535
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d
new file mode 100644
index 000000000000..67d774910313
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Test printf() with a simple string argument.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("sysname = %s", `ostype);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out
new file mode 100644
index 000000000000..82d597b1429a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out
@@ -0,0 +1 @@
+sysname = FreeBSD
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d
new file mode 100644
index 000000000000..c2cf77d63925
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with a simple string argument.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("symbol = %a", &`malloc);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out
new file mode 100644
index 000000000000..7f645e170116
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out
@@ -0,0 +1 @@
+symbol = kernel`malloc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.uints.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.uints.d
new file mode 100644
index 000000000000..caa326e875fc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.uints.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test printf() with simple unsigned integer arguments.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("\n");
+ printf("%u\n", (uchar_t)123);
+ printf("%u\n", (ushort_t)123);
+ printf("%u\n", (ulong_t)123);
+ printf("%u\n", (u_longlong_t)123);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.uints.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.uints.d.out
new file mode 100644
index 000000000000..d800e9167535
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.uints.d.out
@@ -0,0 +1,6 @@
+
+123
+123
+123
+123
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths.d
new file mode 100644
index 000000000000..21595c02974f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test a variety of fixed and dynamic format widths.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("\n");
+ x = 0;
+
+ printf("%0d\n", 1);
+ printf("%1d\n", 1);
+ printf("%2d\n", 1);
+ printf("%3d\n", 1);
+ printf("%4d\n", 1);
+ printf("%5d\n", 1);
+
+ printf("%*d\n", x++, 1);
+ printf("%*d\n", x++, 1);
+ printf("%*d\n", x++, 1);
+ printf("%*d\n", x++, 1);
+ printf("%*d\n", x++, 1);
+ printf("%*d\n", x++, 1);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths.d.out
new file mode 100644
index 000000000000..39fc7a8a98f3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths.d.out
@@ -0,0 +1,14 @@
+
+1
+1
+ 1
+ 1
+ 1
+ 1
+1
+1
+ 1
+ 1
+ 1
+ 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths1.d
new file mode 100644
index 000000000000..b5410ab8ac93
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.widths1.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Try to print charecter wide width using '?'
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("\n");
+ x = 0;
+
+ printf("%?d\n", x++);
+ printf("%?d\n", x++);
+ printf("%?d\n", x++);
+ printf("%?d\n", x++);
+ printf("%?d\n", x++);
+ printf("%?d\n", x++);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.wp.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.wp.d
new file mode 100644
index 000000000000..b6745e140557
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.wp.d
@@ -0,0 +1,66 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test a variety of fixed and dynamic format widths combined with precisions.
+ *
+ * SECTION: Output Formatting/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("\n");
+ x = 0;
+
+ printf("%0.0s\n", "hello");
+ printf("%1.1s\n", "hello");
+ printf("%2.2s\n", "hello");
+ printf("%3.3s\n", "hello");
+ printf("%4.4s\n", "hello");
+ printf("%5.5s\n", "hello");
+ printf("%6.6s\n", "hello");
+ printf("%7.7s\n", "hello");
+ printf("%8.8s\n", "hello");
+ printf("%9.9s\n", "hello");
+
+ printf("%*.*s\n", x, x++, "hello");
+ printf("%*.*s\n", x, x++, "hello");
+ printf("%*.*s\n", x, x++, "hello");
+ printf("%*.*s\n", x, x++, "hello");
+ printf("%*.*s\n", x, x++, "hello");
+ printf("%*.*s\n", x, x++, "hello");
+ printf("%*.*s\n", x, x++, "hello");
+ printf("%*.*s\n", x, x++, "hello");
+ printf("%*.*s\n", x, x++, "hello");
+ printf("%*.*s\n", x, x++, "hello");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.wp.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.wp.d.out
new file mode 100644
index 000000000000..2f1fd9de1a85
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.wp.d.out
@@ -0,0 +1,22 @@
+
+hello
+h
+he
+hel
+hell
+hello
+ hello
+ hello
+ hello
+ hello
+hello
+h
+he
+hel
+hell
+hello
+ hello
+ hello
+ hello
+ hello
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.fds.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.fds.ksh
new file mode 100644
index 000000000000..a5aa27137efa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.fds.ksh
@@ -0,0 +1,91 @@
+#
+# 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 (c) 2012, Joyent, Inc. All rights reserved.
+#
+
+tmpin=/tmp/tst.fds.$$.d
+tmpout1=/tmp/tst.fds.$$.out1
+tmpout2=/tmp/tst.fds.$$.out2
+
+cat > $tmpin <<EOF
+#define DUMPFIELD(fd, fmt, field) \
+ errmsg = "could not dump field"; \
+ printf("%d: field =fmt\n", fd, fds[fd].field);
+
+/*
+ * Note that we are explicitly not looking at fi_mount -- it (by design) does
+ * not work if not running with kernel permissions.
+ */
+#define DUMP(fd) \
+ DUMPFIELD(fd, %s, fi_name); \
+ DUMPFIELD(fd, %s, fi_dirname); \
+ DUMPFIELD(fd, %s, fi_pathname); \
+ DUMPFIELD(fd, %d, fi_offset); \
+ DUMPFIELD(fd, %s, fi_fs); \
+ DUMPFIELD(fd, %o, fi_oflags);
+
+BEGIN
+{
+ DUMP(0);
+ DUMP(1);
+ DUMP(2);
+ DUMP(3);
+ DUMP(4);
+ exit(0);
+}
+
+ERROR
+{
+ printf("error: %s\n", errmsg);
+ exit(1);
+}
+EOF
+
+#
+# First, with all privs
+#
+/usr/sbin/dtrace -q -Cs /dev/stdin < $tmpin > $tmpout2
+mv $tmpout2 $tmpout1
+
+#
+# And now with only dtrace_proc and dtrace_user -- the output should be
+# identical.
+#
+ppriv -s A=basic,dtrace_proc,dtrace_user $$
+
+/usr/sbin/dtrace -q -Cs /dev/stdin < $tmpin > $tmpout2
+
+echo ">>> $tmpout1"
+cat $tmpout1
+
+echo ">>> $tmpout2"
+cat $tmpout2
+
+rval=0
+
+if ! cmp $tmpout1 $tmpout2 ; then
+ rval=1
+fi
+
+rm $tmpout1 $tmpout2 $tmpin
+exit $rval
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.func_access.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.func_access.ksh
new file mode 100644
index 000000000000..da9bb4c6c6b3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.func_access.ksh
@@ -0,0 +1,87 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+# Copyright (c) 2012, Joyent, Inc. All rights reserved.
+#
+
+ppriv -s A=basic,dtrace_proc,dtrace_user $$
+
+/usr/sbin/dtrace -q -s /dev/stdin <<"EOF"
+
+BEGIN {
+ errorcount = 0;
+ expected_errorcount = 27;
+}
+
+BEGIN { trace(mutex_owned(&`pidlock)); }
+BEGIN { trace(mutex_owner(&`pidlock)); }
+BEGIN { trace(mutex_type_adaptive(&`pidlock)); }
+BEGIN { trace(mutex_type_spin(&`pidlock)); }
+
+BEGIN { trace(rw_read_held(&`ksyms_lock)); }
+BEGIN { trace(rw_write_held(&`ksyms_lock)); }
+BEGIN { trace(rw_iswriter(&`ksyms_lock)); }
+
+BEGIN { x = alloca(10); bcopy(`initname, x, 10); trace(stringof(x)); }
+/* We have no reliable way to test msgsize */
+
+BEGIN { trace(strlen(`initname)); }
+BEGIN { trace(strchr(`initname, 0x69)); }
+BEGIN { trace(strrchr(`initname, 0x69)); }
+BEGIN { trace(strstr("/sbin/init/foo", `initname)); }
+BEGIN { trace(strstr(`initname, "in")); }
+BEGIN { trace(strtok(`initname, "/")); }
+BEGIN { trace(strtok(NULL, "/")); }
+BEGIN { trace(strtok("foo/bar", `initname)); }
+BEGIN { trace(strtok(NULL, `initname)); }
+BEGIN { trace(strtoll(`initname)); }
+BEGIN { trace(strtoll(`initname, 10)); }
+BEGIN { trace(substr(`initname, 2, 3)); }
+
+BEGIN { trace(ddi_pathname(`top_devinfo, 1)); }
+BEGIN { trace(strjoin(`initname, "foo")); }
+BEGIN { trace(strjoin("foo", `initname)); }
+BEGIN { trace(dirname(`initname)); }
+BEGIN { trace(cleanpath(`initname)); }
+
+BEGIN { j = "{\"/sbin/init\":\"uh oh\"}"; trace(json(j, `initname)); }
+BEGIN { trace(json(`initname, "x")); }
+
+ERROR {
+ errorcount++;
+}
+
+BEGIN /errorcount == expected_errorcount/ {
+ trace("test passed");
+ exit(0);
+}
+
+BEGIN /errorcount != expected_errorcount/ {
+ printf("fail: expected %d. saw %d.", expected_errorcount, errorcount);
+ exit(1);
+}
+EOF
+
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.getf.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.getf.ksh
new file mode 100644
index 000000000000..7dbb83fba94a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.getf.ksh
@@ -0,0 +1,98 @@
+#
+# 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 (c) 2012, Joyent, Inc. All rights reserved.
+#
+
+ppriv -s A=basic,dtrace_proc,dtrace_user $$
+
+/usr/sbin/dtrace -q -Cs /dev/stdin <<EOF
+
+#define CANREAD(field) \
+ BEGIN { this->fp = getf(0); errmsg = "can't read field"; \
+ printf("field: "); trace(this->fp->field); printf("\n"); }
+
+#define CANTREAD(field) \
+ BEGIN { errmsg = ""; this->fp = getf(0); trace(this->fp->field); \
+ printf("\nable to successfully read field!"); exit(1); }
+
+CANREAD(f_flag)
+CANREAD(f_flag2)
+CANREAD(f_vnode)
+CANREAD(f_offset)
+CANREAD(f_cred)
+CANREAD(f_audit_data)
+CANREAD(f_count)
+
+/*
+ * We can potentially read parts of our cred, but we can't dereference
+ * through cr_zone.
+ */
+CANTREAD(f_cred->cr_zone->zone_id)
+
+CANREAD(f_vnode->v_path)
+CANREAD(f_vnode->v_op)
+CANREAD(f_vnode->v_op->vnop_name)
+
+CANTREAD(f_vnode->v_flag)
+CANTREAD(f_vnode->v_count)
+CANTREAD(f_vnode->v_pages)
+CANTREAD(f_vnode->v_type)
+CANTREAD(f_vnode->v_vfsmountedhere)
+CANTREAD(f_vnode->v_op->vop_open)
+
+BEGIN
+{
+ errmsg = "";
+ this->fp = getf(0);
+ this->fp2 = getf(1);
+
+ trace(this->fp->f_vnode);
+ printf("\nable to successfully read this->fp!");
+ exit(1);
+}
+
+BEGIN
+{
+ errmsg = "";
+ this->fp = getf(0);
+}
+
+BEGIN
+{
+ trace(this->fp->f_vnode);
+ printf("\nable to successfully read this->fp from prior clause!");
+}
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+/errmsg != ""/
+{
+ printf("fatal error: %s", errmsg);
+ exit(1);
+}
+
+EOF
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.kpriv.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.kpriv.ksh
new file mode 100644
index 000000000000..da776d042eb3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.kpriv.ksh
@@ -0,0 +1,112 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
+#
+
+err=/tmp/err.$$
+
+ppriv -s A=basic,dtrace_user $$
+
+#
+# When we lack dtrace_kernel, we expect to not be able to get at kernel memory
+# via any subroutine or other vector.
+#
+# trace(func((void *)&\`utsname)); }
+/usr/sbin/dtrace -wq -Cs /dev/stdin 2> $err <<EOF
+
+#define FAIL \
+ printf("able to read kernel memory via %s!\n", badsubr); \
+ exit(2);
+
+#define CANTREAD1(func) \
+ BEGIN { badsubr = "func()"; func((void *)&\`utsname); FAIL }
+
+#define CANTREAD2(func, arg1) \
+ BEGIN { badsubr = "func()"; func((void *)&\`utsname, arg1); FAIL }
+
+#define CANTREAD2ARG1(func, arg0) \
+ BEGIN { badsubr = "func() (arg1)"; func(arg0, (void *)&\`utsname); FAIL }
+
+#define CANTREAD3(func, arg1, arg2) \
+ BEGIN { badsubr = "func()"; func((void *)&\`utsname, arg1, arg2); FAIL }
+
+CANTREAD1(mutex_owned)
+CANTREAD1(mutex_owner)
+CANTREAD1(mutex_type_adaptive)
+CANTREAD1(mutex_type_spin)
+CANTREAD1(rw_read_held)
+CANTREAD1(rw_write_held)
+CANTREAD1(rw_iswriter)
+CANTREAD3(bcopy, alloca(1), 1)
+CANTREAD1(msgsize)
+CANTREAD1(msgdsize)
+CANTREAD1(strlen)
+CANTREAD2(strchr, '!')
+CANTREAD2(strrchr, '!')
+CANTREAD2(strstr, "doogle")
+CANTREAD2ARG1(strstr, "doogle")
+CANTREAD2(index, "bagnoogle")
+CANTREAD2ARG1(index, "bagnoogle")
+CANTREAD2(rindex, "bagnoogle")
+CANTREAD2ARG1(rindex, "bagnoogle")
+CANTREAD2(strtok, "doogle")
+CANTREAD2ARG1(strtok, "doogle")
+CANTREAD2(json, "doogle")
+CANTREAD2ARG1(json, "doogle")
+CANTREAD1(toupper)
+CANTREAD1(tolower)
+CANTREAD2(ddi_pathname, 1)
+CANTREAD2(strjoin, "doogle")
+CANTREAD2ARG1(strjoin, "doogle")
+CANTREAD1(strtoll)
+CANTREAD1(dirname)
+CANTREAD1(basename)
+CANTREAD1(cleanpath)
+
+#if defined(__amd64)
+CANTREAD3(copyout, uregs[R_R9], 1)
+CANTREAD3(copyoutstr, uregs[R_R9], 1)
+#else
+#if defined(__i386)
+CANTREAD3(copyout, uregs[R_ESP], 1)
+CANTREAD3(copyoutstr, uregs[R_ESP], 1)
+#endif
+#endif
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+/arg4 != DTRACEFLT_KPRIV/
+{
+ printf("bad error code via %s (expected %d, found %d)\n",
+ badsubr, DTRACEFLT_KPRIV, arg4);
+ exit(3);
+}
+
+ERROR
+/arg4 == DTRACEFLT_KPRIV/
+{
+ printf("illegal kernel access properly prevented from %s\n", badsubr);
+}
+EOF
+
+status=$?
+
+if [[ $status -eq 1 ]]; then
+ cat $err
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.op_access.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.op_access.ksh
new file mode 100644
index 000000000000..08964c498e5e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.op_access.ksh
@@ -0,0 +1,70 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+ppriv -s A=basic,dtrace_proc,dtrace_user $$
+
+/usr/sbin/dtrace -q -s /dev/stdin <<"EOF"
+BEGIN {
+ errorcount = 0;
+ expected_errorcount = 7;
+}
+
+/* BYREF */
+BEGIN { trace(`utsname); }
+BEGIN { trace(`kmem_flags); }
+
+/* DIF_OP_SCMP */
+BEGIN /`initname == "/sbin/init"/ { trace("bad"); }
+
+/* DIF_OP_COPYS */
+BEGIN { p = `p0; trace(p); }
+
+/* DIF_OP_STTS */
+BEGIN { self->p = `p0; trace(self->p); }
+
+/* DIF_OP_STGAA */
+BEGIN { a[stringof(`initname)] = 42; trace(a["/sbin/init"]); }
+
+/* DIF_OP_STTAA */
+BEGIN { self->a[stringof(`initname)] = 42; trace(self->a["/sbin/init"]); }
+
+ERROR {
+ errorcount++;
+}
+
+BEGIN /errorcount == expected_errorcount/ {
+ trace("pass");
+ exit(0);
+}
+
+BEGIN /errorcount != expected_errorcount/ {
+ printf("fail: expected %d. saw %d.", expected_errorcount, errorcount);
+ exit(1);
+}
+EOF
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.procpriv.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.procpriv.ksh
new file mode 100644
index 000000000000..7022566391f4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.procpriv.ksh
@@ -0,0 +1,138 @@
+#
+# 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 (c) 2012, Joyent, Inc. All rights reserved.
+#
+
+ppriv -s A=basic,dtrace_proc,dtrace_user $$
+
+#
+# When we have dtrace_proc (but lack dtrace_kernel), we expect to be able to
+# read certain curpsinfo/curlwpsinfo/curcpu fields even though they require
+# reading in-kernel state. However, there are other fields in these translated
+# structures that we know we shouldn't be able to read, as they require reading
+# in-kernel state that we cannot read with only dtrace_proc. Finally, there
+# are a few fields that we may or may not be able to read depending on the
+# specifics of context. This test therefore asserts that we can read what we
+# think we should be able to, that we can't read what we think we shouldn't be
+# able to, and (for purposes of completeness) that we are indifferent about
+# what we cannot assert one way or the other.
+#
+/usr/sbin/dtrace -q -Cs /dev/stdin <<EOF
+
+#define CANREAD(what, field) \
+ BEGIN { errmsg = "can't read field from what"; printf("field: "); \
+ trace(what->field); printf("\n"); }
+
+#define CANTREAD(what, field) \
+ BEGIN { errmsg = ""; trace(what->field); \
+ printf("\nable to successfully read field from what!"); exit(1); }
+
+#define MIGHTREAD(what, field) \
+ BEGIN { errmsg = ""; printf("field: "); trace(what->field); printf("\n"); }
+
+#define CANREADVAR(vname) \
+ BEGIN { errmsg = "can't read vname"; printf("vname: "); \
+ trace(vname); printf("\n"); }
+
+#define CANTREADVAR(vname) \
+ BEGIN { errmsg = ""; trace(vname); \
+ printf("\nable to successfully read vname!"); exit(1); }
+
+#define MIGHTREADVAR(vname) \
+ BEGIN { errmsg = ""; printf("vname: "); trace(vname); printf("\n"); }
+
+CANREAD(curpsinfo, pr_pid)
+CANREAD(curpsinfo, pr_nlwp)
+CANREAD(curpsinfo, pr_ppid)
+CANREAD(curpsinfo, pr_uid)
+CANREAD(curpsinfo, pr_euid)
+CANREAD(curpsinfo, pr_gid)
+CANREAD(curpsinfo, pr_egid)
+CANREAD(curpsinfo, pr_addr)
+CANREAD(curpsinfo, pr_start)
+CANREAD(curpsinfo, pr_fname)
+CANREAD(curpsinfo, pr_psargs)
+CANREAD(curpsinfo, pr_argc)
+CANREAD(curpsinfo, pr_argv)
+CANREAD(curpsinfo, pr_envp)
+CANREAD(curpsinfo, pr_dmodel)
+
+/*
+ * If our p_pgidp points to the same pid structure as our p_pidp, we will
+ * be able to read pr_pgid -- but we won't if not.
+ */
+MIGHTREAD(curpsinfo, pr_pgid)
+
+CANTREAD(curpsinfo, pr_sid)
+CANTREAD(curpsinfo, pr_ttydev)
+CANTREAD(curpsinfo, pr_projid)
+CANTREAD(curpsinfo, pr_zoneid)
+CANTREAD(curpsinfo, pr_contract)
+
+CANREAD(curlwpsinfo, pr_flag)
+CANREAD(curlwpsinfo, pr_lwpid)
+CANREAD(curlwpsinfo, pr_addr)
+CANREAD(curlwpsinfo, pr_wchan)
+CANREAD(curlwpsinfo, pr_stype)
+CANREAD(curlwpsinfo, pr_state)
+CANREAD(curlwpsinfo, pr_sname)
+CANREAD(curlwpsinfo, pr_syscall)
+CANREAD(curlwpsinfo, pr_pri)
+CANREAD(curlwpsinfo, pr_onpro)
+CANREAD(curlwpsinfo, pr_bindpro)
+CANREAD(curlwpsinfo, pr_bindpset)
+
+CANTREAD(curlwpsinfo, pr_clname)
+CANTREAD(curlwpsinfo, pr_lgrp)
+
+CANREAD(curcpu, cpu_id)
+
+CANTREAD(curcpu, cpu_pset)
+CANTREAD(curcpu, cpu_chip)
+CANTREAD(curcpu, cpu_lgrp)
+CANTREAD(curcpu, cpu_info)
+
+/*
+ * We cannot assert one thing or another about the variable "root": for those
+ * with only dtrace_proc, it will be readable in the global but not readable in
+ * the non-global.
+ */
+MIGHTREADVAR(root)
+
+CANREADVAR(cpu)
+CANTREADVAR(pset)
+CANTREADVAR(cwd)
+CANTREADVAR(chip)
+CANTREADVAR(lgrp)
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+/errmsg != ""/
+{
+ printf("fatal error: %s", errmsg);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.providers.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.providers.ksh
new file mode 100644
index 000000000000..94c3722f78b7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.providers.ksh
@@ -0,0 +1,126 @@
+#
+# 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 (c) 2012, Joyent, Inc. All rights reserved.
+#
+
+#
+# First, make sure that we can successfully enable the io provider
+#
+if ! dtrace -P io -n BEGIN'{exit(0)}' > /dev/null 2>&1 ; then
+ echo failed to enable io provider with full privs
+ exit 1
+fi
+
+ppriv -s A=basic,dtrace_proc,dtrace_user $$
+
+#
+# Now make sure that we cannot enable the io provider with reduced privs
+#
+if ! dtrace -x errtags -P io -n BEGIN'{exit(1)}' 2>&1 | \
+ grep D_PDESC_ZERO > /dev/null 2>&1 ; then
+ echo successfully enabled the io provider with reduced privs
+ exit 1
+fi
+
+#
+# Keeping our reduced privs, we want to assure that we can see every provider
+# that we think we should be able to see -- and that we can see curpsinfo
+# state but can't otherwise see arguments.
+#
+/usr/sbin/dtrace -wq -Cs /dev/stdin <<EOF
+
+int seen[string];
+int err;
+
+#define CANENABLE(provider) \
+provider::: \
+/err == 0 && progenyof(\$pid) && !seen["provider"]/ \
+{ \
+ trace(arg0); \
+ printf("\nsuccessful trace of arg0 in %s:%s:%s:%s\n", \
+ probeprov, probemod, probefunc, probename); \
+ exit(++err); \
+} \
+ \
+provider::: \
+/progenyof(\$pid)/ \
+{ \
+ seen["provider"]++; \
+} \
+ \
+provider::: \
+/progenyof(\$pid)/ \
+{ \
+ errstr = "provider"; \
+ this->ignore = stringof(curpsinfo->pr_psargs); \
+ errstr = ""; \
+} \
+ \
+END \
+/err == 0 && !seen["provider"]/ \
+{ \
+ printf("no probes from provider\n"); \
+ exit(++err); \
+} \
+ \
+END \
+/err == 0/ \
+{ \
+ printf("saw %d probes from provider\n", seen["provider"]); \
+}
+
+CANENABLE(proc)
+CANENABLE(sched)
+CANENABLE(vminfo)
+CANENABLE(sysinfo)
+
+BEGIN
+{
+ /*
+ * We'll kick off a system of a do-nothing command -- which should be
+ * enough to kick proc, sched, vminfo and sysinfo probes.
+ */
+ system("echo > /dev/null");
+}
+
+ERROR
+/err == 0 && errstr != ""/
+{
+ printf("fatal error: couldn't read curpsinfo->pr_psargs in ");
+ printf("%s-provided probe\n", errstr);
+ exit(++err);
+}
+
+proc:::exit
+/progenyof(\$pid)/
+{
+ exit(0);
+}
+
+tick-10ms
+/i++ > 500/
+{
+ printf("exit probe did not seem to fire\n");
+ exit(++err);
+}
+EOF
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.unpriv_funcs.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.unpriv_funcs.ksh
new file mode 100644
index 000000000000..c9da0ce68834
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.unpriv_funcs.ksh
@@ -0,0 +1,79 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# Affirmative test of less privileged user operation. We do so by running
+# this test case as root, then as a less privileged user. The output should
+# be exactly the same.
+#
+
+script()
+{
+ cat <<"EOF"
+
+ BEGIN { trace("trace\n"); }
+ BEGIN { printf("%s\n", "printf"); }
+ BEGIN { printf("strlen(\"strlen\") = %d\n", strlen("strlen")); }
+ BEGIN { x = alloca(10);
+ bcopy("alloca\n", x, 7);
+ trace(stringof(x)); }
+
+ BEGIN { printf("index(\"index\", \"x\") = %d\n",
+ index("index", "x")); }
+ BEGIN { printf("strchr(\"strchr\", \'t\') = %s\n",
+ strchr("strchr", 't')); }
+
+ BEGIN { printf("strtok(\"strtok\", \"t\") = %s\n",
+ strtok("strtok", "t")); }
+ BEGIN { printf("strtok(NULL, \"t\") = %s\n",
+ strtok(NULL, "t")); }
+ BEGIN { printf("strtok(NULL, \"t\") = %s\n",
+ strtok(NULL, "t")); }
+ BEGIN { printf("substr(\"substr\", 2, 2) = %s\n",
+ substr("substr", 2, 2)); }
+ BEGIN { trace(strjoin("str", "join\n")); }
+ BEGIN { trace(basename("dirname/basename")); trace("/"); }
+ BEGIN { trace(dirname("dirname/basename")); }
+
+ BEGIN { exit(0); }
+ ERROR { exit(1); }
+EOF
+}
+
+privout=/tmp/$$.priv_output
+unprivout=/tmp/$$.unpriv_output
+
+script | /usr/sbin/dtrace -q -s /dev/stdin > $privout
+ppriv -s A=basic,dtrace_user $$
+script | /usr/sbin/dtrace -q -s /dev/stdin > $unprivout
+
+diff $privout $unprivout
+res=$?
+
+/bin/rm -f $privout $unprivout
+
+exit $res
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.probeqtn.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.probeqtn.d
new file mode 100644
index 000000000000..3560427858af
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.probeqtn.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call probes with mismatch "?" and make sure it results in compilation
+ * error
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+int i;
+BEGIN
+{
+ i = 0;
+}
+
+syscall::?lwp?:entry
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.probestar.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.probestar.d
new file mode 100644
index 000000000000..6103f48618d7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.probestar.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call an undefined probe with matching character "*" and make
+ * sure it results in compilation error.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+no_such_dtrace_probe*
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.tickstar.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.tickstar.d
new file mode 100644
index 000000000000..391b18c3d777
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_PDESC_ZERO.tickstar.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call a probe with matching charecters "*" but does not have
+ * any matching probes.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+int i;
+BEGIN
+{
+ i = 0;
+}
+
+syscall::*tick*:entry
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.assign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.assign.d
new file mode 100644
index 000000000000..e4f7dcb67585
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.assign.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a predicate with no spaces and make sure it results in
+ * compilation error.
+
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+int i = 0;
+
+profile-1
+/i == 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.declare.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.declare.d
new file mode 100644
index 000000000000..30aa26679681
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.declare.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare variables inside probe clause and make sure it results
+ * in compilation error.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1
+{
+ int i = 0;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.declarein.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.declarein.d
new file mode 100644
index 000000000000..9ef8590abb0b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.declarein.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a Variable in between definition and first brace, and make
+ * sure it results in compilation error.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1
+int i;
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.lbraces.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.lbraces.d
new file mode 100644
index 000000000000..b4a4315de379
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.lbraces.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a probe with one missing braces.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1
+{
+ exit(0);
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.probespec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.probespec.d
new file mode 100644
index 000000000000..67c448725430
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.probespec.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Try Declaring Datatypes and variables next to profile declaration and
+ * Make sure it results in compilation error.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1:int i
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.rbraces.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.rbraces.d
new file mode 100644
index 000000000000..4f889d57e6e0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.rbraces.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a probe with one missing braces.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.recdec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.recdec.d
new file mode 100644
index 000000000000..5db21ea9eb00
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/err.D_SYNTAX.recdec.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a probe clause within another probe clause.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1
+{
+ tick-10ms
+{
+}
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.basic1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.basic1.d
new file mode 100644
index 000000000000..df2b1147f18b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.basic1.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple probe clause test; just a empty probe.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.check.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.check.d
new file mode 100644
index 000000000000..d3f2535d738a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.check.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a Variable in BEGIN and use that in another probe.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+int i;
+BEGIN
+{
+ i = 0;
+}
+
+tick-10ms
+/i == 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.declare.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.declare.d
new file mode 100644
index 000000000000..845b3fa49b94
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.declare.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declaration of variable outside probe clause
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+int i;
+tick-10ms
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.declareafter.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.declareafter.d
new file mode 100644
index 000000000000..1c1e2eae2938
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.declareafter.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declaration of a variable after probe clause definition.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ exit(0);
+}
+int i;
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.emptyprobe.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.emptyprobe.d
new file mode 100644
index 000000000000..e23a8dbb691d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.emptyprobe.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Multiple probe clause declarations.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+}
+tick-10ms
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragma.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragma.d
new file mode 100644
index 000000000000..035079d0febc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragma.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Test to Declare pragma in right place.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-10ms
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmaaftertab.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmaaftertab.d
new file mode 100644
index 000000000000..be725f9d54ca
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmaaftertab.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare pragma after a tab and make sure it results in compilation error.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+ #pragma D option quiet
+
+tick-10ms
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmainside.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmainside.d
new file mode 100644
index 000000000000..e602a4148216
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmainside.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare pragma inside probe clause.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+
+tick-10ms
+{
+#pragma D option quiet
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmaoutside.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmaoutside.d
new file mode 100644
index 000000000000..7d2ea61c6189
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.pragmaoutside.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare pragma outside probe clause.
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+
+tick-10ms
+{
+ exit(0);
+}
+#pragma D option quiet
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.probestar.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.probestar.c
new file mode 100644
index 000000000000..bc9f57ba6a8c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.probestar.c
@@ -0,0 +1,47 @@
+/*
+ * 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 2017 Li-Wen Hsu <lwhsu@FreeBSD.org>
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+
+ sigset_t set;
+ siginfo_t info;
+ struct timespec timeout;
+
+ (void)sigemptyset(&set);
+ (void)sigaddset(&set, SIGHUP);
+ timeout.tv_sec = 1;
+ timeout.tv_nsec = 0;
+
+ for (;;)
+ (void)sigtimedwait(&set, &info, &timeout);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.probestar.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.probestar.d
new file mode 100644
index 000000000000..2afb6a8d207e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/probes/tst.probestar.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call matching probe clauses with given name using "*"
+ *
+ * SECTION: Program Structure/Probe Clauses and Declarations
+ *
+ */
+
+
+#pragma D option quiet
+
+int i;
+BEGIN
+{
+ i = 0;
+}
+
+syscall::*wait*:entry
+/pid == $1/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.create.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.create.ksh
new file mode 100644
index 000000000000..6b21eb86c9a5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.create.ksh
@@ -0,0 +1,67 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that the proc:::create probe fires with the proper
+# arguments.
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::create
+ /args[0]->p_pptr->p_pid == $child && pid == $child/
+ {
+ exit(0);
+ }
+EOF
+}
+
+sleeper()
+{
+ while true; do
+ /bin/sleep 1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+sleeper &
+child=$!
+
+script
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.discard.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.discard.ksh
new file mode 100644
index 000000000000..5b948407a50b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.discard.ksh
@@ -0,0 +1,75 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that the proc:::signal-discard probe fires correctly
+# and with the correct arguments.
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::signal-discard
+ /args[1]->p_pid == $child &&
+ xlate<psinfo_t *>(args[1])->pr_psargs == "$longsleep" &&
+ args[2] == SIGHUP/
+ {
+ exit(0);
+ }
+EOF
+}
+
+killer()
+{
+ while true; do
+ sleep 1
+ kill -HUP $child
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+longsleep="/bin/sleep 10000"
+
+/usr/bin/nohup $longsleep &
+child=$!
+
+killer &
+killer=$!
+script
+status=$?
+
+kill $child
+kill $killer
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exec.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exec.ksh
new file mode 100644
index 000000000000..a4ad57212cef
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exec.ksh
@@ -0,0 +1,73 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that the proc:::exec probe fires, followed by the
+# proc:::exec-success probe (in a successful exec(2)).
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::exec
+ /curpsinfo->pr_ppid == $child && args[0] == "/bin/sleep"/
+ {
+ self->exec = 1;
+ }
+
+ proc:::exec-success
+ /self->exec/
+ {
+ exit(0);
+ }
+EOF
+}
+
+sleeper()
+{
+ while true; do
+ /bin/sleep 1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+sleeper &
+child=$!
+
+script
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.execfail.ENOENT.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.execfail.ENOENT.ksh
new file mode 100644
index 000000000000..995eb056255d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.execfail.ENOENT.ksh
@@ -0,0 +1,84 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script is identical to tst.execfail.ksh -- but it additionally checks
+# that errno is set to ENOENT in the case that an interpreter can't be
+# found.
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::exec
+ /curpsinfo->pr_ppid == $child && args[0] == "$badexec"/
+ {
+ self->exec = 1;
+ }
+
+ proc:::exec-failure
+ /self->exec && args[0] == ENOENT/
+ {
+ exit(0);
+ }
+EOF
+}
+
+sleeper()
+{
+ while true; do
+ /bin/sleep 1
+ $badexec
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+badexec=/tmp/execfail.ENOENT.ksh.$$
+dtrace=$1
+
+cat > $badexec <<EOF
+#!/this_is_a_bogus_interpreter
+EOF
+
+chmod +x $badexec
+
+sleeper &
+child=$!
+
+script
+status=$?
+
+kill $child
+rm $badexec
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.execfail.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.execfail.ksh
new file mode 100644
index 000000000000..7fb3faaedc10
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.execfail.ksh
@@ -0,0 +1,86 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that -- if a exec(2) fails -- the proc:::exec probe fires,
+# followed by the proc:::exec-success probe (in a successful exec(2)). To
+# circumvent any potential shell cleverness, this script generates exec
+# failure by generating a file with a bogus interpreter. (It seems unlikely
+# that a shell -- regardless of how clever it claims to be -- would bother to
+# validate the interpreter before exec'ing.)
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::exec
+ /curpsinfo->pr_ppid == $child && args[0] == "$badexec"/
+ {
+ self->exec = 1;
+ }
+
+ proc:::exec-failure
+ /self->exec/
+ {
+ exit(0);
+ }
+EOF
+}
+
+sleeper()
+{
+ while true; do
+ /bin/sleep 1
+ $badexec
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+badexec=/tmp/execfail.ksh.$$
+dtrace=$1
+
+cat > $badexec <<EOF
+#!/this_is_a_bogus_interpreter
+EOF
+
+chmod +x $badexec
+
+sleeper &
+child=$!
+script
+status=$?
+
+kill $child
+rm $badexec
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitcore.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitcore.c
new file mode 100644
index 000000000000..e72b5770b723
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitcore.c
@@ -0,0 +1,36 @@
+/*
+ * 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 2017 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+
+ for (;;)
+ sleep(1);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitcore.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitcore.ksh
new file mode 100644
index 000000000000..59094e3da37f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitcore.ksh
@@ -0,0 +1,86 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that the proc:::exit probe fires with the correct argument
+# when the process core dumps. The problematic bit here is making sure that
+# a process _can_ dump core -- if core dumps are disabled on both a global
+# and per-process basis, this test will fail. Rather than having this test
+# muck with coreadm(1M) settings, it will fail explicitly in this case and
+# provide a hint as to the problem. In general, machines should never be
+# running with both per-process and global core dumps disabled -- so this
+# should be a non-issue in practice.
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::exit
+ /curpsinfo->pr_ppid == $child &&
+ execargs == "$longsleep" && args[0] == CLD_DUMPED/
+ {
+ exit(0);
+ }
+
+ proc:::exit
+ /curpsinfo->pr_ppid == $child &&
+ execargs == "$longsleep" && args[0] != CLD_DUMPED/
+ {
+ printf("Child process could not dump core.");
+ exit(1);
+ }
+EOF
+}
+
+sleeper()
+{
+ while true; do
+ $longsleep &
+ /bin/sleep 1
+ kill -SEGV $!
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+longsleep="./tst.exitcore.exe"
+
+sleeper &
+child=$!
+
+script
+status=$?
+
+kill $child
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitexit.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitexit.ksh
new file mode 100644
index 000000000000..0d71b15f4ee1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitexit.ksh
@@ -0,0 +1,67 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that the proc:::exit probe fires with the correct argument
+# when the process explicitly exits.
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::exit
+ /curpsinfo->pr_ppid == $child && args[0] == CLD_EXITED/
+ {
+ exit(0);
+ }
+EOF
+}
+
+sleeper()
+{
+ while true; do
+ /bin/sleep 1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+sleeper &
+child=$!
+
+script
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitkilled.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitkilled.ksh
new file mode 100644
index 000000000000..86bef7604480
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.exitkilled.ksh
@@ -0,0 +1,75 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that the proc:::exit probe fires with the correct argument
+# when the process is killed.
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::exit
+ /curpsinfo->pr_ppid == $child &&
+ curpsinfo->pr_psargs == "$longsleep" && args[0] == CLD_KILLED/
+ {
+ exit(0);
+ }
+EOF
+}
+
+sleeper()
+{
+ while true; do
+ $longsleep &
+ sleep 1
+ kill -9 $!
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+longsleep="/bin/sleep 10000"
+
+sleeper &
+child=$!
+
+script
+status=$?
+
+kill -STOP $child
+pkill -P $child
+kill $child
+kill -CONT $child
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.signal.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.signal.ksh
new file mode 100644
index 000000000000..cb30eaeb8bb8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.signal.ksh
@@ -0,0 +1,85 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that the proc:::signal-send and proc:::signal-handle
+# probes fire correctly and with the correct arguments.
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::signal-send
+ /execname == "kill" && curpsinfo->pr_ppid == $child &&
+ xlate<psinfo_t *>(args[1])->pr_psargs == "$longsleep" &&
+ args[2] == SIGUSR1/
+ {
+ /*
+ * This is guaranteed to not race with signal-handle.
+ */
+ target = args[1]->p_pid;
+ }
+
+ proc:::signal-handle
+ /target == pid && args[0] == SIGUSR1/
+ {
+ exit(0);
+ }
+EOF
+}
+
+sleeper()
+{
+ while true; do
+ $longsleep &
+ sleep 1
+ kill -USR1 $!
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+longsleep="/bin/sleep 10000"
+
+sleeper &
+child=$!
+
+script
+status=$?
+
+kill -STOP $child
+pkill -P $child
+kill $child
+kill -CONT $child
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.sigwait.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.sigwait.c
new file mode 100644
index 000000000000..c9cc43472cab
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.sigwait.c
@@ -0,0 +1,78 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <signal.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#define NANOSEC 1000000000
+
+int
+main(int argc, char **argv)
+{
+ struct sigevent ev;
+ struct itimerspec ts;
+ sigset_t set;
+ timer_t tid;
+ char *cmd = argv[0];
+ int sig;
+
+ ev.sigev_notify = SIGEV_SIGNAL;
+ ev.sigev_signo = SIGUSR1;
+
+ if (timer_create(CLOCK_REALTIME, &ev, &tid) == -1) {
+ (void) fprintf(stderr, "%s: cannot create CLOCK_HIGHRES "
+ "timer: %s\n", cmd, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ (void) sigemptyset(&set);
+ (void) sigaddset(&set, SIGUSR1);
+ (void) sigprocmask(SIG_BLOCK, &set, NULL);
+
+ ts.it_value.tv_sec = 1;
+ ts.it_value.tv_nsec = 0;
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = NANOSEC / 2;
+
+ if (timer_settime(tid, TIMER_RELTIME, &ts, NULL) == -1) {
+ (void) fprintf(stderr, "%s: timer_settime() failed: %s\n",
+ cmd, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ do {
+ (void) sigwait(&set, &sig);
+ } while(sig != SIGUSR1);
+
+ /*NOTREACHED*/
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.sigwait.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.sigwait.d
new file mode 100644
index 000000000000..bb8281902e22
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.sigwait.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option destructive
+
+proc:::signal-send
+/args[1]->p_pid == $1 && args[2] == SIGUSR1/
+{
+ sent = 1;
+}
+
+proc:::signal-clear
+/pid == $1 && args[0] == SIGUSR1 && sent/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.startexit.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.startexit.ksh
new file mode 100644
index 000000000000..429173806f35
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/proc/tst.startexit.ksh
@@ -0,0 +1,89 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script tests that the firing order of probes in a process is:
+#
+# 1. proc:::start
+# 2. proc:::lwp-start
+# 3. proc:::lwp-exit
+# 4. proc:::exit
+#
+# If this fails, the script will run indefinitely; it relies on the harness
+# to time it out.
+#
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ proc:::start
+ /curpsinfo->pr_ppid == $child/
+ {
+ self->start = 1;
+ }
+
+ proc:::lwp-start
+ /self->start/
+ {
+ self->lwp_start = 1;
+ }
+
+ proc:::lwp-exit
+ /self->lwp_start/
+ {
+ self->lwp_exit = 1;
+ }
+
+ proc:::exit
+ /self->lwp_exit == 1/
+ {
+ exit(0);
+ }
+EOF
+}
+
+sleeper()
+{
+ while true; do
+ /usr/bin/sleep 1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+sleeper &
+child=$!
+
+script
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZERO.profile.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZERO.profile.d
new file mode 100644
index 000000000000..e4e031bab712
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZERO.profile.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * profile without valid value keyword just call with 'n'.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-n
+{
+ printf("This test should fail\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROonens.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROonens.d
new file mode 100644
index 000000000000..3ed28b1b15ba
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROonens.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call profile-'ns' less than 200 micro seconds.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+#pragma D option quiet
+
+profile-1ns
+{
+ printf("Calls 'ns' less than 200 micro seconds\n");
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROonensec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROonensec.d
new file mode 100644
index 000000000000..7b4df199d303
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROonensec.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call profile-1nsec; less than 200 micro seconds.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+#pragma D option quiet
+
+profile-1nsec
+{
+ printf("Call profile-1nsec; less than 200 micro seconds\n");
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROoneus.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROoneus.d
new file mode 100644
index 000000000000..6a64a3a2d4e1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROoneus.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call profile-us; less than 200 micro seconds.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+#pragma D option quiet
+
+profile-1us
+{
+ printf(" Calling profile-us less than 200 micro seconds should fail\n");
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROoneusec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROoneusec.d
new file mode 100644
index 000000000000..b6b80bea03bd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/err.D_PDESC_ZEROoneusec.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * profile-usec; less than 200 micro seconds.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+#pragma D option quiet
+
+profile-1usec
+{
+ printf("profile-usec; less than 200 micro seconds \n");
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.argtest.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.argtest.d
new file mode 100644
index 000000000000..26a40b4133e0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.argtest.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Either one of arg0 (or) arg1 should be 0 and non-zero.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-1
+/(arg0 != 0 && arg1 == 0) || (arg0 == 0 && arg1 != 0)/
+{
+ printf("Test passed; either arg0/arg1 is zero\n");
+ exit(0);
+}
+
+tick-1
+/(arg0 == 0 && arg1 == 0) || (arg0 != 0 && arg1 != 0)/
+{
+ printf("Test failed; either arg0 (or) arg1 should be non zero\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.argtest.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.argtest.d.out
new file mode 100644
index 000000000000..0bd335391684
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.argtest.d.out
@@ -0,0 +1,2 @@
+Test passed; either arg0/arg1 is zero
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.basic.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.basic.d
new file mode 100644
index 000000000000..df8bf98820f3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.basic.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * profile-n simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1
+{
+ printf("This test is a simple profile-n provider test\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.basic.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.basic.d.out
new file mode 100644
index 000000000000..09005bbb8a9b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.basic.d.out
@@ -0,0 +1,2 @@
+This test is a simple profile-n provider test
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.func.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.func.ksh
new file mode 100644
index 000000000000..43aee92fab58
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.func.ksh
@@ -0,0 +1,74 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ profile-1234hz
+ /arg0 != 0/
+ {
+ @[func(arg0)] = count();
+ }
+
+ tick-100ms
+ /i++ == 50/
+ {
+ exit(0);
+ }
+EOF
+}
+
+spinny()
+{
+ while true; do
+ /bin/date > /dev/null
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+spinny &
+child=$!
+
+#
+# This is gutsy -- we're assuming that mtx_lock(9) will show up in the
+# output. This is most likely _not_ to show up in the output if the
+# platform does not support arbitrary resolution interval timers -- but
+# the above script was stress-tested down to 100 hertz and still ran
+# successfully on all platforms, so one is hopeful that this test will pass
+# even in that case.
+#
+script | tee /dev/fd/2 | grep mtx_lock > /dev/null
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.mod.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.mod.ksh
new file mode 100644
index 000000000000..b02db4d6fa14
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.mod.ksh
@@ -0,0 +1,70 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ profile-1234hz
+ /arg0 != 0/
+ {
+ @[mod(arg0)] = count();
+ }
+
+ tick-100ms
+ /i++ == 20/
+ {
+ exit(0);
+ }
+EOF
+}
+
+spinny()
+{
+ while true; do
+ /bin/date > /dev/null
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+spinny &
+child=$!
+
+#
+# The only thing we can be sure of is that some module named "unix" (or
+# "genunix") did some work -- so that's all we'll check.
+#
+script | tee /dev/fd/2 | grep kernel > /dev/null
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilehz.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilehz.d
new file mode 100644
index 000000000000..ba69def5955a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilehz.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple profile-hz test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-100hz
+{
+ printf("This test is a simple profile-hz provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilehz.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilehz.d.out
new file mode 100644
index 000000000000..711f635bbaa8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilehz.d.out
@@ -0,0 +1 @@
+This test is a simple profile-hz provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilems.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilems.d
new file mode 100644
index 000000000000..7ec573e38bc2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilems.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple profile-ms simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1ms
+{
+ printf("This test is a simple profile-ms provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilems.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilems.d.out
new file mode 100644
index 000000000000..1fe17e7c6f2b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilems.d.out
@@ -0,0 +1 @@
+This test is a simple profile-ms provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilemsec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilemsec.d
new file mode 100644
index 000000000000..80451e85bcad
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilemsec.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple profile-msec simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1msec
+{
+ printf("This test is a simple profile-msec provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilemsec.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilemsec.d.out
new file mode 100644
index 000000000000..c3fb4a3b630e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilemsec.d.out
@@ -0,0 +1 @@
+This test is a simple profile-msec provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilenhz.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilenhz.d
new file mode 100644
index 000000000000..37b20907bbc1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilenhz.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * profile-<number> simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-100
+{
+ printf("This test is a simple profile implicit hz test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilenhz.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilenhz.d.out
new file mode 100644
index 000000000000..c9409ce5f51e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilenhz.d.out
@@ -0,0 +1 @@
+This test is a simple profile implicit hz test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilens.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilens.d
new file mode 100644
index 000000000000..72f95ad3c921
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilens.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple profile-2000000000ns simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-2000000000ns
+{
+ printf("This test is a simple profile-ns provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilens.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilens.d.out
new file mode 100644
index 000000000000..86251d01889f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilens.d.out
@@ -0,0 +1 @@
+This test is a simple profile-ns provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilensec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilensec.d
new file mode 100644
index 000000000000..d0236e9a5b53
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilensec.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple profile-nsec simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-2000000000nsec
+{
+ printf("This test is a simple profile-nsec provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilensec.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilensec.d.out
new file mode 100644
index 000000000000..890b769de840
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilensec.d.out
@@ -0,0 +1 @@
+This test is a simple profile-nsec provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profiles.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profiles.d
new file mode 100644
index 000000000000..65201fc84af7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profiles.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple profile-s simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1s
+{
+ printf("This test is a simple profile-s provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profiles.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profiles.d.out
new file mode 100644
index 000000000000..03a0cf220f34
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profiles.d.out
@@ -0,0 +1 @@
+This test is a simple profile-s provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilesec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilesec.d
new file mode 100644
index 000000000000..3e52ac5c6071
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilesec.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple profile-sec simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-1sec
+{
+ printf("This test is a simple profile-sec provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilesec.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilesec.d.out
new file mode 100644
index 000000000000..9091592d1f47
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profilesec.d.out
@@ -0,0 +1 @@
+This test is a simple profile-sec provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileus.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileus.d
new file mode 100644
index 000000000000..32ab415587e6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileus.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple profile-us simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-200us
+{
+ printf("This test is a simple profile-us provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileus.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileus.d.out
new file mode 100644
index 000000000000..aa2706423568
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileus.d.out
@@ -0,0 +1 @@
+This test is a simple profile-us provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileusec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileusec.d
new file mode 100644
index 000000000000..78df000bddc2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileusec.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple profile-usec simple test.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+profile-200usec
+{
+ printf("This test is a simple profile-usec provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileusec.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileusec.d.out
new file mode 100644
index 000000000000..96dfef1c15ac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.profileusec.d.out
@@ -0,0 +1 @@
+This test is a simple profile-usec provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.sym.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.sym.ksh
new file mode 100644
index 000000000000..2946cf2f859e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.sym.ksh
@@ -0,0 +1,70 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ profile-1234hz
+ /arg0 != 0/
+ {
+ @[sym(arg0)] = count();
+ }
+
+ tick-100ms
+ /i++ == 50/
+ {
+ exit(0);
+ }
+EOF
+}
+
+spinny()
+{
+ while true; do
+ /bin/date > /dev/null
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+spinny &
+child=$!
+
+#
+# This is the same gutsy test as that found in the func() test; see that
+# test for the rationale.
+#
+script | tee /dev/fd/2 | grep mtx_lock > /dev/null
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufunc.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufunc.ksh
new file mode 100644
index 000000000000..d2afbed356ac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufunc.ksh
@@ -0,0 +1,71 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ profile-1234hz
+ /arg1 != 0/
+ {
+ @[ufunc(arg1)] = count();
+ }
+
+ tick-100ms
+ /i++ == 20/
+ {
+ exit(0);
+ }
+EOF
+}
+
+spinny()
+{
+ while true; do
+ let i=i+1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+spinny &
+child=$!
+
+#
+# The only thing we can be sure of here is that we caught some function in
+# ksh doing work. (This actually goes one step further and assumes that we
+# catch some non-static function in ksh.)
+#
+script | tee /dev/fd/2 | egrep 'ksh(93)?`[a-zA-Z_]' > /dev/null
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.c
new file mode 100644
index 000000000000..96d78a431cc4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.c
@@ -0,0 +1,78 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+typedef void f(int x);
+
+static void
+f_a(int i)
+{
+}
+
+static void
+f_b(int i)
+{
+}
+
+static void
+f_c(int i)
+{
+}
+
+static void
+f_d(int i)
+{
+}
+
+static void
+f_e(int i)
+{
+}
+
+static void
+fN(f func, int i)
+{
+ func(i);
+}
+
+int
+main()
+{
+ fN(f_a, 1);
+ fN(f_b, 2);
+ fN(f_c, 3);
+ fN(f_d, 4);
+ fN(f_e, 5);
+ fN(f_a, 11);
+ fN(f_c, 13);
+ fN(f_d, 14);
+ fN(f_a, 101);
+ fN(f_c, 103);
+ fN(f_c, 1003);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.ksh
new file mode 100644
index 000000000000..4689355a8e11
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.ksh
@@ -0,0 +1,66 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# ufunc() values sort as expected
+#
+# SECTION: Aggregations, Printing Aggregations
+#
+# NOTES: Assumes that the order of user function addresses will follow
+# the function declaration order.
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -c ./tst.ufuncsort.exe -s /dev/stdin <<EOF
+
+
+ #pragma D option quiet
+ #pragma D option aggsortkey
+
+ pid\$target::fN:entry
+ {
+ @[ufunc(arg0)] = count();
+ }
+EOF
+
+status=$?
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+ exit $status
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.ksh.out
new file mode 100644
index 000000000000..a364322b51b5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufuncsort.ksh.out
@@ -0,0 +1,6 @@
+
+ tst.ufuncsort.exe`f_a 3
+ tst.ufuncsort.exe`f_b 1
+ tst.ufuncsort.exe`f_c 4
+ tst.ufuncsort.exe`f_d 2
+ tst.ufuncsort.exe`f_e 1
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh
new file mode 100644
index 000000000000..8be34ec235d0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh
@@ -0,0 +1,69 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ profile-1234hz
+ /arg1 != 0/
+ {
+ @[umod(arg1)] = count();
+ }
+
+ tick-100ms
+ /i++ == 20/
+ {
+ exit(0);
+ }
+EOF
+}
+
+spinny()
+{
+ while true; do
+ let i=i+1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+spinny &
+child=$!
+
+#
+# The only thing we can be sure of here is that ksh is doing some work.
+#
+script | tee /dev/fd/2 | egrep -w 'ksh(93)?' > /dev/null
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh
new file mode 100644
index 000000000000..8842d2b09565
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh
@@ -0,0 +1,70 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ profile-1234hz
+ /arg1 != 0/
+ {
+ @[usym(arg1)] = count();
+ }
+
+ tick-100ms
+ /i++ == 20/
+ {
+ exit(0);
+ }
+EOF
+}
+
+spinny()
+{
+ while true; do
+ let i=i+1
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+spinny &
+child=$!
+
+#
+# This test is essentially the same as that in the ufunc test; see that
+# test for the rationale.
+#
+script | tee /dev/fd/2 | egrep 'ksh(93)?`[a-zA-Z_]' > /dev/null
+status=$?
+
+kill $child
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_INVAL.wrongdec4.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_INVAL.wrongdec4.d
new file mode 100644
index 000000000000..0a7aa14a8e2a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_INVAL.wrongdec4.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * call profile<provider name>; called with no "::::".
+ * should fail with compilation error.
+ *
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile::::tick-1sec
+{
+ trace(i);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.nonprofile.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.nonprofile.d
new file mode 100644
index 000000000000..1356a8960e77
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.nonprofile.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test;
+ * Call user created provider. Make sure it gives compilation error.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::test
+/i < 3/
+{
+ i++;
+ trace(i);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec1.d
new file mode 100644
index 000000000000..e06edee58b28
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec1.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * call profile::<provider name>; called with two "::".
+ * should fail with compilation error.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile::tick-1sec
+{
+ trace(i);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec2.d
new file mode 100644
index 000000000000..ea8909caa24a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec2.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * call profile:<provider name>; called with one ":".
+ * should fail with compilation error.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:tick-1sec
+{
+ trace(i);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec3.d
new file mode 100644
index 000000000000..edea0b92987a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/err.D_PDESC_ZERO.wrongdec3.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * call profile<provider name>; called with no ":".
+ * should fail with compilation error.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profiletick-1sec
+{
+ trace(i);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.basics.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.basics.d
new file mode 100644
index 000000000000..6b6e5269b457
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.basics.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test;
+ * Call same profile provider two times
+ * Match expected output in tst.basics.d.out
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 3/
+{
+ i++;
+ trace(i);
+}
+
+profile:::tick-1sec
+/i == 3/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.basics.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.basics.d.out
new file mode 100644
index 000000000000..190a18037c64
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.basics.d.out
@@ -0,0 +1 @@
+123
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginexit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginexit.d
new file mode 100644
index 000000000000..202abe67010e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginexit.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ exit(0);
+}
+
+BEGIN
+{
+ printf("shouldn't be here...");
+ here++;
+}
+
+END
+{
+ exit(here);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginprof.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginprof.d
new file mode 100644
index 000000000000..99989d949ab7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginprof.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * print the 'probeprov, probemod, probefunc, probename' from
+ * BEGIN
+ * Match the output from tst.beginprof.d.out
+ *
+ * SECTION: profile Provider/profile-n probes;
+ * Variables/Built-in Variables
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("%s %s %s %s", probeprov, probemod, probefunc, probename);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginprof.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginprof.d.out
new file mode 100644
index 000000000000..d28a05725eb8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.beginprof.d.out
@@ -0,0 +1 @@
+dtrace BEGIN
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probattrs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probattrs.d
new file mode 100644
index 000000000000..bd24ca01b36e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probattrs.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * print the 'probeprov, probemod, probefunc, probename' at once.
+ * Match expected output in tst.probattrs.d.out
+ *
+ *
+ * SECTION: profile Provider/tick-n probes;
+ * Variables/Built-in Variables
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+{
+ printf("%s %s %s %s", probeprov, probemod, probefunc, probename);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probattrs.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probattrs.d.out
new file mode 100644
index 000000000000..2a13979cf662
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probattrs.d.out
@@ -0,0 +1 @@
+profile tick-1sec
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probefunc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probefunc.d
new file mode 100644
index 000000000000..fa7c47c5a2fe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probefunc.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * print the 'probefunc' field i.e. Current probe description's function
+ * field.
+ * Match expected output in tst.probefunc.d.out
+ *
+ * SECTION: profile Provider/tick-n probes;
+ * Variables/Built-in Variables
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+{
+ printf("probe funct = %s", probefunc);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probefunc.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probefunc.d.out
new file mode 100644
index 000000000000..de191dd60d8d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probefunc.d.out
@@ -0,0 +1 @@
+probe funct =
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probemod.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probemod.d
new file mode 100644
index 000000000000..89fd8b2a25b2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probemod.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * print the 'probemod' field i.e. Current probe description's module
+ * field.
+ * Match expected output in tst.probemod.d.out
+ *
+ * SECTION: profile Provider/tick-n probes;
+ * Variables/Built-in Variables
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+{
+ printf("probe description module field = %s", probemod);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probemod.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probemod.d.out
new file mode 100644
index 000000000000..1c95a770f2aa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probemod.d.out
@@ -0,0 +1 @@
+probe description module field =
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probename.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probename.d
new file mode 100644
index 000000000000..c58097f9f59b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probename.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * print the 'probename' field i.e. Current probe description's name
+ * field.
+ * Match expected output in tst.probename.d.out
+ *
+ * SECTION: profile Provider/tick-n probes;
+ * Variables/Built-in Variables
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+{
+ printf("probe name = %s", probename);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probename.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probename.d.out
new file mode 100644
index 000000000000..e5ff3e040aa3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probename.d.out
@@ -0,0 +1 @@
+probe name = tick-1sec
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probprov.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probprov.d
new file mode 100644
index 000000000000..3c3ccef833a1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probprov.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * print the 'probeprov' field i.e. Current probe description's provider
+ * field.
+ * Match expected output in tst.probeprov.d.out
+ *
+ * SECTION: profile Provider/tick-n probes;
+ * Variables/Built-in Variables
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+{
+ printf("probe description provider = %s", probeprov);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probprov.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probprov.d.out
new file mode 100644
index 000000000000..d8ca594f6acc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.probprov.d.out
@@ -0,0 +1 @@
+probe description provider = profile
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profend.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profend.d
new file mode 100644
index 000000000000..9ab438a4a6f8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profend.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * Call simple profile with END profile.
+ * Match expected output in tst.profend.d.out
+ *
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+{
+ i++;
+ trace(i);
+ exit(0);
+}
+
+dtrace:::END
+{
+ printf("\nI'm at END");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profend.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profend.d.out
new file mode 100644
index 000000000000..42e30052f5d3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profend.d.out
@@ -0,0 +1,2 @@
+1
+I'm at END
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profexit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profexit.d
new file mode 100644
index 000000000000..884053f1bd5f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profexit.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test;
+ * Call simple profile
+ * Match expected output in tst.profexit.d.out
+ *
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+{
+ i++;
+ trace(i);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profexit.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profexit.d.out
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.profexit.d.out
@@ -0,0 +1 @@
+1
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.trace.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.trace.d
new file mode 100644
index 000000000000..ec7053d3ec4f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.trace.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * Call simple profile with trace() in END profile
+ * Match expected output in tst.trace.d.out
+ *
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+{
+ i++;
+ exit(0);
+}
+
+dtrace:::END
+{
+ trace(i);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.trace.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.trace.d.out
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.trace.d.out
@@ -0,0 +1 @@
+1
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.twoprof.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.twoprof.d
new file mode 100644
index 000000000000..352ed0b8cbaf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.twoprof.d
@@ -0,0 +1,58 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Simple profile provider test.
+ * Call two different profile provider
+ * Match expected output in tst.twoprof.d.out
+ *
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 3/
+{
+ i++;
+ trace(i);
+}
+
+profile:::tick-100msec
+/i == 3/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.twoprof.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.twoprof.d.out
new file mode 100644
index 000000000000..190a18037c64
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/providers/tst.twoprof.d.out
@@ -0,0 +1 @@
+123
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise1.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise1.c
new file mode 100644
index 000000000000..8dd7bb972ef3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise1.c
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <signal.h>
+
+int
+main(int argc, char **argv)
+{
+ sigset_t ss;
+
+ (void) sigemptyset(&ss);
+ (void) sigaddset(&ss, SIGUSR1);
+ (void) sigprocmask(SIG_BLOCK, &ss, NULL);
+
+ do {
+ (void) getpid();
+ (void) sigpending(&ss);
+ } while (!sigismember(&ss, SIGUSR1));
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise1.d
new file mode 100644
index 000000000000..30bf5ae4bf0a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise1.d
@@ -0,0 +1,68 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for raise
+ *
+ * SECTION: Actions and Subroutines/raise()
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the process to call getpid().
+ */
+ timeout = timestamp + 1000000000;
+}
+
+syscall::getpid:entry
+/pid == $1/
+{
+ trace("raised");
+ raise(SIGUSR1);
+ /*
+ * Wait no more than half a second for the process to die.
+ */
+ timeout = timestamp + 500000000;
+}
+
+syscall::exit:entry
+/pid == $1/
+{
+ exit(0);
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise2.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise2.c
new file mode 100644
index 000000000000..3901d9862097
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise2.c
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+
+static void
+handle(int sig)
+{
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct sigaction sa;
+
+ sa.sa_handler = handle;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ (void) sigaction(SIGUSR1, &sa, NULL);
+
+ for (;;) {
+ (void) getpid();
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise2.d
new file mode 100644
index 000000000000..7d18442d7408
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise2.d
@@ -0,0 +1,68 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for raise
+ *
+ * SECTION: Actions and Subroutines/raise()
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the process to call getpid().
+ */
+ timeout = timestamp + 1000000000;
+}
+
+syscall::getpid:return
+/pid == $1/
+{
+ trace("raised");
+ raise(SIGUSR1);
+ /*
+ * Wait no more than half a second for the process to die.
+ */
+ timeout = timestamp + 500000000;
+}
+
+syscall::exit:entry
+/pid == $1/
+{
+ exit(0);
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise3.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise3.c
new file mode 100644
index 000000000000..3901d9862097
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise3.c
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+
+static void
+handle(int sig)
+{
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct sigaction sa;
+
+ sa.sa_handler = handle;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ (void) sigaction(SIGUSR1, &sa, NULL);
+
+ for (;;) {
+ (void) getpid();
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise3.d
new file mode 100644
index 000000000000..30bf5ae4bf0a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/raise/tst.raise3.d
@@ -0,0 +1,68 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for raise
+ *
+ * SECTION: Actions and Subroutines/raise()
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the process to call getpid().
+ */
+ timeout = timestamp + 1000000000;
+}
+
+syscall::getpid:entry
+/pid == $1/
+{
+ trace("raised");
+ raise(SIGUSR1);
+ /*
+ * Wait no more than half a second for the process to die.
+ */
+ timeout = timestamp + 500000000;
+}
+
+syscall::exit:entry
+/pid == $1/
+{
+ exit(0);
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.aggrate.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.aggrate.d
new file mode 100644
index 000000000000..513cd31266d1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.aggrate.d
@@ -0,0 +1,68 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * If the aggregation rate is set properly, there should be no aggregation
+ * drops.
+ *
+ * SECTION: Aggregations/Minimizing drops;
+ * Options and Tunables/aggrate;
+ * Options and Tunables/aggsize
+ */
+
+/*
+ * We rely on the fact that at least 30 bytes must be stored per aggregation
+ * iteration, but that no more than 300 bytes are stored per iteration.
+ * We are going to let this run for ten seconds. If the aggregation rate
+ * is being set properly, there should be no aggregation drops. Note that
+ * this test (regrettably) may be scheduling sensitive -- but it should only
+ * fail on the most pathological systems.
+ */
+#pragma D option aggsize=300
+#pragma D option aggrate=10msec
+#pragma D option quiet
+
+int n;
+
+tick-100msec
+/n < 100/
+{
+ @a[n++] = sum(n);
+}
+
+tick-100msec
+/n == 100/
+{
+ exit(0);
+}
+
+END
+{
+ printa("%10d\n", @a);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.aggrate.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.aggrate.d.out
new file mode 100644
index 000000000000..c45f92961b34
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.aggrate.d.out
@@ -0,0 +1,101 @@
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.statusrate.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.statusrate.d
new file mode 100644
index 000000000000..43c23bfd940f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.statusrate.d
@@ -0,0 +1,72 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test of statusrate option.
+ *
+ * SECTION: Options and Tunables/statusrate
+ */
+
+/*
+ * Tests the statusrate option, by checking that the time delta between
+ * exit() and END is at least as long as mandated by the statusrate.
+ */
+
+#pragma D option statusrate=10sec
+
+inline uint64_t NANOSEC = 1000000000;
+
+tick-1sec
+/n++ > 5/
+{
+ exit(2);
+ ts = timestamp;
+}
+
+END
+/(this->delta = timestamp - ts) > 2 * NANOSEC/
+{
+ exit(0);
+}
+
+END
+/this->delta <= 2 * NANOSEC/
+{
+ printf("delta between exit() and END (%u nanos) too small",
+ this->delta);
+ exit(1);
+}
+
+END
+/this->delta > 20 * NANOSEC/
+{
+ printf("delta between exit() and END (%u nanos) too large",
+ this->delta);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.switchrate.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.switchrate.d
new file mode 100644
index 000000000000..691b31cd8bbe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.switchrate.d
@@ -0,0 +1,62 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * If the switch rate is set properly, there should be no drops.
+ *
+ * SECTION: Buffers and Buffering/switch Policy;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/switchrate
+ */
+
+/*
+ * We rely on the fact that at least 8 bytes must be stored per iteration
+ * (EPID plus data), but that no more than 40 bytes are stored per iteration.
+ * We are going to let this run for ten seconds. If the switch rate
+ * is being set properly, there should be no drops. Note that this test
+ * (regrettably) may be scheduling sensitive -- but it should only fail on
+ * the most pathological systems.
+ */
+#pragma D option bufsize=40
+#pragma D option switchrate=10msec
+#pragma D option quiet
+
+int n;
+
+tick-100msec
+/n < 100/
+{
+ printf("%10d\n", n++);
+}
+
+tick-100msec
+/n == 100/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.switchrate.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.switchrate.d.out
new file mode 100644
index 000000000000..c45f92961b34
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/rates/tst.switchrate.d.out
@@ -0,0 +1,101 @@
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.basename.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.basename.d
new file mode 100644
index 000000000000..3def9649300b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.basename.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::entry
+/on/
+{
+ trace(basename((char *)rand()));
+}
+
+fbt:::entry
+/on/
+{
+ trace(basename((char *)arg1));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.caller.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.caller.d
new file mode 100644
index 000000000000..b9777c1d031f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.caller.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Make sure that the caller variable is safe to use at every fbt probe
+ * point.
+ *
+ * SECTION: Variables/Built-in Variables;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ trace(caller);
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.cleanpath.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.cleanpath.d
new file mode 100644
index 000000000000..729f320b3908
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.cleanpath.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(cleanpath((char *)rand()));
+}
+
+fbt:::entry
+/on/
+{
+ trace(cleanpath((char *)arg1));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.copyin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.copyin.d
new file mode 100644
index 000000000000..beb1c50bba38
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.copyin.d
@@ -0,0 +1,85 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * We set our buffer size absurdly low to prevent a flood of errors that we
+ * don't care about. We set our statusrate to be infinitely short to cause
+ * lots of activity by the DTrace process.
+ *
+ * SECTION: Actions and Subroutines/copyin();
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+
+#pragma D option bufsize=32
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=1nsec
+
+syscall:::entry
+{
+ n++;
+ trace(copyin(rand(), 1));
+}
+
+syscall:::entry
+{
+ trace(copyin(rand() | 1, 1));
+}
+
+syscall:::entry
+{
+ trace(copyin(NULL, 1));
+}
+
+dtrace:::ERROR
+{
+ err++;
+}
+
+tick-1sec
+/sec++ == 10/
+{
+ exit(2);
+}
+
+END
+/n == 0 || err == 0/
+{
+ exit(1);
+}
+
+END
+/n != 0 && err != 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.copyin2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.copyin2.d
new file mode 100644
index 000000000000..aef094408aaa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.copyin2.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Test that there is no value of 'size' which can be passed to copyin
+ * to cause mischief. The somewhat odd order of operations ensures
+ * that we test both size = 0 and size = 0xfff...fff
+ */
+#include <sys/types.h>
+
+
+#if defined(_LP64)
+#define MAX_BITS 63
+size_t size;
+#else
+#define MAX_BITS 31
+size_t size;
+#endif
+
+syscall:::
+/pid == $pid/
+{
+ printf("size = 0x%lx\n", (ulong_t)size);
+}
+
+syscall:::
+/pid == $pid/
+{
+ tracemem(copyin(curthread->t_procp->p_user.u_envp, size), 10);
+}
+
+syscall:::
+/pid == $pid && size > (1 << MAX_BITS)/
+{
+ exit(0);
+}
+
+syscall:::
+/pid == $pid/
+{
+ size = (size << 1ULL) | 1ULL;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ddi_pathname.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ddi_pathname.d
new file mode 100644
index 000000000000..74275685cb69
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ddi_pathname.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(ddi_pathname((struct dev_info *)rand(), rand()));
+}
+
+fbt:::entry
+/on/
+{
+ trace(ddi_pathname((struct dev_info *)arg1, rand()));
+}
+
+tick-1sec
+/n++ == 20/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.dirname.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.dirname.d
new file mode 100644
index 000000000000..791d9b5f3032
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.dirname.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(dirname((char *)rand()));
+}
+
+fbt:::entry
+/on/
+{
+ trace(dirname((char *)arg1));
+}
+
+tick-1sec
+/n++ == 20/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.errno.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.errno.d
new file mode 100644
index 000000000000..d3f238b79ea8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.errno.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect errno at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[errno] = count();
+}
+
+profile-4999hz
+{
+ @a[errno] = count();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.execname.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.execname.d
new file mode 100644
index 000000000000..cd9ca211516e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.execname.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect execname at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[execname] = count();
+}
+
+profile-4999hz
+{
+ @a[execname] = count();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.gid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.gid.d
new file mode 100644
index 000000000000..f8f90e73641f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.gid.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect gid at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[gid] = count();
+}
+
+profile-4999hz
+{
+ @a[gid] = count();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.hton.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.hton.d
new file mode 100644
index 000000000000..d573bfd1e946
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.hton.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(htons(0x1122));
+}
+
+fbt:::
+/on/
+{
+ trace(htonl(0x11223344));
+}
+
+fbt:::
+/on/
+{
+ trace(htonll(0x1122334455667788));
+}
+
+fbt:::
+/on/
+{
+ trace(ntohs(0x1122));
+}
+
+fbt:::
+/on/
+{
+ trace(ntohl(0x11223344));
+}
+
+fbt:::
+/on/
+{
+ trace(ntohll(0x1122334455667788));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.index.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.index.d
new file mode 100644
index 000000000000..22b0b5bc7d7e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.index.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(index((char *)rand(), (char *)(rand() ^ vtimestamp)));
+}
+
+fbt:::
+/on/
+{
+ trace(rindex((char *)rand(), (char *)(rand() ^ vtimestamp,
+ timestamp)));
+}
+
+fbt:::entry
+/on/
+{
+ trace(index((char *)arg0, (char *)arg1, rand()));
+}
+
+fbt:::entry
+/on/
+{
+ trace(rindex((char *)arg0, (char *)arg1));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.jailname.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.jailname.d
new file mode 100644
index 000000000000..5256a1007559
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.jailname.d
@@ -0,0 +1,44 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Domagoj Stolfa <domagoj.stolfa@cl.cam.ac.uk>.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect jailname at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[jailname] = count();
+}
+
+profile-4999hz
+{
+ @a[jailname] = count();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.jid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.jid.d
new file mode 100644
index 000000000000..034de9328854
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.jid.d
@@ -0,0 +1,44 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Domagoj Stolfa <domagoj.stolfa@cl.cam.ac.uk>.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect jid at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[jid] = count();
+}
+
+profile-4999hz
+{
+ @a[jid] = count();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.msgdsize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.msgdsize.d
new file mode 100644
index 000000000000..c4e7c348fd78
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.msgdsize.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Make sure that the msgdsize safe to use at every fbt probe
+ *
+ * SECTION: Actions and Subroutines/msgdsize();
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(msgdsize((mblk_t *)rand()));
+}
+
+fbt:::entry
+/on/
+{
+ trace(msgdsize((mblk_t *)arg1));
+}
+
+tick-1sec
+/n++ == 20/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.msgsize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.msgsize.d
new file mode 100644
index 000000000000..42aebe4cd147
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.msgsize.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Make sure that the msgsize safe to use at every fbt probe
+ *
+ * SECTION: Actions and Subroutines/msgsize();
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(msgsize((mblk_t *)rand()));
+}
+
+fbt:::
+/on/
+{
+ trace(msgdsize((mblk_t *)rand()));
+}
+
+tick-1sec
+/n++ == 20/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.null.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.null.d
new file mode 100644
index 000000000000..cafa3af717b2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.null.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * trace with NULL argument - generate a bunch of errors
+ *
+ * SECTION: Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy
+ */
+
+/*
+ * We set our buffer size absurdly low to prevent a flood of errors that we
+ * don't care about.
+ */
+
+#pragma D option bufsize=16
+#pragma D option bufpolicy=ring
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ n++;
+ trace(*(int *)NULL);
+}
+
+dtrace:::ERROR
+{
+ err++;
+}
+
+tick-1sec
+/sec++ == 10/
+{
+ exit(2);
+}
+
+END
+/n == 0 || err == 0/
+{
+ exit(1);
+}
+
+END
+/n != 0 && err != 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.pid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.pid.d
new file mode 100644
index 000000000000..2b7a92e13bac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.pid.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect pid at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[pid] = count();
+}
+
+profile-4999hz
+{
+ @a[pid] = count();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ppid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ppid.d
new file mode 100644
index 000000000000..faf07dc482d0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ppid.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect ppid at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[ppid] = count();
+}
+
+profile-4999hz
+{
+ @a[ppid] = count();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.progenyof.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.progenyof.d
new file mode 100644
index 000000000000..d488fe2e898f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.progenyof.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * trace progenyof() at every fbt probe point.
+ *
+ * SECTION: Actions and Subroutines/progenyof();
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ trace(progenyof(rand()));
+}
+
+profile-4999hz
+{
+ trace(progenyof(rand()));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.random.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.random.d
new file mode 100644
index 000000000000..8d157efd459d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.random.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * trace rand() at every fbt probe point.
+ *
+ * SECTION: Actions and Subroutines/rand();
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy
+ */
+
+/*
+ * We set our buffer size absurdly low to prevent a flood of errors that we
+ * don't care about.
+ */
+
+#pragma D option bufsize=16
+#pragma D option bufpolicy=ring
+
+fbt:::
+{
+ n++;
+ trace(*(int *)rand());
+}
+
+dtrace:::ERROR
+{
+ err++;
+}
+
+tick-1sec
+/sec++ == 10/
+{
+ exit(2);
+}
+
+END
+/n == 0 || err == 0/
+{
+ exit(1);
+}
+
+END
+/n != 0 && err != 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.rw.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.rw.d
new file mode 100644
index 000000000000..c1fcd85bac04
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.rw.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ @[rw_read_held((struct rwlock *)&`unp_global_rwlock)] = count();
+ @[rw_read_held((struct rwlock *)rand())] = count();
+}
+
+fbt:::
+/on/
+{
+ @[rw_write_held((struct rwlock *)&`unp_global_rwlock)] = count();
+ @[rw_write_held((struct rwlock *)rand())] = count();
+}
+
+fbt:::
+/on/
+{
+ @[rw_iswriter((struct rwlock *)&`unp_global_rwlock)] = count();
+ @[rw_iswriter((struct rwlock *)rand())] = count();
+}
+
+tick-1sec
+/n++ == 20/
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.shortstr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.shortstr.d
new file mode 100644
index 000000000000..188f705c7c18
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.shortstr.d
@@ -0,0 +1,77 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+#pragma D option strsize=16
+
+BEGIN
+{
+ this->str = ",,,Carrots,,Barley,Oatmeal,,,,,,,,,,,,,,,,,,Beans,";
+}
+
+BEGIN
+{
+ strtok(this->str, ",");
+}
+
+BEGIN
+{
+ this->str = ",,,,,,,,,,,,,,,,,,,,,,Carrots,";
+ strtok(this->str, ",");
+}
+
+BEGIN
+{
+ strtok(this->str, "a");
+}
+
+BEGIN
+{
+ printf("%s\n", substr(this->str, 1, 40));
+}
+
+BEGIN
+{
+ printf("%s\n", strjoin(this->str, this->str));
+}
+
+BEGIN
+{
+ this->str1 = ".........................................";
+ printf("%d\n", index(this->str, this->str1));
+}
+
+BEGIN
+{
+ printf("%d\n", rindex(this->str, this->str1));
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stack.d
new file mode 100644
index 000000000000..57588b4d8bc9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stack.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Call stack() at every fbt probe point.
+ *
+ * SECTION: Actions and Subroutines/stack();
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ stack();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stackdepth.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stackdepth.d
new file mode 100644
index 000000000000..a39387fde04d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stackdepth.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test that the stackdepth variable is safe to use at every fbt probe
+ * point.
+ *
+ * SECTION: Variables/Built-in Variables;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ trace(stackdepth);
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stddev.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stddev.d
new file mode 100644
index 000000000000..927930d03995
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.stddev.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Call stddev() at every fbt probe point.
+ *
+ * SECTION: Actions and Subroutines/stddev();
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ @a = stddev(1);
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strchr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strchr.d
new file mode 100644
index 000000000000..bc95c4861c6d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strchr.d
@@ -0,0 +1,66 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(strchr((char *)(rand() ^ timestamp), rand()));
+}
+
+fbt:::
+/on/
+{
+ trace(strrchr((char *)(rand() ^ timestamp), rand()));
+}
+
+fbt:::entry
+/on/
+{
+ trace(strchr((char *)arg0, '!'));
+}
+
+fbt:::entry
+/on/
+{
+ trace(strrchr((char *)arg0, '!'));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strjoin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strjoin.d
new file mode 100644
index 000000000000..5ed2935d960b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strjoin.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(strjoin((char *)rand(), (char *)(rand() ^ vtimestamp)));
+}
+
+fbt:::entry
+/on/
+{
+ trace(strjoin((char *)arg0, (char *)arg1));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strstr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strstr.d
new file mode 100644
index 000000000000..025e5472ec24
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strstr.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(strstr((char *)rand(), (char *)(rand() ^ vtimestamp)));
+}
+
+fbt:::entry
+/on/
+{
+ trace(strstr((char *)arg0, (char *)arg1));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strtok.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strtok.d
new file mode 100644
index 000000000000..1027d2ed542b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.strtok.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(strtok((char *)rand(), (char *)(rand() ^ vtimestamp)));
+}
+
+fbt:::entry
+/on/
+{
+ trace(strtok((char *)arg0, (char *)arg1));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.substr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.substr.d
new file mode 100644
index 000000000000..d5ed9a48fc5b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.substr.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ on = (timestamp / 1000000000) & 1;
+}
+
+fbt:::
+/on/
+{
+ trace(substr((char *)rand(), rand() ^ vtimestamp));
+}
+
+fbt:::
+/on/
+{
+ trace(substr((char *)rand(), -rand() ^ vtimestamp));
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ucaller.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ucaller.d
new file mode 100644
index 000000000000..524c88b7750c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ucaller.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect ucaller at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[ucaller] = count();
+}
+
+profile-4999hz
+{
+ @a[ucaller] = count();
+}
+
+tick-1sec
+/n++ == 30/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.uid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.uid.d
new file mode 100644
index 000000000000..b546457e7838
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.uid.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect uid at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[uid] = count();
+}
+
+profile-4999hz
+{
+ @a[uid] = count();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.unalign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.unalign.d
new file mode 100644
index 000000000000..e996cbd862d3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.unalign.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * We set our buffer size absurdly low to prevent a flood of errors that we
+ * don't care about. Note that this test (unlike some other safety tests)
+ * doesn't check the error count -- some architectures have no notion of
+ * alignment.
+ */
+#pragma D option bufsize=16
+#pragma D option bufpolicy=ring
+
+fbt:::
+{
+ n++;
+ trace(*(int *)(rand() | 1));
+}
+
+tick-1sec
+/sec++ == 10/
+{
+ exit(2);
+}
+
+END
+/n == 0/
+{
+ exit(1);
+}
+
+END
+/n != 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.uregs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.uregs.d
new file mode 100644
index 000000000000..b13434db0e71
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.uregs.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Trace uregs[0] at every fbt probe point.
+ * SECTION: Variables/Built-in Variables;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ trace(uregs[0]);
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ustack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ustack.d
new file mode 100644
index 000000000000..a286382a0c53
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ustack.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Call ustack() at every fbt probe point.
+ *
+ * SECTION: Actions and Subroutines/ustack();
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ ustack();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ustackdepth.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ustackdepth.d
new file mode 100644
index 000000000000..942913c3c0e8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.ustackdepth.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test that the ustackdepth variable is safe to use at every fbt probe
+ * point.
+ *
+ * SECTION: Variables/Built-in Variables;
+ * Options and Tunables/bufsize;
+ * Options and Tunables/bufpolicy;
+ * Options and Tunables/statusrate
+ */
+
+#pragma D option bufsize=1000
+#pragma D option bufpolicy=ring
+#pragma D option statusrate=10ms
+
+fbt:::
+{
+ trace(ustackdepth);
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.vahole.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.vahole.d
new file mode 100644
index 000000000000..2ef40a5ac474
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.vahole.d
@@ -0,0 +1,69 @@
+#!/usr/sbin/dtrace -Cs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * We set our buffer size absurdly low to prevent a flood of errors that we
+ * don't care about.
+ */
+#pragma D option bufsize=16
+#pragma D option bufpolicy=ring
+
+fbt:::
+{
+ n++;
+#ifdef __sparc
+ trace(*(int *)0x8000000000000000 ^ rand());
+#else
+ trace(*(int *)(`kernelbase - 1));
+#endif
+}
+
+dtrace:::ERROR
+{
+ err++;
+}
+
+tick-1sec
+/sec++ == 10/
+{
+ exit(2);
+}
+
+END
+/n == 0 || err == 0/
+{
+ exit(1);
+}
+
+END
+/n != 0 && err != 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.violentdeath.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.violentdeath.ksh
new file mode 100644
index 000000000000..879774a42ea3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.violentdeath.ksh
@@ -0,0 +1,51 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+script()
+{
+ $dtrace -x bufpolicy=ring -x bufsize=1k -s /dev/stdin <<EOF
+ fbt:::
+ {}
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+let i=0
+
+while [ "$i" -lt 10 ]; do
+ script &
+ child=$!
+ sleep 1
+ kill -9 $child
+ let i=i+1
+done
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.zonename.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.zonename.d
new file mode 100644
index 000000000000..5fc025f9557e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/safety/tst.zonename.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * collect zonename at every fbt probe and at every firing of a
+ * high-frequency profile probe
+ */
+
+fbt:::
+{
+ @a[zonename] = count();
+}
+
+profile-4999hz
+{
+ @a[zonename] = count();
+}
+
+tick-1sec
+/n++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_ARR_LOCAL.thisarray.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_ARR_LOCAL.thisarray.d
new file mode 100644
index 000000000000..289d164d4270
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_ARR_LOCAL.thisarray.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Use 'this' variables in associative array.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+
+this int y;
+this int z;
+this int res;
+
+BEGIN
+{
+ this->x[this->y, this->z] = 123;
+ this->res = this->x[this->y, this->z]++;
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_CLASS.selfthis.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_CLASS.selfthis.d
new file mode 100644
index 000000000000..eda1151b24be
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_CLASS.selfthis.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declare a variable and assign inappropriate value.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+self this int x;
+
+BEGIN
+{
+ x = "dummy";
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_CLASS.thisself.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_CLASS.thisself.d
new file mode 100644
index 000000000000..f9c596b631dd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_CLASS.thisself.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Multiple storage declarations.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+this self int x;
+
+BEGIN
+{
+ x = "dummy";
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_IDRED.errval.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_IDRED.errval.d
new file mode 100644
index 000000000000..3130fbfe4855
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_DECL_IDRED.errval.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declare a variable with different data types.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+int x;
+char x;
+double x;
+long x;
+
+BEGIN
+{
+ x = 123;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dec.err.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dec.err.d
new file mode 100644
index 000000000000..4261e0727d15
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dec.err.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a variable and assign inappropriate value.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+int x;
+
+BEGIN
+{
+ x = "dummy";
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupgtype.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupgtype.d
new file mode 100644
index 000000000000..71f9c0b4823d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupgtype.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test assigning a variable two different incompatible types.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+
+BEGIN
+{
+ x = `kmem_flags;
+ x = *`rootvp;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupltype.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupltype.d
new file mode 100644
index 000000000000..c316441e3e8b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupltype.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test assigning a variable two different incompatible types.
+ *
+ * SECTION: Variables/Clause-Local Variables
+ *
+ */
+
+BEGIN
+{
+ this->x = `kmem_flags;
+ this->x = *`rootvp;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupttype.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupttype.d
new file mode 100644
index 000000000000..23f26f7fc07f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_OP_INCOMPAT.dupttype.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test assigning a variable two different incompatible types.
+ * Test assigning a variable two different incompatible types.
+ *
+ * SECTION: Variables/Thread-Local Variables
+ *
+ */
+
+BEGIN
+{
+ self->x = `kmem_flags;
+ self->x = *`rootvp;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_SYNTAX.declare.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_SYNTAX.declare.d
new file mode 100644
index 000000000000..246236a9252f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.D_SYNTAX.declare.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a variable Inside Begin and make sure compilation fails.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+
+BEGIN
+{
+ int x = 123;
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.bigglobal.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.bigglobal.d
new file mode 100644
index 000000000000..a50a759e4eb5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.bigglobal.d
@@ -0,0 +1,26 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ */
+
+struct mrbig {
+ char toomany[100000];
+};
+
+struct mrbig mrbig;
+
+BEGIN
+{
+ mrbig.toomany[0] = '!';
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.biglocal.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.biglocal.d
new file mode 100644
index 000000000000..08a2a4c2ed84
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.biglocal.d
@@ -0,0 +1,26 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ */
+
+struct mrbig {
+ char toomany[100000];
+};
+
+this struct mrbig mrbig;
+
+BEGIN
+{
+ this->mrbig.toomany[0] = '!';
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.16kglobal.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.16kglobal.d
new file mode 100644
index 000000000000..8a5d1cd3a01e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.16kglobal.d
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2016, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option strsize=16k
+
+char *k;
+
+BEGIN
+{
+ j = probeprov;
+ k = j;
+ k[0] = 'D';
+ k[1] = 'T';
+}
+
+BEGIN
+{
+ trace(stringof(k));
+ exit(k == "DTrace" ? 0 : 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.16klocal.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.16klocal.d
new file mode 100644
index 000000000000..930520c235c5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.16klocal.d
@@ -0,0 +1,29 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2016, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option strsize=16k
+
+BEGIN
+{
+ this->j = probeprov;
+ this->j[0] = 'D';
+ this->j[1] = 'T';
+}
+
+BEGIN
+{
+ trace(this->j);
+ exit(this->j == "DTrace" ? 0 : 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.basicvar.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.basicvar.d
new file mode 100644
index 000000000000..55616314c041
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.basicvar.d
@@ -0,0 +1,57 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Global variables defined once, is visible in every clause of
+ * D program
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+
+#pragma D option quiet
+
+int x;
+
+BEGIN
+{
+ x = 123;
+}
+
+profile:::tick-1sec
+{
+ printf("The value of x is %d\n", x);
+}
+
+profile:::tick-100msec
+{
+ printf("The value of x is %d\n", x);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.basicvar.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.basicvar.d.out
new file mode 100644
index 000000000000..2b8999e4430a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.basicvar.d.out
@@ -0,0 +1,2 @@
+The value of x is 123
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.localvar.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.localvar.d
new file mode 100644
index 000000000000..9a89a0485125
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.localvar.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Assign a value to a variable in a local clause.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+}
+int i;
+
+profile:::tick-1sec
+{
+ i = 0;
+}
+
+profile:::tick-100msec
+{
+ printf("The value of int i is %d\n", i);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.misc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.misc.d
new file mode 100644
index 000000000000..3b6eb7a71507
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.misc.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the different kinds of integer scalar references. In particular, we
+ * test accessing a kernel executable scalar, kernel scoped scalar, DTrace
+ * scalar first ref that forces creation (both global and TLS), and DTrace
+ * scalar subsequent reference (both global and TLS).
+ *
+ * SECTION: Variables/External Variables
+ *
+ */
+
+BEGIN
+{
+ printf("\nkmem_flags = 0x%x\n", `kmem_flags);
+ printf("ufs`ufs_allow_shared_writes = %d\n",
+ ufs`ufs_allow_shared_writes);
+ x = 123;
+ printf("x = %u\n", x);
+ self->x = 456;
+ printf("self->x = %u\n", self->x);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.self.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.self.d
new file mode 100644
index 000000000000..514f3859ec98
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.self.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declare self a variable and assign appropriate value.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+self x;
+
+BEGIN
+{
+ x = "dummy";
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfarray.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfarray.d
new file mode 100644
index 000000000000..410e8def449d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfarray.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a self variable and assign appropriate value.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+
+self int y;
+self int z;
+self int res;
+
+BEGIN
+{
+ self->x[self->y, self->z] = 123;
+ self->res = self->x[self->y, self->z]++;
+ printf("The result = %d\n", self->res);
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfarray2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfarray2.d
new file mode 100644
index 000000000000..036a6526fe7c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfarray2.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+#pragma D option destructive
+#pragma D option dynvarsize=1m
+
+struct bar {
+ pid_t pid;
+ struct thread *curthread;
+};
+
+self struct bar foo[int];
+
+syscall:::entry
+/!self->foo[0].pid/
+{
+ self->foo[0].pid = pid;
+ self->foo[0].curthread = curthread;
+}
+
+syscall:::entry
+/self->foo[0].pid != pid/
+{
+ printf("expected %d, found %d (found curthread %p, curthread is %p)\n",
+ pid, self->foo[0].pid, self->foo[0].curthread, curthread);
+ exit(1);
+}
+
+tick-100hz
+{
+ system("date > /dev/null")
+}
+
+tick-1sec
+/i++ == 10/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfthis.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfthis.d
new file mode 100644
index 000000000000..7bbfaf76a483
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.selfthis.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Declare a this variable and assign value of self variable to it.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+self int x;
+this int y;
+
+BEGIN
+{
+ this->x = 123;
+ self->y = this->x;
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.this.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.this.d
new file mode 100644
index 000000000000..01ea89f48421
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.this.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple 'this' declaration.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+this x;
+
+BEGIN
+{
+ x = "dummy";
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.thisself.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.thisself.d
new file mode 100644
index 000000000000..925dff2bbf6d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/tst.thisself.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declare a self value and assign value of 'this' variable to that.
+ *
+ * SECTION: Variables/Scalar Variables
+ *
+ */
+self int x;
+this int y;
+
+BEGIN
+{
+ self->x = 123;
+ this->y = self->x;
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.enqueue.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.enqueue.d
new file mode 100644
index 000000000000..77105c1efa2b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.enqueue.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option switchrate=100hz
+#pragma D option destructive
+
+sched:::enqueue
+/pid == 0 && args[1]->pr_pid == $pid/
+{
+ self->one = 1;
+}
+
+sched:::enqueue
+/self->one && args[2]->cpu_id >= 0 && args[2]->cpu_id <= `max_cpuid/
+{
+ self->two = 1;
+}
+
+sched:::enqueue
+/self->two && args[0]->pr_lwpid > 0/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.oncpu.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.oncpu.d
new file mode 100644
index 000000000000..25717671580e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.oncpu.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option switchrate=100hz
+#pragma D option destructive
+
+sched:::on-cpu
+/pid == $pid/
+{
+ self->on++;
+}
+
+sched:::off-cpu
+/pid == $pid && self->on/
+{
+ self->off++;
+}
+
+sched:::off-cpu
+/self->on > 50 && self->off > 50/
+{
+ exit(0);
+}
+
+profile:::tick-1sec
+/n++ > 10/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.stackdepth.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.stackdepth.d
new file mode 100644
index 000000000000..b42512708b85
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sched/tst.stackdepth.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option switchrate=100hz
+
+sched:::on-cpu
+/stackdepth > 0/
+{
+ exit(0);
+}
+
+tick-1s
+/i++ == 3/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_MACRO_UNDEF.invalidargs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_MACRO_UNDEF.invalidargs.d
new file mode 100644
index 000000000000..27d969e71086
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_MACRO_UNDEF.invalidargs.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Try to print arguments not provided.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ print("The arguments are %d %d\n", $1, $2);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_OP_LVAL.rdonly.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_OP_LVAL.rdonly.d
new file mode 100644
index 000000000000..5bf467515923
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_OP_LVAL.rdonly.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Try to update a read-only macro.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ $pid++;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_OP_WRITE.usepidmacro.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_OP_WRITE.usepidmacro.d
new file mode 100644
index 000000000000..649cbdbcff92
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_OP_WRITE.usepidmacro.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Try to assign value to Macro.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ pid = 1;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.concat.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.concat.d
new file mode 100644
index 000000000000..00a299696c50
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.concat.d
@@ -0,0 +1,45 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Try to concat macro with user variables in provider description
+ * section.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+/i = 123$pid/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.desc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.desc.d
new file mode 100644
index 000000000000..3dfa2b266b47
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.desc.d
@@ -0,0 +1,49 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Try to call providers using macro variables.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+/i = 123$pid/
+{
+ exit(0);
+}
+
+pid$pid
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.inval.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.inval.d
new file mode 100644
index 000000000000..28b251cd112a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.inval.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Attempt to print invalid arguments.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ print("The arguments are %d %d\n", $-1);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.pid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.pid.d
new file mode 100644
index 000000000000..d9711d2afd73
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/err.D_SYNTAX.pid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Attempt to concat and assign a macro to a variable
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ i = 123$pid;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.D_MACRO_UNUSED.overflow.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.D_MACRO_UNUSED.overflow.ksh
new file mode 100644
index 000000000000..3c493dffa50d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.D_MACRO_UNUSED.overflow.ksh
@@ -0,0 +1,80 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Attempt to pass some arguments and try not to print it.
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$.d
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+BEGIN
+{
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#Call dtrace -C -s <.d>
+
+$dtrace -x errtags -s $dfilename "this is test" 1>/dev/null \
+ 2>/var/tmp/err.$$.txt
+
+if [ $? -ne 1 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+grep "D_MACRO_UNUSED" /var/tmp/err.$$.txt >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ print -u2 "Expected error D_MACRO_UNUSED not returned"
+ /bin/rm -f /var/tmp/err.$$.txt
+ exit 1
+fi
+
+/bin/rm -f $dfilename
+/bin/rm -f /var/tmp/err.$$.txt
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.arg0.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.arg0.d
new file mode 100644
index 000000000000..999dbc329ce0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.arg0.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print argument 0 I mean "$0"
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The arg0 is %s\n", $0);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.arguments.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.arguments.ksh
new file mode 100644
index 000000000000..89c6a6aebb13
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.arguments.ksh
@@ -0,0 +1,90 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Pass 10 arguments and try to print them.
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+bname=`basename $0`
+
+dfilename=/var/tmp/$bname.$$
+
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+
+BEGIN
+{
+ printf("%d %d %d %d %d %d %d %d %d %d", \$1, \$2, \$3, \$4, \$5, \$6,
+ \$7, \$8, \$9, \$10);
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#Call dtrace -C -s <.d>
+
+chmod 555 $dfilename
+
+
+output=`$dfilename 1 2 3 4 5 6 7 8 9 10 2>/dev/null`
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+set -A outarray $output
+
+if [[ ${outarray[0]} != 1 || ${outarray[1]} != 2 || ${outarray[2]} != 3 || \
+ ${outarray[3]} != 4 || ${outarray[4]} != 5 || ${outarray[5]} != 6 || \
+ ${outarray[6]} != 7 || ${outarray[7]} != 8 || ${outarray[8]} != 9 || \
+ ${outarray[9]} != 10 ]]; then
+ print -u2 "Error in output by $dfilename"
+ exit 1
+fi
+
+/bin/rm -f $dfilename
+exit 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.assign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.assign.d
new file mode 100644
index 000000000000..5dd17407de4c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.assign.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Assign macros to variables
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ processid = $pid;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.basic.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.basic.d
new file mode 100644
index 000000000000..a407f839c5b6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.basic.d
@@ -0,0 +1,42 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Basic script which uses exit(0) to exit.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.egid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.egid.d
new file mode 100644
index 000000000000..3899d2ad298f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.egid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Script which prints effective group id.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The egid is %d\n", $egid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.egid.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.egid.ksh
new file mode 100644
index 000000000000..2397db6e1b72
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.egid.ksh
@@ -0,0 +1,97 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+#
+# To verify egid of current process
+#
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$.d
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+
+BEGIN
+/\$egid != \$1/
+{
+ exit(1);
+}
+
+BEGIN
+/\$egid == \$1/
+{
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#chmod 555 the .d file
+
+chmod 555 $dfilename >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ print -u2 "chmod $dfilename failed"
+ exit 1
+fi
+
+#Get the groupid of the calling process using ps
+
+groupid=`ps -x -o pid,egid | grep "$$ " | awk '{print $2}' 2>/dev/null`
+if [ $? -ne 0 ]; then
+ print -u2 "unable to get uid of the current process with pid = $$"
+ exit 1
+fi
+
+#Pass groupid as argument to .d file
+$dfilename $groupid >/dev/null 2>&1
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+#Cleanup leftovers
+
+rm -f $dfilename
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.euid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.euid.d
new file mode 100644
index 000000000000..e4cdaa6b9ffb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.euid.d
@@ -0,0 +1,44 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Script which prints effective user id.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The euid is %d\n", $euid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.euid.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.euid.ksh
new file mode 100644
index 000000000000..5bdc391dbbc0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.euid.ksh
@@ -0,0 +1,86 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# To verify euid of current process
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+
+BEGIN
+/\$euid != \$1/
+{
+ exit(1);
+}
+
+BEGIN
+/\$euid == \$1/
+{
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#Call dtrace -C -s <.d>
+
+chmod 555 $dfilename
+
+userid=`ps -x -o pid,uid | grep "$$ " | awk '{print $2}' 2>/dev/null`
+if [ $? -ne 0 ]; then
+ print -u2 "unable to get uid of the current process with pid = $$"
+ exit 1
+fi
+
+$dfilename $userid >/dev/null 2>&1
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+rm -f $dfilename
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.gid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.gid.d
new file mode 100644
index 000000000000..c3329ce12061
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.gid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Script which prints group id.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The gid is %d\n", $gid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.gid.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.gid.ksh
new file mode 100644
index 000000000000..0c4e77b54e4f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.gid.ksh
@@ -0,0 +1,86 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# To verify gid of the child process.
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+
+BEGIN
+/\$gid != \$1/
+{
+ exit(1);
+}
+
+BEGIN
+/\$gid == \$1/
+{
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#Call dtrace -C -s <.d>
+
+chmod 555 $dfilename
+
+groupid=`ps -x -o pid,gid | grep "$$ " | awk '{print $2}' 2>/dev/null`
+if [ $? -ne 0 ]; then
+ print -u2 "unable to get uid of the current process with pid = $$"
+ exit 1
+fi
+
+$dfilename $groupid >/dev/null 2>&1
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+rm -f $dfilename
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.pgid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.pgid.d
new file mode 100644
index 000000000000..e01b99684474
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.pgid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Script which prints effective process group id.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The pgid is %d\n", $pgid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.pid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.pid.d
new file mode 100644
index 000000000000..1364366c37b5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.pid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Script which prints pid.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The pid is %d\n", $pid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.ppid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.ppid.d
new file mode 100644
index 000000000000..8712cd963493
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.ppid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Script which prints parent processid
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The ppid is %d\n", $ppid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.ppid.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.ppid.ksh
new file mode 100644
index 000000000000..37613ce1a5e1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.ppid.ksh
@@ -0,0 +1,86 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# To verify ppid of child process.
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$.d
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+
+BEGIN
+/\$ppid != \$1/
+{
+ exit(1);
+}
+
+BEGIN
+/\$ppid == \$1/
+{
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#chmod the .d file to 555
+
+chmod 555 $dfilename >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ print -u2 "chmod 555 $dfilename failed"
+ exit 1
+fi
+
+#Pass current pid (I mean parent pid for .d script).
+
+$dfilename $$ #>/dev/null 2>&1
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+rm -f $dfilename
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.projid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.projid.d
new file mode 100644
index 000000000000..a81ab8ee6e02
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.projid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Script which prints current project id.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The projid is %d\n", $projid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.projid.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.projid.ksh
new file mode 100644
index 000000000000..e11f1e56b47d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.projid.ksh
@@ -0,0 +1,86 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# To verify projid of child process.
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+
+BEGIN
+/\$projid != \$1/
+{
+ exit(1);
+}
+
+BEGIN
+/\$projid == \$1/
+{
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#Call dtrace -C -s <.d>
+
+chmod 555 $dfilename
+
+projectid=`ps -x -o pid,projid | grep "$$ " | awk '{print $2}' 2>/dev/null`
+if [ $? -ne 0 ]; then
+ print -u2 "unable to get uid of the current process with pid = $$"
+ exit 1
+fi
+
+$dfilename $projectid >/dev/null 2>&1
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+rm -f $dfilename
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.quite.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.quite.d
new file mode 100644
index 000000000000..c61debed1bdd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.quite.d
@@ -0,0 +1,42 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Script which uses -qs in scripting line
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.sid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.sid.d
new file mode 100644
index 000000000000..87bab5369efb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.sid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Script which prints session id.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The sid is %d\n", $sid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.sid.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.sid.ksh
new file mode 100644
index 000000000000..08a65b2d62dc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.sid.ksh
@@ -0,0 +1,86 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# To verify sid of current process.
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+
+BEGIN
+/\$sid != \$1/
+{
+ exit(1);
+}
+
+BEGIN
+/\$sid == \$1/
+{
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#Call dtrace -C -s <.d>
+
+chmod 555 $dfilename
+
+sessionid=`ps -x -o pid,sid | grep "$$ " | awk '{print $2}' 2>/dev/null`
+if [ $? -ne 0 ]; then
+ print -u2 "unable to get sid of the current process with pid = $$"
+ exit 1
+fi
+
+$dfilename $sessionid >/dev/null 2>&1
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+rm -f $dfilename
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.stringmacro.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.stringmacro.ksh
new file mode 100644
index 000000000000..a8b1ec1fe61e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.stringmacro.ksh
@@ -0,0 +1,78 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# Pass a bunch of strings as a sentence and print them
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$.d
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+BEGIN
+{
+ printf("%s", \$\$1);
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#Call dtrace -C -s <.d>
+
+chmod 555 $dfilename
+
+output=`$dfilename 'this is test' 2>/dev/null`
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+if [ "$output" != "this is test" ]; then
+ print -u2 "Expected output not returned"
+ exit 1
+fi
+
+/bin/rm -f $dfilename
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.taskid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.taskid.d
new file mode 100644
index 000000000000..617827c8d35c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.taskid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Script which prints taskid.
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The taskid is %d\n", $taskid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.taskid.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.taskid.ksh
new file mode 100644
index 000000000000..e4de7fbfd3d4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.taskid.ksh
@@ -0,0 +1,86 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# To verify taskid of current process.
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+
+BEGIN
+/\$taskid != \$1/
+{
+ exit(1);
+}
+
+BEGIN
+/\$taskid == \$1/
+{
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#Call dtrace -C -s <.d>
+
+chmod 555 $dfilename
+
+taskidval=`ps -x -o pid,taskid | grep "$$ " | awk '{print $2}' 2>/dev/null`
+if [ $? -ne 0 ]; then
+ print -u2 "unable to get uid of the current process with pid = $$"
+ exit 1
+fi
+
+$dfilename $taskidval >/dev/null 2>&1
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+rm -f $dfilename
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.trace.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.trace.d
new file mode 100644
index 000000000000..34ba243ef978
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.trace.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * To use trace in a script
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ trace("hello");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.uid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.uid.d
new file mode 100644
index 000000000000..f3ebca615001
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.uid.d
@@ -0,0 +1,43 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * print uid in a script
+ *
+ * SECTION: Scripting
+ *
+ */
+
+BEGIN
+{
+ printf("The uid is %d\n", $uid);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.uid.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.uid.ksh
new file mode 100644
index 000000000000..8cd6130ff644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scripting/tst.uid.ksh
@@ -0,0 +1,86 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+############################################################################
+# ASSERTION:
+# To verify uid of current process.
+#
+# SECTION: Scripting
+#
+############################################################################
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+bname=`basename $0`
+dfilename=/var/tmp/$bname.$$
+
+## Create .d file
+##########################################################################
+cat > $dfilename <<-EOF
+#!$dtrace -qs
+
+
+BEGIN
+/\$uid != \$1/
+{
+ exit(1);
+}
+
+BEGIN
+/\$uid == \$1/
+{
+ exit(0);
+}
+EOF
+##########################################################################
+
+
+#Call dtrace -C -s <.d>
+
+chmod 555 $dfilename
+
+userid=`ps -x -o pid,uid | grep "$$ " | awk '{print $2}' 2>/dev/null`
+if [ $? -ne 0 ]; then
+ print -u2 "unable to get uid of the current process with pid = $$"
+ exit 1
+fi
+
+$dfilename $userid >/dev/null 2>&1
+
+if [ $? -ne 0 ]; then
+ print -u2 "Error in executing $dfilename"
+ exit 1
+fi
+
+rm -f $dfilename
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.c
new file mode 100644
index 000000000000..013a9e7c7897
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.c
@@ -0,0 +1,49 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+ int val = 1;
+
+ while (1) {
+ if (sysctlbyname("debug.dtracetest.sdttest", NULL, NULL, &val,
+ sizeof(val)))
+ err(1, "sysctlbyname");
+
+ sleep(1);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.d
new file mode 100644
index 000000000000..e965b05f2405
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Verify that argN (1..7) variables are properly remapped.
+ */
+
+BEGIN
+{
+ /* Timeout after 5 seconds */
+ timeout = timestamp + 5000000000;
+ ignore = $1;
+}
+
+ERROR
+{
+ printf("sdt:::test failed.\n");
+ exit(1);
+}
+
+test:::sdttest
+/arg0 != 1 || arg1 != 2 || arg2 != 3 || arg3 != 4 || arg4 != 5 || arg5 != 6 ||
+ arg6 != 7/
+{
+ printf("sdt arg mismatch\n\n");
+ printf("args are : %d, %d, %d, %d, %d, %d, %d\n", arg0, arg1, arg2,
+ arg3, arg4, arg5, arg6);
+ printf("should be : 1, 2, 3, 4, 5, 6, 7\n");
+ exit(1);
+}
+
+test:::sdttest
+{
+ exit(0);
+}
+
+profile:::tick-1
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_IDENT_BADREF.SizeofAssoc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_IDENT_BADREF.SizeofAssoc.d
new file mode 100644
index 000000000000..9ace4197659a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_IDENT_BADREF.SizeofAssoc.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: sizeof returns the size in bytes of any D expression or data
+ * type. For an associative array, the D compiler should throw an error since
+ * an associative array does not have a fixed size.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ assoc_array[0] = 010;
+ assoc_array[1] = 100;
+ assoc_array[2] = 210;
+
+ printf("sizeof (assoc_array): %d\n", sizeof (assoc_array));
+ printf("sizeof (assoc_array[0]): %d\n", sizeof (assoc_array[0]));
+ printf("sizeof (assoc_array[1]): %d\n", sizeof (assoc_array[1]));
+ printf("sizeof (assoc_array[2]): %d\n", sizeof (assoc_array[2]));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d
new file mode 100644
index 000000000000..f2dcdfab20da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: The D compiler throws a D_IDENT_UNDEF error when sizeof is passed
+ * an unknown symbol.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ printf("sizeof (`): %d\n", sizeof (`));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SIZEOF_TYPE.badstruct.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SIZEOF_TYPE.badstruct.d
new file mode 100644
index 000000000000..c921db88b62d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SIZEOF_TYPE.badstruct.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ trace(sizeof (struct suckitlarry));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SIZEOF_TYPE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SIZEOF_TYPE.d
new file mode 100644
index 000000000000..43c493a594b2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SIZEOF_TYPE.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * sizeof() should handle invalid types
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ */
+
+BEGIN
+{
+ trace(sizeof (void));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SYNTAX.SizeofBadType.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SYNTAX.SizeofBadType.d
new file mode 100644
index 000000000000..85519e6dd7f7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/err.D_SYNTAX.SizeofBadType.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: sizeof returns the size in bytes of any D expression or data
+ * type. When an operator or non-symbol is passed as an argument to sizeof
+ * operator, the D_SYNTAX error is thrown by the compiler.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ printf("sizeof (*): %d\n", sizeof (*));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofArray.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofArray.d
new file mode 100644
index 000000000000..8843728c409e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofArray.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: sizeof returns the size in bytes of any D expression or data
+ * type. For a simpler array, the sizeof on the array variable itself gives
+ * the sum total of memory allocated to the array in bytes. With individual
+ * members of the array it gives their respective sizes.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ */
+#pragma D option quiet
+
+int array[5];
+
+BEGIN
+{
+ array[0] = 010;
+ array[1] = 100;
+ array[2] = 210;
+
+ printf("sizeof (array): %d\n", sizeof (array));
+ printf("sizeof (array[0]): %d\n", sizeof (array[0]));
+ printf("sizeof (array[1]): %d\n", sizeof (array[1]));
+ printf("sizeof (array[2]): %d\n", sizeof (array[2]));
+
+ exit(0);
+}
+
+END
+/(20 != sizeof (array)) || (4 != sizeof (array[0])) || (4 != sizeof (array[1]))
+ || (4 != sizeof (array[2]))/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofDataTypes.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofDataTypes.d
new file mode 100644
index 000000000000..fe558e8e0bc0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofDataTypes.d
@@ -0,0 +1,122 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: sizeof returns the size in bytes of any D expression or data
+ * type.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ */
+#pragma D option quiet
+
+char new_char;
+short new_short;
+int new_int;
+long new_long;
+long long new_long_long;
+int8_t new_int8;
+int16_t new_int16;
+int32_t new_int32;
+int64_t new_int64;
+intptr_t new_intptr;
+uint8_t new_uint8;
+uint16_t new_uint16;
+uint32_t new_uint32;
+uint64_t new_uint64;
+uintptr_t new_uintptr;
+
+/*
+float new_float;
+double new_double;
+long double new_long_double;
+
+string new_string;
+*/
+
+struct record {
+ char ch;
+ int in;
+} new_struct;
+
+struct {
+ char ch;
+ int in;
+} anon_struct;
+
+union record {
+ char ch;
+ int in;
+} new_union;
+
+union {
+ char ch;
+ int in;
+} anon_union;
+
+enum colors {
+ RED,
+ GREEN,
+ BLUE
+} new_enum;
+
+
+int *pointer;
+
+BEGIN
+{
+ printf("sizeof (new_char): %d\n", sizeof (new_char));
+ printf("sizeof (new_short): %d\n", sizeof (new_short));
+ printf("sizeof (new_int): %d\n", sizeof (new_int));
+ printf("sizeof (new_long): %d\n", sizeof (new_long));
+ printf("sizeof (new_long_long): %d\n", sizeof (new_long_long));
+ printf("sizeof (new_int8): %d\n", sizeof (new_int8));
+ printf("sizeof (new_int16): %d\n", sizeof (new_int16));
+ printf("sizeof (new_int32): %d\n", sizeof (new_int32));
+ printf("sizeof (new_int64): %d\n", sizeof (new_int64));
+ printf("sizeof (pointer): %d\n", sizeof (pointer));
+ printf("sizeof (intptr_t): %d\n", sizeof (intptr_t));
+ printf("sizeof (new_struct): %d\n", sizeof (new_struct));
+ printf("sizeof (anon_struct): %d\n", sizeof (anon_struct));
+ printf("sizeof (new_union): %d\n", sizeof (new_union));
+ printf("sizeof (anon_union): %d\n", sizeof (anon_union));
+ printf("sizeof (new_enum): %d\n", sizeof (new_enum));
+ exit(0);
+}
+
+END
+/(1 != sizeof (new_char)) || (2 != sizeof (new_short)) ||
+ (4 != sizeof (new_int)) ||
+ ((4 != sizeof (new_long)) && (8 != sizeof (new_long))) ||
+ (8 != sizeof (new_long_long)) ||
+ (1 != sizeof (new_int8)) || (2 != sizeof (new_int16)) ||
+ (4 != sizeof (new_int32)) || (8 != sizeof (new_int64)) ||
+ (sizeof (pointer) != sizeof (new_intptr)) || (8 != sizeof (new_struct)) ||
+ (4 != sizeof (new_union)) || (4 != sizeof (new_enum))/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofExpression.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofExpression.d
new file mode 100644
index 000000000000..0bb7f686eec2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofExpression.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the use of sizeof with expressions.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("sizeof ('c') : %d\n", sizeof ('c'));
+ printf("sizeof (10 * 'c') : %d\n", sizeof (10 * 'c'));
+ printf("sizeof (100 + 12345) : %d\n", sizeof (100 + 12345));
+ printf("sizeof (1234567890) : %d\n", sizeof (1234567890));
+
+ printf("sizeof (1234512345 * 1234512345 * 12345678 * 1ULL) : %d\n",
+ sizeof (1234512345 * 1234512345 * 12345678 * 1ULL));
+ printf("sizeof (-129) : %d\n", sizeof (-129));
+ printf("sizeof (0x67890/0x77000) : %d\n", sizeof (0x67890/0x77000));
+
+ printf("sizeof (3 > 2 ? 3 : 2) : %d\n", sizeof (3 > 2 ? 3 : 2));
+
+ exit(0);
+}
+
+END
+/(4 != sizeof ('c')) || (4 != sizeof (10 * 'c')) ||
+ (4 != sizeof (100 + 12345)) || (4 != sizeof (1234567890)) ||
+ (8 != sizeof (1234512345 * 1234512345 * 12345678 * 1ULL)) ||
+ (4 != sizeof (-129)) || (4 != sizeof (0x67890/0x77000)) ||
+ (4 != sizeof (3 > 2 ? 3 : 2))/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofNULL.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofNULL.d
new file mode 100644
index 000000000000..4bd8a48421a8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofNULL.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: The size of the inbuilt variable NULL is the same as that of an
+ * integer.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ printf("sizeof (NULL): %d\n", sizeof (NULL));
+ exit(0);
+}
+
+END
+/4 != sizeof (NULL)/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofStrConst.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofStrConst.d
new file mode 100644
index 000000000000..51f72505a2da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofStrConst.d
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: sizeof returns the size in bytes of any D expression or data
+ * type. When a raw string is passed to the sizeof operator, the compiler
+ * throws a D_SYNTAX error.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ printf("sizeof \"hi\": %d\n", sizeof ("hi"));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofStrConst.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofStrConst.d.out
new file mode 100644
index 000000000000..3fe02aafb04a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofStrConst.d.out
@@ -0,0 +1,2 @@
+sizeof "hi": 3
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString1.d
new file mode 100644
index 000000000000..0be9e45793ef
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString1.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: sizeof returns the size in bytes of any D expression or data
+ * type. For sizeof strings the D compiler throws D_SIZEOF_TYPE.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ */
+#pragma D option quiet
+#pragma D option strsize=256
+
+BEGIN
+{
+ assoc_array["hello"] = "hello";
+ assoc_array["hi"] = "hi";
+ assoc_array["hello"] = "hello, world";
+
+ printf("sizeof (assoc_array[\"hello\"]): %d\n",
+ sizeof (assoc_array["hello"]));
+ printf("sizeof (assoc_array[\"hi\"]): %d\n",
+ sizeof (assoc_array["hi"]));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString1.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString1.d.out
new file mode 100644
index 000000000000..9c43b1e3064b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString1.d.out
@@ -0,0 +1,3 @@
+sizeof (assoc_array["hello"]): 256
+sizeof (assoc_array["hi"]): 256
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString2.d
new file mode 100644
index 000000000000..f12a6003affc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString2.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: sizeof returns the size in bytes of any D expression or data
+ * type. For a string variable, the D compiler throws a D_SIZEOF_TYPE.
+ *
+ * SECTION: Structs and Unions/Member Sizes and Offsets
+ *
+ */
+#pragma D option quiet
+#pragma D option strsize=256
+
+BEGIN
+{
+ var = "hello";
+ printf("sizeof (var): %d\n", sizeof (var));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString2.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString2.d.out
new file mode 100644
index 000000000000..fdeca6991289
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sizeof/tst.SizeofString2.d.out
@@ -0,0 +1,2 @@
+sizeof (var): 256
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/bug.1001148.SpecSizeVariations.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/bug.1001148.SpecSizeVariations.d
new file mode 100644
index 000000000000..318a2d052fab
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/bug.1001148.SpecSizeVariations.d
@@ -0,0 +1,87 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify the behavior of variations in specsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/specsize
+ *
+ * BUG: 1001148
+ *
+ * NOTES: This code has four different behaviors.
+ * 1. 0 < specsize < 8
+ * 2. 8 <= specsize <= 39 || 0 == specsize
+ * 3. 40 <= specsize
+ * 4. 0 > specsize
+ *
+ */
+
+#pragma D option quiet
+#pragma D option specsize=10
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(0);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations1.d
new file mode 100644
index 000000000000..c59ea3bee57d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations1.d
@@ -0,0 +1,84 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+
+/*
+ * ASSERTION:
+ * Verify the behavior of variations in bufsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/bufsize
+ *
+ * NOTES: This test behaves differently depending on the values
+ * assigned to bufsize.
+ */
+
+#pragma D option quiet
+#pragma D option bufsize=49
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(0);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations2.d
new file mode 100644
index 000000000000..5ac7957ced85
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations2.d
@@ -0,0 +1,90 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * Verify the behavior of variations in bufsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/bufsize
+ *
+ * NOTES: This test behaves differently depending on the values
+ * assigned to bufsize.
+ * 1. 0 > bufsize.
+ * 2. 0 == bufsize.
+ * 3. 0 < bufsize <= 7
+ * 4. 8 <= bufsize <= 31
+ * 5. 32 <= bufsize <= 47
+ * 6. 48 <= bufsize <= 71
+ * 7. 72 <= bufsize
+ */
+
+#pragma D option quiet
+#pragma D option bufsize=4
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(0);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithBreakPoint.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithBreakPoint.d
new file mode 100644
index 000000000000..958ce68612a1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithBreakPoint.d
@@ -0,0 +1,69 @@
+#!/usr/sbin/dtrace -ws
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Destructive actions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ * SECTION: dtrace(1M) Utility/ -w option
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+syscall:::
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ breakpoint();
+ i++;
+}
+
+syscall:::
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithChill.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithChill.d
new file mode 100644
index 000000000000..ebb3b016019d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithChill.d
@@ -0,0 +1,69 @@
+#!/usr/sbin/dtrace -ws
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Destructive actions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ * SECTION: dtrace (1M) Utility/ -w option
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ chill(10);
+ i++;
+}
+
+profile:::tick-1sec
+/1 == 1/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithCopyOut.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithCopyOut.d
new file mode 100644
index 000000000000..9c14bb5a5956
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithCopyOut.d
@@ -0,0 +1,69 @@
+#!/usr/sbin/dtrace -ws
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Destructive actions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ * SECTION: dtrace(1M) Utility/ -w option
+ *
+ */
+#pragma D option quiet
+
+char a[2];
+void *buf;
+uintptr_t addr;
+size_t nbytes;
+BEGIN
+{
+ self->i = 0;
+ addr = (uintptr_t) &a[0];
+ nbytes = 10;
+ var = speculation();
+}
+
+BEGIN
+{
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ self->i++;
+ copyout(buf, addr, nbytes);
+}
+
+BEGIN
+{
+ printf("This test should not have compiled\n");
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithCopyOutStr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithCopyOutStr.d
new file mode 100644
index 000000000000..695eb8c8dea4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithCopyOutStr.d
@@ -0,0 +1,68 @@
+#!/usr/sbin/dtrace -ws
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Destructive actions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ * SECTION: dtrace(1M) Utility/ -w option
+ */
+#pragma D option quiet
+
+string str;
+char a[2];
+uintptr_t addr;
+size_t maxlen;
+BEGIN
+{
+ self->i = 0;
+ addr = (uintptr_t) &a[0];
+ maxlen = 10;
+ var = speculation();
+}
+
+BEGIN
+{
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ self->i++;
+ copyoutstr(str, addr, maxlen);
+}
+
+BEGIN
+{
+ printf("This test should not have compiled\n");
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithPanic.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithPanic.d
new file mode 100644
index 000000000000..dcba0801946e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithPanic.d
@@ -0,0 +1,69 @@
+#!/usr/sbin/dtrace -ws
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Destructive actions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ * SECTION: dtrace(1M) Utility/ -w option
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ panic();
+ i++;
+}
+
+profile:::tick-1sec
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithRaise.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithRaise.d
new file mode 100644
index 000000000000..e4fe06b6a3b8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithRaise.d
@@ -0,0 +1,68 @@
+#!/usr/sbin/dtrace -ws
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Destructive actions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ * SECTION: dtrace(1M) Utility/ -w option
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ raise(9);
+ i++;
+}
+
+profile:::tick-1sec
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithStop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithStop.d
new file mode 100644
index 000000000000..468e8f20e2e4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithStop.d
@@ -0,0 +1,68 @@
+#!/usr/sbin/dtrace -ws
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Destructive actions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ * SECTION: dtrace(1M) Utility/ -w option
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ stop();
+ i++;
+}
+
+profile:::tick-1sec
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_COMM.AggAftCommit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_COMM.AggAftCommit.d
new file mode 100644
index 000000000000..89a15c032dad
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_COMM.AggAftCommit.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * A clause cannot contain a commit() followed by an aggregating action.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation;
+ */
+
+BEGIN
+{
+ commit(1);
+ @a["foo"] = count();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithAvg.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithAvg.d
new file mode 100644
index 000000000000..a763543428bc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithAvg.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Aggregating actions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ @avrg["speculate"] = avg(i);
+ i++;
+}
+
+profile:::tick-1sec
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithCount.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithCount.d
new file mode 100644
index 000000000000..57d0d03c5437
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithCount.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Aggregating functions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ @counts["speculate"] = count();
+ i++;
+}
+
+profile:::tick-1sec
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithLquant.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithLquant.d
new file mode 100644
index 000000000000..90a899d251ce
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithLquant.d
@@ -0,0 +1,72 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Aggregating functions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+syscall:::entry
+{
+ self->ts = timestamp;
+}
+
+syscall:::return
+/self->ts/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ @Lqauntus[execname] = lquantize(timestamp - self->ts, 0, 100, 1);
+ i++;
+}
+
+syscall:::
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithMax.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithMax.d
new file mode 100644
index 000000000000..a10fff1bb3fd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithMax.d
@@ -0,0 +1,62 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Aggregating functions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ @Maximus["speculate"] = max(i);
+ i++;
+}
+
+profile:::tick-1sec
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithMin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithMin.d
new file mode 100644
index 000000000000..4ad8dee33c63
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithMin.d
@@ -0,0 +1,62 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Aggregating functions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ @Minimus["speculate"] = min(i);
+ i++;
+}
+
+profile:::tick-1sec
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithQuant.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithQuant.d
new file mode 100644
index 000000000000..38e816ec2ce6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithQuant.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Aggregating functions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+syscall:::entry
+{
+ self->ts = timestamp;
+}
+
+syscall:::return
+/self->ts/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ @Qauntus[execname] = quantize(timestamp - self->ts);
+ i++;
+}
+
+syscall:::
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithStddev.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithStddev.d
new file mode 100644
index 000000000000..22953c2a55f4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithStddev.d
@@ -0,0 +1,65 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Aggregating actions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ @sdev["speculate"] = stddev(i);
+ i++;
+}
+
+profile:::tick-1sec
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithSum.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithSum.d
new file mode 100644
index 000000000000..620a0768d0e5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_AGG_SPEC.SpeculateWithSum.d
@@ -0,0 +1,62 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Aggregating functions may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+profile:::tick-1sec
+/i < 1/
+{
+ var = speculation();
+ speculate(var);
+ printf("Speculation ID: %d", var);
+ @sums["speculate"] = sum(i);
+ i++;
+}
+
+profile:::tick-1sec
+/1 == i/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_COMM.CommitAftCommit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_COMM.CommitAftCommit.d
new file mode 100644
index 000000000000..ebc316a9fe99
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_COMM.CommitAftCommit.d
@@ -0,0 +1,82 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * A clause cannot contain multiple commit() calls to same buffer.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation;
+ * Options and Tunables/cleanrate
+ */
+#pragma D option quiet
+#pragma D option cleanrate=3000hz
+
+BEGIN
+{
+ self->i = 0;
+ var1 = 0;
+}
+
+profile:::tick-1sec
+/!var1/
+{
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+}
+
+profile:::tick-1sec
+/var1/
+{
+ speculate(var1);
+ printf("Speculating on id: %d\n", var1);
+ self->i++;
+}
+
+profile:::tick-1sec
+/(!self->i)/
+{
+}
+
+profile:::tick-1sec
+/(self->i)/
+{
+ commit(var1);
+ commit(var1);
+ exit(0);
+}
+
+END
+{
+ printf("Succesfully commited both buffers");
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_COMM.DisjointCommit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_COMM.DisjointCommit.d
new file mode 100644
index 000000000000..e482d07ee47e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_COMM.DisjointCommit.d
@@ -0,0 +1,102 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * A clause cannot contain multiple commit() calls to disjoint buffers.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation;
+ * Options and Tunables/cleanrate
+ */
+#pragma D option quiet
+#pragma D option cleanrate=3000hz
+
+BEGIN
+{
+ self->i = 0;
+ self->j = 0;
+ self->commit = 0;
+ var1 = 0;
+ var2 = 0;
+}
+
+BEGIN
+{
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+}
+
+BEGIN
+{
+ var2 = speculation();
+ printf("Speculation ID: %d\n", var2);
+}
+
+BEGIN
+/var1/
+{
+ speculate(var1);
+ printf("Speculating on id: %d\n", var1);
+ self->i++;
+}
+
+BEGIN
+/var2/
+{
+ speculate(var2);
+ printf("Speculating on id: %d", var2);
+ self->j++;
+
+}
+
+BEGIN
+/(self->i) && (self->j)/
+{
+ commit(var1);
+ commit(var2);
+ self->commit++;
+}
+
+BEGIN
+/self->commit/
+{
+ printf("Succesfully commited both buffers");
+ exit(0);
+}
+
+BEGIN
+/!self->commit/
+{
+ printf("Couldnt commit both buffers");
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_DREC.CommitAftDataRec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_DREC.CommitAftDataRec.d
new file mode 100644
index 000000000000..268b68fbb98c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_COMM_DREC.CommitAftDataRec.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Commit may not follow data recording actions.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+ exit(0);
+}
+
+END
+{
+ printf("This test shouldnt have compiled\n");
+ commit(self->spec);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_DREC_COMM.DataRecAftCommit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_DREC_COMM.DataRecAftCommit.d
new file mode 100644
index 000000000000..75560d831759
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_DREC_COMM.DataRecAftCommit.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Data recording actions may not follow commit.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation;
+ * Options and Tunables/cleanrate
+ *
+ */
+#pragma D option quiet
+#pragma D option cleanrate=2000hz
+
+BEGIN
+{
+ self->speculateFlag = 0;
+}
+
+syscall:::entry
+{
+ self->spec = speculation();
+}
+
+syscall:::
+/self->spec/
+{
+ speculate(self->spec);
+ printf("Called speculate with id: %d\n", self->spec);
+ self->speculateFlag++;
+}
+
+syscall:::
+/(self->spec) && (self->speculateFlag)/
+{
+ commit(self->spec);
+ printf("Data recording after commit\n");
+}
+
+END
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_DREC_COMM.ExitAfterCommit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_DREC_COMM.ExitAfterCommit.d
new file mode 100644
index 000000000000..c190740bf787
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_DREC_COMM.ExitAfterCommit.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Exit after commit should throw a D_DREC_COMM.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ self->i = 0;
+ self->spec = speculation();
+}
+
+BEGIN
+/self->spec/
+{
+ speculate(self->spec);
+ self->i++;
+ printf("self->i: %d\n", self->i);
+}
+
+BEGIN
+/self->i/
+{
+ commit(self->spec);
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_EXIT_SPEC.ExitAftSpec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_EXIT_SPEC.ExitAftSpec.d
new file mode 100644
index 000000000000..70964f916e26
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_EXIT_SPEC.ExitAftSpec.d
@@ -0,0 +1,70 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Exit action may never be speculative.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+BEGIN
+{
+ i = 0;
+}
+
+syscall:::entry
+{
+ self->spec = speculation();
+}
+
+syscall:::
+/self->spec/
+{
+ speculate(self->spec);
+ i++;
+ printf("i: %d\n", i);
+ exit(0);
+}
+
+syscall:::
+/1 == i/
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_MALFORM.NspecExpr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_MALFORM.NspecExpr.d
new file mode 100644
index 000000000000..91168e300826
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_MALFORM.NspecExpr.d
@@ -0,0 +1,77 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using an expression in the pragma for nspec throws a D_PRAGMA_MALFORM
+ * error.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/nspec
+ *
+ */
+
+#pragma D option quiet
+#pragma D option cleanrate=3000hz
+#pragma D option nspec=24 * 44
+
+BEGIN
+{
+ var1 = 0;
+ var2 = 0;
+ var3 = 0;
+}
+
+BEGIN
+{
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+ var2 = speculation();
+ printf("Speculation ID: %d\n", var2);
+ var3 = speculation();
+ printf("Speculation ID: %d\n", var3);
+}
+
+BEGIN
+/var1 && var2 && (!var3)/
+{
+ printf("Succesfully got two speculative buffers");
+ exit(0);
+}
+
+BEGIN
+/(!var1) || (!var2) || var3/
+{
+ printf("Test failed");
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.HugeNspecValue.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.HugeNspecValue.d
new file mode 100644
index 000000000000..d13132ef5879
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.HugeNspecValue.d
@@ -0,0 +1,76 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Setting the nspec option to a huge integer throws a D_PRAGMA_OPTSET error.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/nspec
+ *
+ */
+
+#pragma D option quiet
+#pragma D option cleanrate=3000hz
+#pragma D option nspec=245566729809009887663
+
+BEGIN
+{
+ var1 = 0;
+ var2 = 0;
+ var3 = 0;
+}
+
+BEGIN
+{
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+ var2 = speculation();
+ printf("Speculation ID: %d\n", var2);
+ var3 = speculation();
+ printf("Speculation ID: %d\n", var3);
+}
+
+BEGIN
+/var1 && var2 && (!var3)/
+{
+ printf("Succesfully got two speculative buffers");
+ exit(0);
+}
+
+BEGIN
+/(!var1) || (!var2) || var3/
+{
+ printf("Test failed");
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.InvalidSpecSize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.InvalidSpecSize.d
new file mode 100644
index 000000000000..d957f678aed1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.InvalidSpecSize.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Setting the specsize option to an illegal value throws the compiler error
+ * D_PRAGMA_OPTSET.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/specsize
+ */
+
+#pragma D option quiet
+#pragma D option specsize=1b
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+ exit(0);
+}
+
+END
+{
+ printf("This shouldnt have compiled\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.NegSpecSize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.NegSpecSize.d
new file mode 100644
index 000000000000..c5fa9f503e72
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PRAGMA_OPTSET.NegSpecSize.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * ASSERTION:
+ * Verify the behavior of speculations with changes in specsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/specsize
+ *
+ */
+
+#pragma D option quiet
+#pragma D option specsize=-40
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(0);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PROTO_LEN.SpecNoId.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PROTO_LEN.SpecNoId.d
new file mode 100644
index 000000000000..65d53ba66f66
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_PROTO_LEN.SpecNoId.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * An identifier returned from speculation must be passed to the speculate()
+ * function.
+ *
+ * SECTION: Speculative Tracing/Creating a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ var = speculation();
+ printf("Speculation ID: %d", var);
+ self->i = 0;
+}
+
+profile:::tick-1sec
+{
+ speculate();
+ self->i++;
+}
+
+profile:::tick-1sec
+/1 <= self->i/
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_COMM.SpecAftCommit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_COMM.SpecAftCommit.d
new file mode 100644
index 000000000000..ec4b22b8092f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_COMM.SpecAftCommit.d
@@ -0,0 +1,72 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * A clause cannot contain a speculate after a commit.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation;
+ * Options and Tunables/cleanrate
+ *
+ */
+#pragma D option quiet
+#pragma D option cleanrate=3000hz
+
+BEGIN
+{
+ self->i = 0;
+ var1 = 0;
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+}
+
+profile:::tick-1sec
+/var1/
+{
+ speculate(var1);
+ printf("Speculating on id: %d\n", var1);
+ self->i++;
+}
+
+profile:::tick-1sec
+/(!self->i)/
+{
+}
+
+profile:::tick-1sec
+/(self->i)/
+{
+ commit(var1);
+ speculate(var1);
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_DREC.SpecAftDataRec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_DREC.SpecAftDataRec.d
new file mode 100644
index 000000000000..80f1fdd2c131
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_DREC.SpecAftDataRec.d
@@ -0,0 +1,70 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * speculate() may not follow data recording actions.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+BEGIN
+{
+ i = 0;
+}
+
+syscall:::entry
+{
+ self->spec = speculation();
+}
+
+syscall:::
+/self->spec/
+{
+ printf("Entering syscall clause\n");
+ speculate(self->spec);
+ i++;
+ printf("i: %d\n", i);
+}
+
+syscall:::
+/1 == i/
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_SPEC.SpecAftSpec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_SPEC.SpecAftSpec.d
new file mode 100644
index 000000000000..67af53b976a6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.D_SPEC_SPEC.SpecAftSpec.d
@@ -0,0 +1,66 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * A clause can contain only one speculate() call.
+ *
+ * SECTION: Speculative Tracing/Using a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ self->i = 0;
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+ var2 = speculation();
+ printf("Speculation ID: %d\n", var2);
+}
+
+profile:::tick-1sec
+{
+ speculate(var1);
+ printf("Speculating on id: %d\n", var1);
+ speculate(var2);
+ printf("Speculating on id: %d", var2);
+ self->i++;
+
+}
+
+profile:::tick-1sec
+/1 > self->i/
+{
+ exit(0);
+}
+
+END
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeBufSize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeBufSize.d
new file mode 100644
index 000000000000..7d2f4b36b9f2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeBufSize.d
@@ -0,0 +1,88 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify the behavior of variations in bufsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/bufsize
+ *
+ * NOTES: This test behaves differently depending on the values
+ * assigned to bufsize.
+ * 1. 0 > bufsize.
+ * 2. 0 == bufsize.
+ * 3. 0 < bufsize <= 7
+ * 4. 8 <= bufsize <= 31
+ * 5. 32 <= bufsize <= 47
+ * 6. 48 <= bufsize <= 71
+ * 7. 72 <= bufsize
+ */
+
+#pragma D option quiet
+#pragma D option bufsize=-72
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(0);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeNspec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeNspec.d
new file mode 100644
index 000000000000..9e1d063d51ad
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeNspec.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using a negative value for nspec throws a compiler error.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/nspec
+ */
+
+#pragma D option quiet
+#pragma D option nspec=-72
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+ printf("This test shouldnt have compiled\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeSpecSize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeSpecSize.d
new file mode 100644
index 000000000000..233257a444d8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.NegativeSpecSize.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Setting the specsize to a negative number should throw a compiler error.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/specsize
+ *
+ * NOTES: Why dont we have an error tag for this error?
+ */
+
+#pragma D option quiet
+#pragma D option specsize=-10
+
+BEGIN
+{
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.SpecSizeVariations1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.SpecSizeVariations1.d
new file mode 100644
index 000000000000..c42029c3f3c8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.SpecSizeVariations1.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * ASSERTION:
+ * Verify the behavior of variations in specsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/specsize
+ *
+ */
+
+#pragma D option quiet
+#pragma D option specsize=2
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(0);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.SpecSizeVariations2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.SpecSizeVariations2.d
new file mode 100644
index 000000000000..8a57280734fb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/err.SpecSizeVariations2.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * ASSERTION:
+ * Verify the behavior of variations in specsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/specsize
+ *
+ */
+
+#pragma D option quiet
+#pragma D option specsize=0
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(0);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.CommitAfterDiscard.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.CommitAfterDiscard.d
new file mode 100644
index 000000000000..a874ab5b5590
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.CommitAfterDiscard.d
@@ -0,0 +1,86 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Call to commit() on a buffer after it has been discarded is silently
+ * ignored.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation;
+ * Options and Tunables/cleanrate
+ *
+ */
+#pragma D option quiet
+#pragma D option cleanrate=3000hz
+
+BEGIN
+{
+ self->i = 0;
+ self->commit = 0;
+ self->discard = 0;
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+}
+
+BEGIN
+/var1/
+{
+ speculate(var1);
+ printf("This statement and the following are speculative!!\n");
+ printf("Speculating on id: %d\n", var1);
+ self->i++;
+}
+
+BEGIN
+/(self->i)/
+{
+ discard(var1);
+ self->discard++;
+ commit(var1);
+ self->commit++;
+}
+
+BEGIN
+/self->commit/
+{
+ printf("Commited a discarded buffer\n");
+ exit(0);
+}
+
+
+BEGIN
+/!self->commit/
+{
+ printf("Couldnt commit a discarded buffer\n");
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.CommitWithZero.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.CommitWithZero.d
new file mode 100644
index 000000000000..647552fbbfde
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.CommitWithZero.d
@@ -0,0 +1,66 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: An Id of zero though invalid may be passed to speculate(),
+ * commit() and discard() without any ill effects.
+ *
+ * SECTION: Speculative Tracing/Creating a Speculation;
+ * Options and Tunables/cleanrate
+ */
+#pragma D option quiet
+#pragma D option cleanrate=4000hz
+
+BEGIN
+{
+ self->commitFlag = 0;
+ self->var1 = speculation();
+ printf("Speculative buffer ID: %d\n", self->var1);
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/0 < self->commitFlag/
+{
+ printf("commit(), self->commitFlag = %d\n", self->commitFlag);
+ exit(0);
+}
+
+BEGIN
+/0 == self->commitFlag/
+{
+ printf("commit(), self->commitFlag = %d\n", self->commitFlag);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DataRecAftDiscard.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DataRecAftDiscard.d
new file mode 100644
index 000000000000..03ae1b5ff1de
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DataRecAftDiscard.d
@@ -0,0 +1,77 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Data recording actions may follow discard.
+ *
+ * SECTION: Speculative Tracing/Discarding a Speculation;
+ * Options and Tunables/cleanrate
+ */
+#pragma D option quiet
+#pragma D option cleanrate=2000hz
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->discardFlag = 0;
+ self->spec = speculation();
+}
+
+BEGIN
+/self->spec/
+{
+ speculate(self->spec);
+ printf("Called speculate with id: %d\n", self->spec);
+ self->speculateFlag++;
+}
+
+BEGIN
+/(self->spec) && (self->speculateFlag)/
+{
+ discard(self->spec);
+ self->discardFlag++;
+ printf("Data recording after discard\n");
+}
+
+BEGIN
+/self->discardFlag/
+{
+ exit(0);
+}
+
+BEGIN
+/!self->discardFlag/
+{
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftCommit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftCommit.d
new file mode 100644
index 000000000000..25fcfc542a7b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftCommit.d
@@ -0,0 +1,85 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Can call discard() on a buffer after it has been commited.
+ *
+ * SECTION: Speculative Tracing/Discarding a Speculation;
+ * Options and Tunables/cleanrate
+ *
+ */
+#pragma D option quiet
+#pragma D option cleanrate=3000hz
+
+BEGIN
+{
+ self->i = 0;
+ self->commit = 0;
+ self->discard = 0;
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+}
+
+BEGIN
+/var1/
+{
+ speculate(var1);
+ printf("This statement and the following are speculative!!\n");
+ printf("Speculating on id: %d\n", var1);
+ self->i++;
+}
+
+BEGIN
+/(self->i)/
+{
+ commit(var1);
+ self->commit++;
+ discard(var1);
+ self->discard++;
+}
+
+BEGIN
+/self->discard/
+{
+ printf("Discarded a commited buffer\n");
+ exit(0);
+}
+
+
+BEGIN
+/!self->discard/
+{
+ printf("Couldnt discard a commited buffer\n");
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftDataRec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftDataRec.d
new file mode 100644
index 000000000000..d5c573f9032e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftDataRec.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Discard may not follow data recording actions.
+ *
+ * SECTION: Speculative Tracing/Discarding a Speculation
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ printf("Can have data recording before discarding\n");
+ discard(self->spec);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftDiscard.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftDiscard.d
new file mode 100644
index 000000000000..8c95cee748f5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardAftDiscard.d
@@ -0,0 +1,85 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Can call discard on an already discarded buffer.
+ *
+ * SECTION: Speculative Tracing/Discarding a Speculation;
+ * Options and Tunables/cleanrate
+ *
+ */
+#pragma D option quiet
+#pragma D option cleanrate=3000hz
+
+BEGIN
+{
+ self->i = 0;
+ self->discard1 = 0;
+ self->discard2 = 0;
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+}
+
+BEGIN
+/var1/
+{
+ speculate(var1);
+ printf("This statement and the following are speculative!!\n");
+ printf("Speculating on id: %d\n", var1);
+ self->i++;
+}
+
+BEGIN
+/(self->i)/
+{
+ discard(var1);
+ self->discard1++;
+ discard(var1);
+ self->discard2++;
+}
+
+BEGIN
+/(self->discard2) && (self->discard1)/
+{
+ printf("Discarded a discarded buffer\n");
+ exit(0);
+}
+
+
+BEGIN
+/(!self->discard2) || (!self->discard1)/
+{
+ printf("Couldnt discard a discarded buffer\n");
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardWithZero.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardWithZero.d
new file mode 100644
index 000000000000..1a7856137825
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.DiscardWithZero.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: An Id of zero though invalid may be passed to speculate(),
+ * commit() and discard() without any ill effects.
+ *
+ * SECTION: Speculative Tracing/Creating a Speculation;
+ * Options and Tunables/cleanrate
+ */
+#pragma D option quiet
+#pragma D option cleanrate=4000hz
+
+BEGIN
+{
+ self->discardFlag = 0;
+ self->var1 = speculation();
+ printf("Speculative buffer ID: %d\n", self->var1);
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+/0 == self->spec/
+{
+ discard(self->spec);
+ self->discardFlag++;
+}
+
+BEGIN
+/0 < self->discardFlag/
+{
+ printf("discard(), self->discardFlag = %d\n", self->discardFlag);
+ exit(0);
+}
+
+BEGIN
+/0 == self->discardFlag/
+{
+ printf("discard(), self->discardFlag = %d\n", self->discardFlag);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.ExitAftDiscard.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.ExitAftDiscard.d
new file mode 100644
index 000000000000..f5bcd6624f19
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.ExitAftDiscard.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Using exit after discard should work fine.
+ *
+ * SECTION: Speculative Tracing/Discarding a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ self->i = 0;
+ self->spec = speculation();
+}
+
+BEGIN
+/self->spec/
+{
+ speculate(self->spec);
+ self->i++;
+ printf("self->i: %d\n", self->i);
+}
+
+BEGIN
+/self->i/
+{
+ discard(self->spec);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.NoSpecBuffer.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.NoSpecBuffer.d
new file mode 100644
index 000000000000..879ac46e0806
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.NoSpecBuffer.d
@@ -0,0 +1,65 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * The number of speculative buffers defaults to one. If no speculative buffer
+ * is available when speculation is called, an ID of zero is returned.
+ *
+ * SECTION: Speculative Tracing/Creating a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+ notused = $1;
+}
+
+syscall::open:entry
+/i < 2/
+{
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+ i++;
+}
+
+syscall:::
+/(2 == i) && (0 == self->spec)/
+{
+ printf("i: %d\tself->spec: %d", i, self->spec);
+ exit(0);
+}
+
+syscall:::
+/(2 == i) && (0 != self->spec)/
+{
+ printf("i: %d\tself->spec: %d", i, self->spec);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.NoSpecBuffer.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.NoSpecBuffer.exe
new file mode 100644
index 000000000000..5acce76efc6c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.NoSpecBuffer.exe
@@ -0,0 +1,30 @@
+#!/usr/bin/env ksh
+#
+# 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 2017 Li-Wen Hsu <lwhsu@FreeBSD.org>
+
+while true
+do
+ sleep 0.1
+ cat /COPYRIGHT > /dev/null
+done
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations1.d
new file mode 100644
index 000000000000..17df6b548434
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations1.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * ASSERTION:
+ * Verify the behavior of speculations with changes in specsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/specsize
+ *
+ */
+
+#pragma D option quiet
+#pragma D option specsize=8
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(1);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations2.d
new file mode 100644
index 000000000000..bcd2f2ea90ca
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations2.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * ASSERTION:
+ * Verify the behavior of speculations with changes in specsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/specsize
+ *
+ */
+
+#pragma D option quiet
+#pragma D option specsize=10
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(1);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations3.d
new file mode 100644
index 000000000000..6b91efd9114b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations3.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * ASSERTION:
+ * Verify the behavior of speculations with changes in specsize.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/specsize
+ *
+ */
+
+#pragma D option quiet
+#pragma D option specsize=40
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->commitFlag = 0;
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ printf("Lots of data\n");
+ printf("Has to be crammed into this buffer\n");
+ printf("Until it overflows\n");
+ printf("And causes flops\n");
+ self->speculateFlag++;
+
+}
+
+BEGIN
+/1 <= self->speculateFlag/
+{
+ commit(self->spec);
+ self->commitFlag++;
+}
+
+BEGIN
+/1 <= self->commitFlag/
+{
+ printf("Statement was executed\n");
+ exit(0);
+}
+
+BEGIN
+/1 > self->commitFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculateWithRandom.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculateWithRandom.d
new file mode 100644
index 000000000000..24f1ff4b4fbd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculateWithRandom.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * When speculate() is called with an inactive buffer number, it is
+ * ignored.
+ *
+ * SECTION: Speculative Tracing/Creating a Speculation
+ *
+ */
+#pragma D option quiet
+BEGIN
+{
+ self->i = 0;
+}
+
+BEGIN
+{
+ speculate(3456710);
+ self->i++;
+ printf("self->i: %d\n", self->i);
+
+}
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationCommit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationCommit.d
new file mode 100644
index 000000000000..744ba676645c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationCommit.d
@@ -0,0 +1,75 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test the normal behavior of speculate() and commit().
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation;
+ * Actions and Subroutines/speculation();
+ * Options and Tunables/cleanrate
+ *
+ */
+#pragma D option quiet
+#pragma D option cleanrate=2000hz
+
+BEGIN
+{
+ self->var = speculation();
+ printf("Speculation ID: %d\n", self->var);
+ self->speculate = 0;
+ self->commit = 0;
+}
+
+BEGIN
+/1 > self->speculate/
+{
+ speculate(self->var);
+ self->speculate++;
+ printf("Called speculate on id: %d\n", self->var);
+}
+
+BEGIN
+/1 <= self->speculate/
+{
+ commit(self->var);
+ self->commit++;
+}
+
+BEGIN
+/(1 == self->commit)/
+{
+ printf("Succesfully tested buffer commit\n");
+ exit(0);
+}
+
+BEGIN
+/(0 == self->commit)/
+{
+ printf("Failed to commit buffer\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationDiscard.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationDiscard.d
new file mode 100644
index 000000000000..4ac0e236d13f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationDiscard.d
@@ -0,0 +1,74 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Test the normal behavior of speculate() and discard().
+ *
+ * SECTION: Speculative Tracing/Discarding a Speculation;
+ * Options and Tunables/cleanrate
+ *
+ */
+#pragma D option quiet
+#pragma D option cleanrate=2000hz
+
+BEGIN
+{
+ self->var = speculation();
+ printf("Speculation ID: %d\n", self->var);
+ self->speculate = 0;
+ self->discard = 0;
+}
+
+BEGIN
+/1 > self->speculate/
+{
+ speculate(self->var);
+ self->speculate++;
+ printf("Called speculate on id: %d\n", self->var);
+}
+
+BEGIN
+/1 <= self->speculate/
+{
+ discard(self->var);
+ self->discard++;
+}
+
+BEGIN
+/(1 == self->discard)/
+{
+ printf("Succesfully tested buffer discard\n");
+ exit(0);
+}
+
+BEGIN
+/(0 == self->discard)/
+{
+ printf("Failed to discard buffer\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationID.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationID.d
new file mode 100644
index 000000000000..b2e3678a1143
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationID.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * The speculation() function returns a speculative identifier when a
+ * speculative buffer is available.
+ *
+ * SECTION: Speculative Tracing/Creating a Speculation
+ *
+ */
+#pragma D option quiet
+
+BEGIN
+{
+ var = speculation();
+ printf("Speculation ID: %d", var);
+ exit(0);
+}
+
+END
+/0 == var/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationWithZero.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationWithZero.d
new file mode 100644
index 000000000000..76600dbaf93a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.SpeculationWithZero.d
@@ -0,0 +1,65 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Calling speculate() with zero does not have any ill effects.
+ * Statement after speculate does not execute.
+ *
+ * SECTION: Speculative Tracing/Creating a Speculation
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ self->speculateFlag = 0;
+ self->spec = speculation();
+ self->spec = speculation();
+ printf("Speculative buffer ID: %d\n", self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+ self->speculateFlag++;
+}
+
+BEGIN
+/1 == self->speculateFlag/
+{
+ printf("Statement was executed\n");
+ exit(1);
+}
+
+BEGIN
+/1 != self->speculateFlag/
+{
+ printf("Statement wasn't executed\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.TwoSpecBuffers.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.TwoSpecBuffers.d
new file mode 100644
index 000000000000..8016b200c500
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.TwoSpecBuffers.d
@@ -0,0 +1,77 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Increasing the value of nspec to two should will increase the number of
+ * speculative buffers to two.
+ *
+ * SECTION: Speculative Tracing/Options and Tuning;
+ * Options and Tunables/nspec
+ *
+ */
+
+#pragma D option quiet
+#pragma D option cleanrate=3000hz
+#pragma D option nspec=2
+
+BEGIN
+{
+ var1 = 0;
+ var2 = 0;
+ var3 = 0;
+}
+
+BEGIN
+{
+ var1 = speculation();
+ printf("Speculation ID: %d\n", var1);
+ var2 = speculation();
+ printf("Speculation ID: %d\n", var2);
+ var3 = speculation();
+ printf("Speculation ID: %d\n", var3);
+}
+
+BEGIN
+/var1 && var2 && (!var3)/
+{
+ printf("Succesfully got two speculative buffers");
+ exit(0);
+}
+
+BEGIN
+/(!var1) || (!var2) || var3/
+{
+ printf("Test failed");
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.negcommit.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.negcommit.d
new file mode 100644
index 000000000000..cf17c71ee063
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.negcommit.d
@@ -0,0 +1,37 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ commit(-1);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.negspec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.negspec.d
new file mode 100644
index 000000000000..72965c7d13d6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.negspec.d
@@ -0,0 +1,37 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+BEGIN
+{
+ speculate(-1);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.zerosize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.zerosize.d
new file mode 100644
index 000000000000..a4b40014e0fd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/speculation/tst.zerosize.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option destructive
+
+BEGIN
+{
+ self->spec = speculation();
+ speculate(self->spec);
+}
+
+BEGIN
+{
+ this->one = 1;
+ this->two = 2;
+ chill(1);
+ speculate(self->spec);
+}
+
+BEGIN
+{
+ speculate(self->spec);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stability/err.D_ATTR_MIN.MinAttributes.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stability/err.D_ATTR_MIN.MinAttributes.d
new file mode 100644
index 000000000000..99fcede74972
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stability/err.D_ATTR_MIN.MinAttributes.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: If a program has a set of attributes less than the predefined
+ * minimum a D_ATTR_MIN is thrown
+ *
+ * SECTION: Stability/Stability Enforcement
+ * SECTION: Errtags/D_ATTR_MIN
+ *
+ */
+
+#pragma D option quiet
+#pragma D option amin=Evolving/Evolving/Common
+
+BEGIN
+{
+ trace(curthread->t_procp);
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_STACK_PROTO.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_STACK_PROTO.bad.d
new file mode 100644
index 000000000000..0af06e6c6344
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_STACK_PROTO.bad.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * stack() accepts one argument
+ *
+ * SECTION: Actions and Subroutines/stack()
+ *
+ */
+
+
+BEGIN
+{
+ stack(1, 2);
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_STACK_SIZE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_STACK_SIZE.d
new file mode 100644
index 000000000000..8344e5c2b708
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_STACK_SIZE.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test stack() with an invalid argument.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ stack("i'm not an integer constant");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_FRAMES.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_FRAMES.bad.d
new file mode 100644
index 000000000000..bfd7376362fb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_FRAMES.bad.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * ustack() first argument must be a non-zero positive integer constant
+ *
+ * SECTION: User Process Tracing/ustack();
+ * Actions and Subroutines/ustack()
+ *
+ */
+
+
+BEGIN
+{
+ ustack(0, 200);
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_PROTO.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_PROTO.bad.d
new file mode 100644
index 000000000000..5360d982dcb1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_PROTO.bad.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * ustack() accepts two arguments
+ *
+ * SECTION: User Process Tracing/ustack();
+ * Actions and Subroutines/ustack()
+ *
+ */
+
+
+BEGIN
+{
+ ustack(1, 10, "badarg");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_STRSIZE.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_STRSIZE.bad.d
new file mode 100644
index 000000000000..4c89ed5d1ab6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/err.D_USTACK_STRSIZE.bad.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * ustack() second argument must be a positive integer constant.
+ *
+ * SECTION: User Process Tracing/ustack();
+ * Actions and Subroutines/ustack()
+ *
+ */
+
+
+BEGIN
+{
+ ustack(1, "badarg");
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/tst.default.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/tst.default.d
new file mode 100644
index 000000000000..f7a4f06b1bf6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stack/tst.default.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the stack action with the default stack depth.
+ *
+ * SECTION: Output Formatting/printf()
+ *
+ */
+
+BEGIN
+{
+ stack();
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stackdepth/tst.default.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stackdepth/tst.default.d
new file mode 100644
index 000000000000..c37380d53a16
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stackdepth/tst.default.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the stackdepth variable.
+ *
+ * SECTION: Variables/Built-in Variables
+ *
+ */
+
+BEGIN
+{
+ trace(stackdepth);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop1.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop1.c
new file mode 100644
index 000000000000..28ce1b87a951
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop1.c
@@ -0,0 +1,37 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+ for (;;) {
+ getpid();
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop1.d
new file mode 100644
index 000000000000..dd5a4b99844f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop1.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for stop
+ *
+ * SECTION: Actions and Subroutines/stop()
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the process to call getpid().
+ */
+ timeout = timestamp + 1000000000;
+ stopped = 0;
+}
+
+syscall::getpid:entry
+/pid == $1 && stopped == 1/
+{
+ trace("looks like it's still going");
+ exit(1);
+}
+
+syscall::getpid:entry
+/pid == $1 && stopped == 0/
+{
+ stop();
+ trace("stopped");
+ stopped = 1;
+ /*
+ * Wait for a quarter second before declaring victory.
+ */
+ timeout = timestamp + 1000000000 / 4;
+}
+
+profile:::tick-8
+/timestamp > timeout && stopped == 1/
+{
+ trace("looks like it really stopped");
+ exit(0);
+}
+
+profile:::tick-8
+/timestamp > timeout/
+{
+ trace("timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop2.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop2.c
new file mode 100644
index 000000000000..28ce1b87a951
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop2.c
@@ -0,0 +1,37 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+ for (;;) {
+ getpid();
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop2.d
new file mode 100644
index 000000000000..4c79cd8492d6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/stop/tst.stop2.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive test for stop
+ *
+ * SECTION: Actions and Subroutines/stop()
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ /*
+ * Wait no more than a second for the process to call getpid().
+ */
+ timeout = timestamp + 1000000000;
+ stopped = 0;
+}
+
+syscall::getpid:entry
+/pid == $1 && stopped == 1/
+{
+ trace("looks like it's still going");
+ exit(1);
+}
+
+syscall::getpid:return
+/pid == $1 && stopped == 0/
+{
+ stop();
+ trace("stopped");
+ stopped = 1;
+ /*
+ * Wait for a quarter second before declaring victory.
+ */
+ timeout = timestamp + 1000000000 / 4;
+}
+
+profile:::tick-8
+/timestamp > timeout && stopped == 1/
+{
+ trace("looks like it really stopped");
+ exit(0);
+}
+
+profile:::tick-8
+/timestamp > timeout/
+{
+ trace("timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strlen/tst.strlen1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strlen/tst.strlen1.d
new file mode 100644
index 000000000000..7775395b78ef
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strlen/tst.strlen1.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the strlen() subroutine.
+ *
+ * SECTION: Actions and Subroutines/strlen()
+ *
+ */
+
+BEGIN
+/strlen("I like DTrace") == 13/
+{
+ correct = 1;
+}
+
+BEGIN
+{
+ exit(correct ? 0 : 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooLarge.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooLarge.d
new file mode 100644
index 000000000000..4d6b5af75b55
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooLarge.d
@@ -0,0 +1,35 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * The largest base we will accept is Base 36 -- i.e. using all of 0-9 and
+ * A-Z as numerals.
+ *
+ * SECTION: Actions and Subroutines/strtoll()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("%d\n", strtoll("0", 37));
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooSmall.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooSmall.d
new file mode 100644
index 000000000000..de56b50e9eda
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooSmall.d
@@ -0,0 +1,34 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * The smallest base we will accept is Base 2.
+ *
+ * SECTION: Actions and Subroutines/strtoll()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("%d\n", strtoll("0", 1));
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d
new file mode 100644
index 000000000000..0b1812a53ce0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d
@@ -0,0 +1,66 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * Test the strtoll() subroutine.
+ *
+ * SECTION: Actions and Subroutines/strtoll()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+
+ /* minimum base (2) and maximum base (36): */
+ printf("%d\n", strtoll("0", 2));
+ printf("%d\n", strtoll("1", 36));
+
+ /* simple tests: */
+ printf("%d\n", strtoll("0x20", 16));
+ printf("%d\n", strtoll("-32", 10));
+ printf("%d\n", strtoll("010", 8));
+ printf("%d\n", strtoll("101010", 2));
+
+ /* INT64_MIN and INT64_MAX: */
+ printf("%d\n", strtoll("9223372036854775807"));
+ printf("%d\n", strtoll("-9223372036854775808"));
+ printf("%d\n", strtoll("0777777777777777777777", 8));
+ printf("%d\n", strtoll("-01000000000000000000000", 8));
+
+ /* wrapping: */
+ printf("%d\n", strtoll("1000000000000000000000", 8));
+ printf("%d\n", strtoll("-1000000000000000000001", 8));
+
+ /* hex without prefix: */
+ printf("%d\n", strtoll("baddcafe", 16));
+
+ /* stopping at first out-of-base character: */
+ printf("%d\n", strtoll("12j", 10));
+ printf("%d\n", strtoll("102", 2));
+
+ /* base 36: */
+ printf("%d\n", strtoll("-0DTrace4EverZ", 36));
+
+ /* base 10 is assumed: */
+ printf("%d\n", strtoll("1985"));
+ printf("%d\n", strtoll("-2012"));
+
+ /* empty string: */
+ printf("%d\n", strtoll(""));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d.out
new file mode 100644
index 000000000000..d12eb9c1973b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d.out
@@ -0,0 +1,20 @@
+0
+1
+32
+-32
+8
+42
+9223372036854775807
+-9223372036854775808
+9223372036854775807
+-9223372036854775808
+-9223372036854775808
+9223372036854775807
+3135097598
+12
+2
+-1819882045752187535
+1985
+-2012
+0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_ADDROF_VAR.StructPointer.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_ADDROF_VAR.StructPointer.d
new file mode 100644
index 000000000000..85e49fa0e2cd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_ADDROF_VAR.StructPointer.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Trying to access the members of a user defined struct by means of
+ * a pointer to it should throw a D_ADDROF_VAR compiler error.
+ *
+ * SECTION: Structs and Unions/Pointers to Structs
+ *
+ */
+
+#pragma D option quiet
+
+struct record {
+ int position;
+ int content;
+
+};
+
+struct record var;
+struct record *ptr;
+BEGIN
+{
+
+ var.position = 1;
+ var.content = 'a';
+
+ ptr = &var;
+
+ printf("ptr->position: %d\tptr->content: %c\n",
+ ptr->position, ptr->content);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_COMBO.StructWithoutColon.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_COMBO.StructWithoutColon.d
new file mode 100644
index 000000000000..004e9019bf7b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_COMBO.StructWithoutColon.d
@@ -0,0 +1,74 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Combining multiple struct definitions in a single line should throw a
+ * compiler error.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+#pragma D option quiet
+
+struct superStruct {
+ int position;
+ char content;
+}
+
+struct record {
+ int position;
+ char content;
+}
+
+
+struct pirate {
+ int position;
+ char content;
+};
+
+struct superStruct super;
+struct record rec;
+struct pirate pir;
+
+BEGIN
+{
+ rec.content = 'a';
+ rec.position = 1;
+
+ pir.content = 'b';
+ pir.position = 2;
+
+ printf(
+ "rec.content: %c\nrec.position: %d\npir.content: %c\npir.position: %d",
+ rec.content, rec.position, pir.content, pir.position);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_COMBO.StructWithoutColon1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_COMBO.StructWithoutColon1.d
new file mode 100644
index 000000000000..1c403b67d36a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_COMBO.StructWithoutColon1.d
@@ -0,0 +1,68 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Combining multiple struct definitions in a single line should throw a
+ * compiler error.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+#pragma D option quiet
+
+struct record {
+ int position;
+ char content;
+};
+
+
+struct pirate {
+ int position;
+ char content;
+}
+
+struct record rec;
+struct pirate pir;
+
+BEGIN
+{
+ rec.content = 'a';
+ rec.position = 1;
+
+ pir.content = 'b';
+ pir.position = 2;
+
+ printf(
+ "rec.content: %c\nrec.position: %d\npir.content: %c\npir.position: %d",
+ rec.content, rec.position, pir.content, pir.position);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.circular.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.circular.d
new file mode 100644
index 000000000000..dcbc8ee209e3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.circular.d
@@ -0,0 +1,66 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * A circular definition of structs (two structs defining each other as
+ * members) should throw an error at compile time.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+#pragma D option quiet
+
+
+struct record {
+ struct pirate p;
+ int position;
+ char content;
+};
+
+
+struct pirate {
+ struct record r;
+ int position;
+ char content;
+};
+
+struct record rec;
+struct pirate pir;
+
+BEGIN
+{
+ rec.position = 0;
+ rec.content = 'a';
+ printf("rec.position: %d\nrec.content: %c\n",
+ rec.position, rec.content);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.order.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.order.d
new file mode 100644
index 000000000000..932f4dc9eac7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.order.d
@@ -0,0 +1,69 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * When two struct are defined such that one of them contains the other, the
+ * inner struct has to be defined first.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+#pragma D option quiet
+
+
+struct record {
+ struct pirate p;
+ int position;
+ char content;
+};
+
+struct pirate {
+ int position;
+ char content;
+};
+
+struct record rec;
+struct pirate pir;
+
+BEGIN
+{
+ rec.content = 'y';
+ rec.position = 2;
+
+ pir.content = 'z';
+ pir.position = 26;
+
+ printf(
+ "rec.content: %c\nrec.position: %d\npir.content: %c\npir.position: %d",
+ rec.content, rec.position, pir.content, pir.position);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.order2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.order2.d
new file mode 100644
index 000000000000..807b61866902
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.order2.d
@@ -0,0 +1,108 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * When struct definitions are nested inside one another, the inner struct
+ * should be defined before the outer one can declare it as a variable.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+#pragma D option quiet
+
+struct InnerMore {
+ struct InnerMost IMost;
+ int dummy_More;
+};
+
+struct InnerMost {
+ int position;
+ char content;
+};
+
+struct Inner {
+ struct InnerMore IMore;
+ int dummy_More;
+};
+
+struct Outer {
+ struct Inner I;
+ int dummy_More;
+};
+
+struct OuterMore {
+ struct Outer O;
+ int dummy_More;
+};
+
+struct OuterMost {
+ struct OuterMore OMore;
+ int dummy_More;
+} OMost;
+
+
+BEGIN
+{
+
+ OMost.dummy_More = 0;
+ OMost.OMore.dummy_More = 1;
+ OMost.OMore.O.dummy_More = 2;
+ OMost.OMore.O.I.dummy_More = 3;
+ OMost.OMore.O.I.IMore.dummy_More = 4;
+ OMost.OMore.O.I.IMore.IMost.position = 5;
+ OMost.OMore.O.I.IMore.IMost.content = 'e';
+
+ printf("OMost.dummy_More: %d\nOMost.OMore.dummy_More: %d\n",
+ OMost.dummy_More, OMost.OMore.dummy_More);
+
+ printf("OMost.OMore.O.dummy_More: %d\nOMost.OMore.O.I.dummy_More: %d\n",
+ OMost.OMore.O.dummy_More, OMost.OMore.O.I.dummy_More);
+
+ printf("OMost.OMore.O.I.IMore.dummy_More:%d\n",
+ OMost.OMore.O.I.IMore.dummy_More);
+
+ printf("OMost.OMore.O.I.IMore.IMost.position: %d\n",
+ OMost.OMore.O.I.IMore.IMost.position);
+
+ printf("OMost.OMore.O.I.IMore.IMost.content: %c\n",
+ OMost.OMore.O.I.IMore.IMost.content);
+
+ exit(0);
+}
+
+END
+/(0 != OMost.dummy_More) || (1 != OMost.OMore.dummy_More)
+ (2 != OMost.OMore.O.dummy_More) || (3 != OMost.OMore.O.I.dummy_More)
+ (4 != OMost.OMore.O.I.IMore.dummy_More)
+ (5 != OMost.OMore.O.I.IMore.IMost.position)
+ ('e' != OMost.OMore.O.I.IMore.IMost.content)/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.recursive.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.recursive.d
new file mode 100644
index 000000000000..011fbdd31c50
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.recursive.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION: Recursive naming of structures should produce compiler error.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+#pragma D option quiet
+
+struct record {
+ struct record rec;
+ int position;
+ char content;
+};
+
+struct record r1;
+struct record r2;
+
+BEGIN
+{
+ r1.position = 1;
+ r1.content = 'a';
+
+ r2.position = 2;
+ r2.content = 'b';
+
+ printf("r1.position: %d\nr1.content: %c\n", r1.position, r1.content);
+ printf("r2.position: %d\nr2.content: %c\n", r2.position, r2.content);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.simple.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.simple.d
new file mode 100644
index 000000000000..7fc54ff04dd3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_INCOMPLETE.simple.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Declaring an inner struct within another struct and not defining it should
+ * throw a compiler error.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+#pragma D option quiet
+
+
+struct record {
+ struct pirate p;
+ int position;
+ char content;
+};
+
+
+struct record rec;
+
+BEGIN
+{
+ rec.position = 0;
+ rec.content = 'a';
+ printf("rec.position: %d\nrec.content: %c\n",
+ rec.position, rec.content);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_VOIDOBJ.baddec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_VOIDOBJ.baddec.d
new file mode 100644
index 000000000000..bba126fe73b9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_DECL_VOIDOBJ.baddec.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declaring void objects will result in a D_DECL_VOIDOBJ error
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+#pragma D option quiet
+
+struct {
+ int trace();
+};
+
+BEGIN
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_PROTO_ARG.DupStructAssoc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_PROTO_ARG.DupStructAssoc.d
new file mode 100644
index 000000000000..0eea2d8dafc2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/err.D_PROTO_ARG.DupStructAssoc.d
@@ -0,0 +1,80 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declaring an associative array with a struct to be its key type and trying to
+ * index with another struct having the same composition throws an error.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+#pragma D option quiet
+
+struct record {
+ int position;
+ char content;
+};
+
+struct pirate {
+ int position;
+ char content;
+};
+
+struct record r1;
+struct record r2;
+struct pirate p1;
+struct pirate p2;
+
+BEGIN
+{
+ r1.position = 1;
+ r1.content = 'a';
+
+ r2.position = 2;
+ r2.content = 'b';
+
+ p1.position = 1;
+ p1.content = 'a';
+
+ p2.position = 2;
+ p2.content = 'b';
+
+ assoc_array[r1] = 1000;
+ assoc_array[r2] = 2000;
+ assoc_array[p1] = 3333;
+ assoc_array[p2] = 4444;
+
+ printf("assoc_array[r1]: %d\n", assoc_array[r1]);
+ printf("assoc_array[r2]: %d\n", assoc_array[r2]);
+ printf("assoc_array[p1]: %d\n", assoc_array[p1]);
+ printf("assoc_array[p2]: %d\n", assoc_array[p2]);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructAssoc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructAssoc.d
new file mode 100644
index 000000000000..ead235da6ffe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructAssoc.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * When a struct is used as a key for an associative array, the key is formed
+ * by using the values of the members of the struct variable and not the
+ * address of the struct variable.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+#pragma D option quiet
+
+struct record {
+ int position;
+ char content;
+};
+
+struct record r1;
+struct record r2;
+
+BEGIN
+{
+ r1.position = 1;
+ r1.content = 'a';
+
+ r2.position = 1;
+ r2.content = 'a';
+
+ assoc_array[r1] = 1000;
+ assoc_array[r2] = 2000;
+
+ printf("assoc_array[r1]: %d\n", assoc_array[r1]);
+ printf("assoc_array[r2]: %d\n", assoc_array[r2]);
+
+ exit(0);
+}
+
+END
+/assoc_array[r1] != assoc_array[r2]/
+{
+ printf("Error");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructDataTypes.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructDataTypes.d
new file mode 100644
index 000000000000..5cfdc32553c6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructDataTypes.d
@@ -0,0 +1,133 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Declaration of the different data types within a struct and
+ * their definitions in a later clause should work fine.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ * NOTES: The floats, doubles and strings have not been implemented yet.
+ * When they do, appropriate lines in the code below should be uncommented.
+ * Similarly, the lines with the kmem_flags pointer assignment should be
+ * uncommented when the issues pertaining to it are clarified.
+ *
+ */
+#pragma D option quiet
+
+struct record {
+ char new_char;
+ short new_short;
+ int new_int;
+ long new_long;
+ long long new_long_long;
+ int8_t new_int8;
+ int16_t new_int16;
+ int32_t new_int32;
+ int64_t new_int64;
+ intptr_t new_intptr;
+ uint8_t new_uint8;
+ uint16_t new_uint16;
+ uint32_t new_uint32;
+ uint64_t new_uint64;
+ uintptr_t new_uintptr;
+
+ /*
+ float new_float;
+ double new_double;
+ long double new_long_double;
+
+ string new_string;
+ */
+
+ struct {
+ char ch;
+ int in;
+ long lg;
+ } new_struct;
+
+ union {
+ char ch;
+ int in;
+ long lg;
+ } new_union;
+
+enum colors {
+ RED,
+ GREEN,
+ BLUE
+} new_enum;
+
+
+ int *pointer;
+} var;
+
+/*
+ var.pointer = &`kmem_flags;
+*/
+BEGIN
+{
+ var.new_char = 'c';
+ var.new_short = 10;
+ var.new_int = 100;
+ var.new_long = 1234567890;
+ var.new_long_long = 1234512345;
+ var.new_int8 = 'p';
+ var.new_int16 = 20;
+ var.new_int32 = 200;
+ var.new_int64 = 2000000;
+ var.new_intptr = 0x12345;
+ var.new_uint8 = 'q';
+ var.new_uint16 = 30;
+ var.new_uint32 = 300;
+ var.new_uint64 = 3000000;
+ var.new_uintptr = 0x67890;
+
+/* var.new_float = 1.23456;
+ var.new_double = 2.34567890;
+ var.new_long_double = 3.567890123;
+
+ var.new_string = "hello";
+*/
+
+/*
+ var.pointer = &`kmem_flags;
+*/
+
+ var.new_struct.ch = 'c';
+ var.new_struct.in = 4;
+ var.new_struct.lg = 4;
+
+ var.new_union.ch = 'd';
+ var.new_union.in = 5;
+ var.new_union.lg = 5;
+
+ this->var = var;
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructInside.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructInside.d
new file mode 100644
index 000000000000..159accc406f6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.StructInside.d
@@ -0,0 +1,124 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify the nested behavior of structs.
+ *
+ * SECTION: Structs and Unions/Structs
+ *
+ */
+
+#pragma D option quiet
+
+struct InnerMost {
+ int position;
+ char content;
+};
+
+struct InnerMore {
+ struct InnerMost IMost;
+ int dummy_More;
+};
+
+struct Inner {
+ struct InnerMore IMore;
+ int dummy_More;
+};
+
+struct Outer {
+ struct Inner I;
+ int dummy_More;
+};
+
+struct OuterMore {
+ struct Outer O;
+ int dummy_More;
+};
+
+struct OuterMost {
+ struct OuterMore OMore;
+ int dummy_More;
+} OMost;
+
+struct OuterMost OMostCopy;
+
+BEGIN
+{
+
+ OMost.dummy_More = 0;
+ OMost.OMore.dummy_More = 1;
+ OMost.OMore.O.dummy_More = 2;
+ OMost.OMore.O.I.dummy_More = 3;
+ OMost.OMore.O.I.IMore.dummy_More = 4;
+ OMost.OMore.O.I.IMore.IMost.position = 5;
+ OMost.OMore.O.I.IMore.IMost.content = 'e';
+
+ printf("OMost.dummy_More: %d\nOMost.OMore.dummy_More: %d\n",
+ OMost.dummy_More, OMost.OMore.dummy_More);
+
+ printf("OMost.OMore.O.dummy_More: %d\n",
+ OMost.OMore.O.dummy_More);
+
+ printf("OMost.OMore.O.I.dummy_More: %d\n",
+ OMost.OMore.O.I.dummy_More);
+
+ printf("OMost.OMore.O.I.IMore.dummy_More:%d\n",
+ OMost.OMore.O.I.IMore.dummy_More);
+
+ printf("OMost.OMore.O.I.IMore.IMost.position: %d\n",
+ OMost.OMore.O.I.IMore.IMost.position);
+
+ printf("OMost.OMore.O.I.IMore.IMost.content: %c\n",
+ OMost.OMore.O.I.IMore.IMost.content);
+
+ OMostCopy = OMost;
+
+ exit(0);
+}
+
+END
+/(0 != OMost.dummy_More) || (1 != OMost.OMore.dummy_More) ||
+ (2 != OMost.OMore.O.dummy_More) || (3 != OMost.OMore.O.I.dummy_More) ||
+ (4 != OMost.OMore.O.I.IMore.dummy_More) ||
+ (5 != OMost.OMore.O.I.IMore.IMost.position) ||
+ ('e' != OMost.OMore.O.I.IMore.IMost.content)/
+{
+ exit(1);
+}
+
+END
+/(0 != OMostCopy.dummy_More) || (1 != OMostCopy.OMore.dummy_More) ||
+ (2 != OMostCopy.OMore.O.dummy_More) ||
+ (3 != OMostCopy.OMore.O.I.dummy_More) ||
+ (4 != OMostCopy.OMore.O.I.IMore.dummy_More) ||
+ (5 != OMostCopy.OMore.O.I.IMore.IMost.position) ||
+ ('e' != OMostCopy.OMore.O.I.IMore.IMost.content)/
+{
+ exit(2);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.clauselocal.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.clauselocal.d
new file mode 100644
index 000000000000..0a7e80e43b2a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.clauselocal.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+struct foo {
+ int x;
+ char y;
+ short z;
+};
+
+this struct foo bar;
+long bignum;
+
+BEGIN
+{
+ this->bar.x = 1;
+ this->bar.y = ',';
+ this->bar.z = 1234;
+}
+
+BEGIN
+{
+ printf("Die %s%c %s.\n", this->bar.x == 1 ? "SystemTap" : "DTrace",
+ this->bar.y, this->bar.z == 1234 ? "Die" : "The");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.clauselocal.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.clauselocal.d.out
new file mode 100644
index 000000000000..c3fbf224fc6d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/struct/tst.clauselocal.d.out
@@ -0,0 +1,2 @@
+Die SystemTap, Die.
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.else.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.else.d
new file mode 100644
index 000000000000..88da007436fb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.else.d
@@ -0,0 +1,33 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "else" statement is executed
+ */
+
+BEGIN
+{
+ if (0) {
+ n = 1;
+ } else {
+ n = 0;
+ }
+ exit(n)
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if.d
new file mode 100644
index 000000000000..3da5d2daf695
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if.d
@@ -0,0 +1,33 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "if" statement executes the correct body.
+ */
+
+BEGIN
+{
+ if (1) {
+ n = 0;
+ } else {
+ n = 1;
+ }
+ exit(n)
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if2.d
new file mode 100644
index 000000000000..b56e39929d67
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if2.d
@@ -0,0 +1,33 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "if" statement executes the correct body.
+ * parses single-statement, braceless bodies correctly.
+ */
+
+BEGIN
+{
+ if (1)
+ n = 0;
+ else
+ n = 1;
+ exit(n)
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d
new file mode 100644
index 000000000000..00837eb65c2c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * statements before and after an if statement are executed.
+ */
+
+BEGIN
+{
+ i = 1;
+ if (1) {
+ i++;
+ } else {
+ i++;
+ }
+ i++;
+}
+
+BEGIN
+/i == 3/
+{
+ exit(0);
+}
+
+BEGIN
+/i != 3/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d
new file mode 100644
index 000000000000..e8ad443a04bd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d
@@ -0,0 +1,38 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * nested "if" statement executes the correct body.
+ */
+
+BEGIN
+{
+ if (0) {
+ exit(1);
+ } else {
+ if (0) {
+ exit(1);
+ } else {
+ exit(0);
+ }
+ exit(1);
+ }
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d
new file mode 100644
index 000000000000..81196c0ca47c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d
@@ -0,0 +1,30 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "if" body without trailing semicolon parses correctly
+ */
+
+BEGIN
+{
+ if (1) {
+ exit(0)
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d
new file mode 100644
index 000000000000..e1bd3895f9f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d
@@ -0,0 +1,31 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "if" body without trailing semicolon parses correctly
+ */
+
+BEGIN
+{
+ if (1) {
+ i = 1;
+ exit(0)
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.args.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.args.c
new file mode 100644
index 000000000000..ad483ee99629
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.args.c
@@ -0,0 +1,43 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+/*ARGSUSED*/
+int
+main(int argc, char **argv)
+{
+ for (;;) {
+ (void) __syscall(SYS_mmap, NULL, (size_t)1, 2, 3, -1,
+ (off_t)0x12345678);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.args.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.args.d
new file mode 100644
index 000000000000..8e473b466ea8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.args.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Make sure we're correctly reporting arguments to syscall probes.
+ */
+
+#pragma D option quiet
+
+syscall::mmap*:entry
+/pid == $1 && arg0 == 0 && arg1 == 1 && arg2 == 2 && arg3 == 3 &&
+ (int)arg4 == -1 && arg5 == 0x12345678/
+{
+ exit(0);
+}
+
+tick-1s
+/i++ == 3/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.openret.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.openret.ksh
new file mode 100644
index 000000000000..6469db7703fa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/syscall/tst.openret.ksh
@@ -0,0 +1,75 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+script() {
+ $dtrace -c 'cat shajirosan' -qs /dev/stdin <<EOF
+ syscall::open*:entry
+ /pid == \$target/
+ {
+ self->p = arg0;
+ }
+
+ syscall::open*:return
+ /self->p && copyinstr(self->p) == "shajirosan"/
+ {
+ self->err = 1;
+ self->p = 0;
+ }
+
+ syscall::open*:return
+ /self->err && (int)arg0 == -1 && (int)arg1 == -1/
+ {
+ exit(0);
+ }
+
+ syscall::open*:return
+ /self->err/
+ {
+ printf("a failed open(2) returned %d\n", (int)arg0);
+ exit(1);
+ }
+
+ syscall::open*:return
+ /self->p/
+ {
+ self->p = 0;
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post.c
new file mode 100644
index 000000000000..1e7f957f1e63
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post.c
@@ -0,0 +1,45 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libsysevent.h>
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ sysevent_id_t id;
+
+ for (;;) {
+ if (sysevent_post_event("class_dtest", "subclass_dtest",
+ "vendor_dtest", "publisher_dtest", NULL, &id) != 0) {
+ (void) fprintf(stderr, "failed to post sysevent\n");
+ return (1);
+ }
+
+ sleep(1);
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post.d
new file mode 100644
index 000000000000..e547a2610cb9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post.d
@@ -0,0 +1,88 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ $1 + 0; /* make sure pid is referenced */
+
+ /*
+ * Wait no more than a five seconds for the sysevent to be posted
+ */
+ timeout = timestamp + 5000000000;
+}
+
+sysevent:::post
+/args[0]->ec_name != NULL/
+{
+ printf("channel name is non-NULL (%s)\n",
+ args[0]->ec_name);
+ exit(1);
+}
+
+sysevent:::post
+/strstr(args[1]->se_publisher, "vendor_dtest") == NULL/
+{
+ printf("missing vendor name from publisher (%s)\n",
+ args[1]->se_publisher);
+ exit(1);
+}
+
+sysevent:::post
+/strstr(args[1]->se_publisher, "publisher_dtest") == NULL/
+{
+ printf("missing publisher name from publisher (%s)\n",
+ args[1]->se_publisher);
+ exit(1);
+}
+
+sysevent:::post
+/args[1]->se_class != "class_dtest"/
+{
+ printf("unexpected class name (%s)\n", args[1]->se_class);
+ exit(1);
+}
+
+sysevent:::post
+/args[1]->se_subclass != "subclass_dtest"/
+{
+ printf("unexpected subclass name (%s)\n", args[1]->se_subclass);
+ exit(1);
+}
+
+sysevent:::post
+{
+ exit(0);
+}
+
+profile:::tick-8
+/timestamp > timeout/
+{
+ printf("timed out\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c
new file mode 100644
index 000000000000..4a452a7ad2de
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c
@@ -0,0 +1,49 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <libsysevent.h>
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ evchan_t *ch;
+
+ if (sysevent_evc_bind("channel_dtest", &ch,
+ EVCH_CREAT | EVCH_HOLD_PEND) != 0) {
+ (void) fprintf(stderr, "failed to bind to sysevent channel\n");
+ return (1);
+ }
+
+ for (;;) {
+ if (sysevent_evc_publish(ch, "class_dtest", "subclass_dtest",
+ "vendor_dtest", "publisher_dtest", NULL, EVCH_SLEEP) != 0) {
+ (void) sysevent_evc_unbind(ch);
+ (void) fprintf(stderr, "failed to publisth sysevent\n");
+ return (1);
+ }
+ sleep(1);
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.d
new file mode 100644
index 000000000000..9d12e1eccc08
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.d
@@ -0,0 +1,87 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ $1 + 0; /* make sure pid is referenced */
+
+ /*
+ * Wait no more than five seconds for the sysevent to be posted
+ */
+ timeout = timestamp + 5000000000;
+}
+
+sysevent:::post
+/args[0]->ec_name != "channel_dtest"/
+{
+ printf("unexpected channel name (%s)\n", args[0]->ec_name);
+ exit(1);
+}
+
+sysevent:::post
+/strstr(args[1]->se_publisher, "vendor_dtest") == NULL/
+{
+ printf("missing vendor name from publisher (%s)\n",
+ args[1]->se_publisher);
+ exit(1);
+}
+
+sysevent:::post
+/strstr(args[1]->se_publisher, "publisher_dtest") == NULL/
+{
+ printf("missing publisher name from publisher (%s)\n",
+ args[1]->se_publisher);
+ exit(1);
+}
+
+sysevent:::post
+/args[1]->se_class != "class_dtest"/
+{
+ printf("unexpected class name (%s)\n", args[1]->se_class);
+ exit(1);
+}
+
+sysevent:::post
+/args[1]->se_subclass != "subclass_dtest"/
+{
+ printf("unexpected subclass name (%s)\n", args[1]->se_subclass);
+ exit(1);
+}
+
+sysevent:::post
+{
+ exit(0);
+}
+
+profile:::tick-8
+/timestamp > timeout/
+{
+ printf("timed out\n");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZERO.tick.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZERO.tick.d
new file mode 100644
index 000000000000..015ae2b0e613
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZERO.tick.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Negative test; calls tick without valid value.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-n
+{
+ printf("This test is a simple tick-n negative test\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROonens.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROonens.d
new file mode 100644
index 000000000000..3ed28b1b15ba
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROonens.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call profile-'ns' less than 200 micro seconds.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+#pragma D option quiet
+
+profile-1ns
+{
+ printf("Calls 'ns' less than 200 micro seconds\n");
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROonensec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROonensec.d
new file mode 100644
index 000000000000..7b4df199d303
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROonensec.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call profile-1nsec; less than 200 micro seconds.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+#pragma D option quiet
+
+profile-1nsec
+{
+ printf("Call profile-1nsec; less than 200 micro seconds\n");
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROoneus.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROoneus.d
new file mode 100644
index 000000000000..6a64a3a2d4e1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROoneus.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Call profile-us; less than 200 micro seconds.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+#pragma D option quiet
+
+profile-1us
+{
+ printf(" Calling profile-us less than 200 micro seconds should fail\n");
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROoneusec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROoneusec.d
new file mode 100644
index 000000000000..b6b80bea03bd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/err.D_PDESC_ZEROoneusec.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * profile-usec; less than 200 micro seconds.
+ *
+ * SECTION: profile Provider/profile-n probes
+ *
+ */
+
+#pragma D option quiet
+
+profile-1usec
+{
+ printf("profile-usec; less than 200 micro seconds \n");
+ exit (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickarg0.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickarg0.d
new file mode 100644
index 000000000000..4dda358c4913
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickarg0.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * Simple tick-n 'arg0' test.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-1
+{
+ printf("The arg0 is %d\n", (int)arg0);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickms.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickms.d
new file mode 100644
index 000000000000..602f3a91a08e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickms.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * tick-ms simple test.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-1ms
+{
+ printf("This test is a simple tick-ms provider test\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickms.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickms.d.out
new file mode 100644
index 000000000000..1e267598c0d4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickms.d.out
@@ -0,0 +1,2 @@
+This test is a simple tick-ms provider test
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickmsec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickmsec.d
new file mode 100644
index 000000000000..1cf3b742ebff
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickmsec.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * tick-msec simple test.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-1msec
+{
+ printf("This test is a simple tick-msec provider test\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickmsec.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickmsec.d.out
new file mode 100644
index 000000000000..286bb14b7092
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickmsec.d.out
@@ -0,0 +1,2 @@
+This test is a simple tick-msec provider test
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickns.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickns.d
new file mode 100644
index 000000000000..917139cab8ff
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickns.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * tick-ns simple test.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-20000000ns
+{
+ printf("This test is a simple tick-ns provider test\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickns.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickns.d.out
new file mode 100644
index 000000000000..26adddebc943
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickns.d.out
@@ -0,0 +1,2 @@
+This test is a simple tick-ns provider test
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticknsec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticknsec.d
new file mode 100644
index 000000000000..3eedead2a43c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticknsec.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * tick-nsec simple test.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-20000000nsec
+{
+ printf("This test is a simple tick-nsec provider test\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticknsec.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticknsec.d.out
new file mode 100644
index 000000000000..4ad77b587d60
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticknsec.d.out
@@ -0,0 +1,2 @@
+This test is a simple tick-nsec provider test
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticks.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticks.d
new file mode 100644
index 000000000000..05f2657da46b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticks.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * tick-1s simple test.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-1s
+{
+ printf("This test is a simple tick-s provider test\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticks.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticks.d.out
new file mode 100644
index 000000000000..b0631218745a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticks.d.out
@@ -0,0 +1,2 @@
+This test is a simple tick-s provider test
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticksec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticksec.d
new file mode 100644
index 000000000000..703af4d52cac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticksec.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * tick-1sec simple test.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-1sec
+{
+ printf("This test is a simple tick-sec provider test\n");
+}
+tick-1sec
+{
+ printf("This test is a simple tick-sec provider test");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticksec.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticksec.d.out
new file mode 100644
index 000000000000..d9d4f45a6d4d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.ticksec.d.out
@@ -0,0 +1,2 @@
+This test is a simple tick-sec provider test
+This test is a simple tick-sec provider test
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickus.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickus.d
new file mode 100644
index 000000000000..aa10cbb50de9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickus.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * tick-2000us simple test.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-2000us
+{
+ printf("This test is a simple tick-us provider test\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickus.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickus.d.out
new file mode 100644
index 000000000000..00baa3dce635
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickus.d.out
@@ -0,0 +1,2 @@
+This test is a simple tick-us provider test
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickusec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickusec.d
new file mode 100644
index 000000000000..9deb8f4c57f7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickusec.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * tick-2000usec simple test.
+ *
+ * SECTION: profile Provider/tick-n probes
+ *
+ */
+
+
+#pragma D option quiet
+
+tick-2000usec
+{
+ printf("This test is a simple tick-usec provider test\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickusec.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickusec.d.out
new file mode 100644
index 000000000000..40987e325c7e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tick-n/tst.tickusec.d.out
@@ -0,0 +1,2 @@
+This test is a simple tick-usec provider test
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_PROTO_LEN.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_PROTO_LEN.bad.d
new file mode 100644
index 000000000000..68c11950b51c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_PROTO_LEN.bad.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * Test trace() with no arguments.
+ *
+ * SECTION: Actions and Subroutines/trace()
+ */
+
+BEGIN
+{
+
+ trace();
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_TRACE_AGG.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_TRACE_AGG.bad.d
new file mode 100644
index 000000000000..b29b9f179964
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_TRACE_AGG.bad.d
@@ -0,0 +1,29 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+BEGIN
+{
+ @ = count();
+ trace(@);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_TRACE_VOID.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_TRACE_VOID.bad.d
new file mode 100644
index 000000000000..ed044b2236fb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/err.D_TRACE_VOID.bad.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * Test an invalid specification of trace() with a void argument.
+ *
+ * SECTION: Actions and Subroutines/trace()
+ */
+
+BEGIN
+{
+ trace((void)`kmem_flags);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.dyn.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.dyn.d
new file mode 100644
index 000000000000..24ad80fb469c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.dyn.d
@@ -0,0 +1,28 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+BEGIN
+{
+ trace(*curpsinfo);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.misc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.misc.d
new file mode 100644
index 000000000000..70ad5fc6d969
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.misc.d
@@ -0,0 +1,68 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test a variety of trace() action invocations.
+ *
+ * SECTION: Actions and Subroutines/trace();
+ * Output Formatting/trace()
+ *
+ * NOTES:
+ * We test things that exercise different kinds of DIFO return types
+ * to ensure each one can be traced.
+ */
+
+BEGIN
+{
+ i = 1;
+}
+
+
+tick-1
+/i != 5/
+{
+ trace("test trace"); /* DT_TYPE_STRING */
+ trace(12345); /* DT_TYPE_INT (constant) */
+ trace(x++); /* DT_TYPE_INT (derived) */
+ trace(timestamp); /* DT_TYPE_INT (variable) */
+ trace(`kmem_flags); /* CTF type (by value) */
+ trace(*`rootvp); /* CTF type (by ref) */
+ i++;
+}
+
+tick-1
+/i == 5/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.qstring.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.qstring.d
new file mode 100644
index 000000000000..a81d147b0969
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.qstring.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+/*
+ * ASSERTION:
+ * Positive trace tests - trace with strings, using quiet option
+ *
+ * SECTION: Actions and Subroutines/trace()
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ trace("this");
+ trace(" %should work.\n");
+ trace("%don't w%orry -- this won't cause a %segfault.\n");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.qstring.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.qstring.d.out
new file mode 100644
index 000000000000..908ffb2a2657
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.qstring.d.out
@@ -0,0 +1,3 @@
+this %should work.
+%don't w%orry -- this won't cause a %segfault.
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.string.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.string.d
new file mode 100644
index 000000000000..c5e7c2ccbd54
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/trace/tst.string.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive trace tests - trace with strings
+ *
+ * SECTION: Actions and Subroutines/trace()
+ */
+
+BEGIN
+{
+ trace("this");
+ trace(" %should work.\n");
+ trace("%don't w%orry -- this won't cause a %segfault.\n");
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_ARG.badsize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_ARG.badsize.d
new file mode 100644
index 000000000000..4e137cec5974
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_ARG.badsize.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test tracemem() with an invalid size argument.
+ *
+ * SECTION: Actions and Subroutines/tracemem()
+ */
+
+BEGIN
+{
+ tracemem(123, "i'm a string");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_LEN.toofew.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_LEN.toofew.d
new file mode 100644
index 000000000000..91c4f77bbcf8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_LEN.toofew.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test tracemem() with too few arguments.
+ *
+ * SECTION: Actions and Subroutines/tracemem()
+ */
+
+
+BEGIN
+{
+ tracemem(123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_ADDR.badaddr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_ADDR.badaddr.d
new file mode 100644
index 000000000000..68145774e8d5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_ADDR.badaddr.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test tracemem() with an invalid address argument.
+ *
+ * SECTION: Actions and Subroutines/tracemem()
+ */
+
+BEGIN
+{
+ tracemem(`v, 123);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_ARGS.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_ARGS.d
new file mode 100644
index 000000000000..1eb96be529cc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_ARGS.d
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ tracemem(`dtrace_zero, 256, 0, "fishpong");
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_DYNSIZE.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_DYNSIZE.d
new file mode 100644
index 000000000000..554bb7dfb4df
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_DYNSIZE.d
@@ -0,0 +1,30 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+BEGIN
+{
+ tracemem(`dtrace_zero, 256, "fishpong");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_SIZE.negsize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_SIZE.negsize.d
new file mode 100644
index 000000000000..b3dd4381e3d0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_SIZE.negsize.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test tracemem() with a negative size argument.
+ *
+ * SECTION: Actions and Subroutines/tracemem()
+ */
+
+BEGIN
+{
+ tracemem(123, -456);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_SIZE.zerosize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_SIZE.zerosize.d
new file mode 100644
index 000000000000..595bfcc030bf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/err.D_TRACEMEM_SIZE.zerosize.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test tracemem() with a zero size argument.
+ *
+ * SECTION: Actions and Subroutines/tracemem()
+ */
+
+BEGIN
+{
+ tracemem(123, 0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.dynsize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.dynsize.d
new file mode 100644
index 000000000000..de530e811cb1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.dynsize.d
@@ -0,0 +1,45 @@
+/*
+ * 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 (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = -10;
+}
+
+tick-10ms
+/i++ < 150/
+{
+ printf("%d:", i);
+ tracemem(`dtrace_zero, 128, i);
+ printf("\n");
+}
+
+tick-10ms
+/i >= 150/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.dynsize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.dynsize.d.out
new file mode 100644
index 000000000000..6415893b8db1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.dynsize.d.out
@@ -0,0 +1,1313 @@
+-9:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+-8:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+-7:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+-6:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+-5:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+-4:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+-3:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+-2:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+-1:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+0:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+1:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 .
+
+2:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 ..
+
+3:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 ...
+
+4:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 ....
+
+5:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 .....
+
+6:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 ......
+
+7:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 .......
+
+8:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 ........
+
+9:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 .........
+
+10:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 ..........
+
+11:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 ...........
+
+12:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 ............
+
+13:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
+
+14:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
+
+15:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
+
+16:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+17:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 .
+
+18:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 ..
+
+19:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 ...
+
+20:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 ....
+
+21:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 .....
+
+22:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 ......
+
+23:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 .......
+
+24:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 ........
+
+25:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 .........
+
+26:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 ..........
+
+27:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 ...........
+
+28:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 ............
+
+29:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
+
+30:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
+
+31:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
+
+32:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+33:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 .
+
+34:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 ..
+
+35:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 ...
+
+36:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 ....
+
+37:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 .....
+
+38:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 ......
+
+39:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 .......
+
+40:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 ........
+
+41:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 .........
+
+42:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 ..........
+
+43:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 ...........
+
+44:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 ............
+
+45:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
+
+46:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
+
+47:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
+
+48:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+49:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 .
+
+50:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 ..
+
+51:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 ...
+
+52:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 ....
+
+53:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 .....
+
+54:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 ......
+
+55:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 .......
+
+56:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 ........
+
+57:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 .........
+
+58:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 ..........
+
+59:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 ...........
+
+60:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 ............
+
+61:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
+
+62:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
+
+63:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
+
+64:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+65:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 .
+
+66:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 ..
+
+67:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 ...
+
+68:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 ....
+
+69:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 .....
+
+70:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 ......
+
+71:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 .......
+
+72:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 ........
+
+73:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 .........
+
+74:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 ..........
+
+75:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 ...........
+
+76:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 ............
+
+77:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
+
+78:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
+
+79:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
+
+80:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+81:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 .
+
+82:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 ..
+
+83:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 ...
+
+84:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 ....
+
+85:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 .....
+
+86:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 ......
+
+87:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 .......
+
+88:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 ........
+
+89:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 .........
+
+90:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 ..........
+
+91:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 ...........
+
+92:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 ............
+
+93:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
+
+94:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
+
+95:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
+
+96:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+97:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 .
+
+98:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 ..
+
+99:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 ...
+
+100:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 ....
+
+101:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 .....
+
+102:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 ......
+
+103:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 .......
+
+104:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 ........
+
+105:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 .........
+
+106:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 ..........
+
+107:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 ...........
+
+108:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 ............
+
+109:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
+
+110:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
+
+111:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
+
+112:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+113:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 .
+
+114:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 ..
+
+115:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 ...
+
+116:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 ....
+
+117:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 .....
+
+118:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 ......
+
+119:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 .......
+
+120:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 ........
+
+121:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 .........
+
+122:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 ..........
+
+123:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 ...........
+
+124:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 ............
+
+125:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
+
+126:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
+
+127:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
+
+128:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+129:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+130:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+131:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+132:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+133:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+134:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+135:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+136:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+137:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+138:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+139:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+140:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+141:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+142:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+143:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+144:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+145:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+146:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+147:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+148:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+149:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+150:
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
+ 0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.rootvp.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.rootvp.d
new file mode 100644
index 000000000000..537b72281254
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/tracemem/tst.rootvp.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test tracemem() by tracing out the contents of the root vnode
+ * as a raw stream of bytes.
+ *
+ * SECTION: Actions and Subroutines/tracemem()
+ */
+
+
+BEGIN
+{
+ i = 1;
+}
+
+tick-1
+/i != 5/
+{
+ tracemem(`rootvp, 20);
+ i++;
+}
+
+tick-1
+/i == 5/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_DECL_TYPERED.BadTransDecl.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_DECL_TYPERED.BadTransDecl.d
new file mode 100644
index 000000000000..2a44778e334d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_DECL_TYPERED.BadTransDecl.d
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator with the input type enclosed in
+ * between braces rather than angle brackets.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *uvar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct
+{
+ struct input_struct *uvar
+}
+{
+ myi = ((struct input_struct *) uvar)->i;
+ myc = ((struct input_struct *) uvar)->c;
+}
+
+BEGIN
+{
+ printf("Using braces instead of angle brackets for translator input");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_OP_INCOMPLETE.NonExistentInput1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_OP_INCOMPLETE.NonExistentInput1.d
new file mode 100644
index 000000000000..0c8c84d35b59
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_OP_INCOMPLETE.NonExistentInput1.d
@@ -0,0 +1,54 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator with a non-existent input type.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ */
+
+#pragma D option quiet
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < struct input_struct *ivar >
+{
+ myi = ((struct input_struct *) ivar)->nonexistentI;
+ myc = ((struct input_struct *) ivar)->nonexistentC;
+};
+
+BEGIN
+{
+ printf("Test the translation of a non existing input type");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl1.d
new file mode 100644
index 000000000000..52e5c9aea96f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl1.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator with the input type enclosed in
+ * between parantheses rather than angle brackets.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *uvar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct ( struct input_struct *uvar )
+{
+ myi = ((struct input_struct *) uvar)->i;
+ myc = ((struct input_struct *) uvar)->c;
+}
+
+BEGIN
+{
+ printf("Test translator with input type in parantheses");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl3.d
new file mode 100644
index 000000000000..6be8128a76a1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl3.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator without enclosing braces { }.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *uvar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < struct input_struct *uvar >
+ myi = ((struct input_struct *) uvar)->i;
+ myc = ((struct input_struct *) uvar)->c;
+;
+
+BEGIN
+{
+ printf("Test the translator definition without enclosing braces");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl4.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl4.d
new file mode 100644
index 000000000000..926f74c7ee9a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_SYNTAX.BadTransDecl4.d
@@ -0,0 +1,65 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator without terminating semi-colon (;).
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *uvar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < struct input_struct *uvar >
+{
+ myi = ((struct input_struct *) uvar)->i;
+ myc = ((struct input_struct *) uvar)->c;
+}
+
+translator struct output_struct < struct new_struct *newvar >
+{
+};
+
+
+BEGIN
+{
+ printf("Test translator declaration without terminating semi-colon");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_TYPE_MEMBER.NonExistentInput2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_TYPE_MEMBER.NonExistentInput2.d
new file mode 100644
index 000000000000..16deff89396f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_TYPE_MEMBER.NonExistentInput2.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator with a non-existent member
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *ivar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < struct input_struct *ivar >
+{
+ myi = ((struct input_struct *) ivar)->i;
+ myc = ((struct input_struct *) ivar)->nonexistent;
+};
+
+BEGIN
+{
+ printf("Testing the assignment of a non-existent input member");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_INCOMPAT.BadInputType1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_INCOMPAT.BadInputType1.d
new file mode 100644
index 000000000000..26cab45821a8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_INCOMPAT.BadInputType1.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator with a mismatch in types.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *uvar;
+
+struct output_struct {
+ int myi;
+ char *myc;
+};
+
+translator struct output_struct < struct input_struct *uvar >
+{
+ myi = ((struct input_struct *) uvar)->i;
+ myc = ((struct input_struct *) uvar)->c;
+};
+
+BEGIN
+{
+ printf("Translating against the rules of assignment operator");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_MEMB.NonExistentOutput2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_MEMB.NonExistentOutput2.d
new file mode 100644
index 000000000000..6d6eba1b93a4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_MEMB.NonExistentOutput2.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator with a non-existent output member.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *ivar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < struct input_struct *ivar >
+{
+ myi = ((struct input_struct *) ivar)->i;
+ yourc = ((struct input_struct *) ivar)->nonexistent;
+};
+
+BEGIN
+{
+ printf("Testing translation with non existent output member");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_NONE.BadTransDecl6.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_NONE.BadTransDecl6.d
new file mode 100644
index 000000000000..4cfabcea354c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_NONE.BadTransDecl6.d
@@ -0,0 +1,72 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * When xlate is used on a variable for which no translation exists a
+ * D_XLATE_NONE is thrown
+ *
+ * SECTION: Translators/Translate Operator
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct myinput_struct {
+ int i;
+ char c;
+};
+
+struct myoutput_struct {
+ int myi;
+ char myc;
+};
+
+translator struct myoutput_struct < struct myinput_struct *ivar >
+{
+ myi = ((struct myinput_struct *) ivar)->i;
+ myc = ((struct myinput_struct *) ivar)->c;
+
+};
+
+struct myinput_struct f;
+BEGIN
+{
+ f.i = 10;
+ f.c = 'c';
+
+ xlate < struct myoutput_struct >(f)->myi;
+ printf("Translate operator used without correct translator decl\n");
+ exit(0);
+}
+
+ERROR
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_REDECL.RepeatTransDecl.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_REDECL.RepeatTransDecl.d
new file mode 100644
index 000000000000..62f8482e334e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_REDECL.RepeatTransDecl.d
@@ -0,0 +1,67 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Redeclaring the same translation twice throws a D_XLATE_REDECL error.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int ii1;
+ char ic1;
+} *ivar1;
+
+struct output_struct {
+ int oi;
+ char oc;
+};
+
+
+translator struct output_struct < struct input_struct *ivar1 >
+{
+ oi = ((struct input_struct *) ivar1)->ii1;
+ oc = ((struct input_struct *) ivar1)->ic1;
+};
+
+translator struct output_struct < struct input_struct *ivar1 >
+{
+ oi = ((struct input_struct *) ivar1)->ii1;
+ oc = ((struct input_struct *) ivar1)->ic1;
+};
+
+
+BEGIN
+{
+ printf("Redeclaration of the same translation");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.BadTransDecl8.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.BadTransDecl8.d
new file mode 100644
index 000000000000..63786c7da673
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.BadTransDecl8.d
@@ -0,0 +1,58 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * When the output type of the translator declaration is not a struct or
+ * union a D_XLATE_SOU is thrown.
+ *
+ * SECTION: Translators/Translator Declarations
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int ii;
+ char ic;
+};
+
+enum colors
+{
+ RED,
+ BLUE
+};
+
+translator enum colors < struct input_struct *ivar >
+{
+};
+
+BEGIN
+{
+ printf("Output type of translation is an enum");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.BadTransInt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.BadTransInt.d
new file mode 100644
index 000000000000..6545569721bb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.BadTransInt.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * When the output type of the translator declaration is not a struct or
+ * union a D_XLATE_SOU is thrown.
+ *
+ * SECTION: Translators/Translator Declarations
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int ii;
+ char ic;
+};
+
+translator int < struct input_struct *ivar >
+{
+};
+
+BEGIN
+{
+ printf("Output type of translation is an int");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.NonExistentOutput1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.NonExistentOutput1.d
new file mode 100644
index 000000000000..1ebb94ccedbb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/err.D_XLATE_SOU.NonExistentOutput1.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator with a non-existent output type.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *ivar;
+
+translator struct output_struct < struct input_struct *ivar >
+{
+ myi = ((struct input_struct *) ivar)->i;
+ myc = ((struct input_struct *) ivar)->nonexistent;
+};
+
+BEGIN
+{
+ printf("Translation with non existent output type struct");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.CircularTransDecl.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.CircularTransDecl.d
new file mode 100644
index 000000000000..58466f703a8c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.CircularTransDecl.d
@@ -0,0 +1,100 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test circular declaration of translations
+ *
+ * SECTION: Translators/ Translator Declarations
+ * SECTION: Translators/ Translate Operator
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+};
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < struct input_struct ivar >
+{
+ myi = ((struct input_struct ) ivar).i;
+ myc = ((struct input_struct ) ivar).c;
+};
+
+translator struct input_struct < struct output_struct uvar >
+{
+ i = ((struct output_struct ) uvar).myi;
+ c = ((struct output_struct ) uvar).myc;
+};
+
+struct input_struct f1;
+struct output_struct f2;
+
+BEGIN
+{
+ f1.i = 10;
+ f1.c = 'c';
+
+ f2.myi = 100;
+ f2.myc = 'd';
+
+ printf("Testing circular translations\n");
+ forwardi = xlate < struct output_struct > (f1).myi;
+ forwardc = xlate < struct output_struct > (f1).myc;
+ backwardi = xlate < struct input_struct > (f2).i;
+ backwardc = xlate < struct input_struct > (f2).c;
+
+ printf("forwardi: %d\tforwardc: %c\n", forwardi, forwardc);
+ printf("backwardi: %d\tbackwardc: %c", backwardi, backwardc);
+ exit(0);
+}
+
+BEGIN
+/(10 == forwardi) && ('c' == forwardc) && (100 == backwardi) &&
+ ('d' == backwardc)/
+{
+ exit(0);
+}
+
+BEGIN
+/(10 != forwardi) || ('c' != forwardc) || (100 != backwardi) ||
+ ('d' != backwardc)/
+{
+ exit(1);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.EmptyTransDecl.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.EmptyTransDecl.d
new file mode 100644
index 000000000000..5a292071f16f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.EmptyTransDecl.d
@@ -0,0 +1,79 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the empty declaration of a translator
+ *
+ * SECTION: Translators/ Translator Declarations
+ * SECTION: Translators/ Translate Operator
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *uvar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < struct input_struct uvar >
+{
+};
+
+struct input_struct in;
+struct output_struct ou;
+
+BEGIN
+{
+ in.i = 10;
+ in.c = 'c';
+
+ ou = xlate < struct output_struct > (in);
+
+ printf("ou.myi: %d\tou.myc: %c\n", ou.myi, ou.myc);
+}
+
+BEGIN
+/(0 != ou.myi) || (0 != ou.myc)/
+{
+ printf("Failed\n");
+ exit(1);
+}
+
+BEGIN
+/(0 == ou.myi) || (0 == ou.myc)/
+{
+ printf("Passed\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.ForwardTag.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.ForwardTag.d
new file mode 100644
index 000000000000..246a8d2b087e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.ForwardTag.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a forward tag using a translator definition.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *uvar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < struct callmewhatever *idontcare >
+{
+ myi = ((struct input_struct *) uvar)->i;
+ myc = ((struct input_struct *) uvar)->c;
+};
+
+BEGIN
+{
+ printf("This test defines a forward tag");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.InputAliasTrans.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.InputAliasTrans.d
new file mode 100644
index 000000000000..a562b39447bf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.InputAliasTrans.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * The input type of the tranlator declaration is an alias.
+ *
+ * SECTION: Translators/ Translator Declarations.
+ *
+ */
+
+#pragma D option quiet
+
+typedef struct input_struct {
+ int ii;
+ char ic;
+} input_t;
+
+struct output_struct {
+ int oi;
+ char oc;
+};
+
+
+translator struct output_struct < input_t *ivar >
+{
+ oi = ((input_t *) ivar)->ii;
+ oc = ((input_t *) ivar)->ic;
+};
+
+BEGIN
+{
+ printf("Input type is an alias");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.InputIntTrans.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.InputIntTrans.d
new file mode 100644
index 000000000000..e5159ed64f2e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.InputIntTrans.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of a translator the input type in the translator
+ * declaration being different from the values being assigned inside.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int i;
+ char c;
+} *uvar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < int idontcare >
+{
+ myi = ((struct input_struct *) uvar)->i;
+ myi = ((struct input_struct *) uvar)->c;
+};
+
+BEGIN
+{
+ printf("Input type to the translator decl is different from members");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.OutputAliasTrans.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.OutputAliasTrans.d
new file mode 100644
index 000000000000..cd4715319913
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.OutputAliasTrans.d
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * The output type is an alias.
+ *
+ * SECTION: Translators/ Translator Declarations.
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int ii;
+ char ic;
+};
+
+struct output_struct {
+ int oi;
+ char oc;
+};
+
+typedef struct output_struct output_t;
+
+
+translator output_t < struct input_struct *ivar >
+{
+ oi = ((struct input_struct *) ivar)->ii;
+ oc = ((struct input_struct *) ivar)->ic;
+};
+
+BEGIN
+{
+ printf("Output type is an alias");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.PartialDereferencing.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.PartialDereferencing.d
new file mode 100644
index 000000000000..ae532cc4d1c7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.PartialDereferencing.d
@@ -0,0 +1,85 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * If you dereference a single member of the translation input, then the
+ * compiler will generate the code corresponding to that member
+ *
+ * SECTION: Translators/ Translate Operator
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int ii;
+ char ic;
+};
+
+struct output_struct {
+ int oi;
+ char oc;
+};
+
+
+translator struct output_struct < struct input_struct ivar >
+{
+ oi = ((struct input_struct) ivar).ii;
+ oc = ((struct input_struct) ivar).ic;
+};
+
+struct output_struct out;
+struct input_struct in;
+
+BEGIN
+{
+ in.ii = 100;
+ in.ic = 'z';
+
+ printf("Translating only a part of the input struct\n");
+ out.oi = xlate < struct output_struct > (in).oi;
+
+ printf("out.oi: %d\t out.oc: %d\n", out.oi, out.oc);
+}
+
+BEGIN
+/(100 != out.oi) || (0 != out.oc)/
+{
+ exit(1);
+}
+
+BEGIN
+/(100 == out.oi) && (0 == out.oc)/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.PartialOutputTransDefn.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.PartialOutputTransDefn.d
new file mode 100644
index 000000000000..9be52a9fc65a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.PartialOutputTransDefn.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * A translator declaration may omit expressions for one or more members
+ * of the output type
+ *
+ * SECTION: Translators/Translator Declarations;
+ * Translators/Translate Operator
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int ii;
+ char ic;
+};
+
+struct output_struct {
+ int oi;
+ char oc;
+};
+
+
+translator struct output_struct < struct input_struct *ivar >
+{
+ oi = ((struct input_struct *) ivar)->ii;
+};
+
+BEGIN
+{
+ printf("Translating only a part of the input struct");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.ProcModelTrans.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.ProcModelTrans.d
new file mode 100644
index 000000000000..ff313eca185f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.ProcModelTrans.d
@@ -0,0 +1,53 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Use the translators in /usr/lib/dtrace/procfs.d
+ *
+ * SECTION: Translators/ Translator Declarations
+ * SECTION: Translators/ Translate Operator
+ * SECTION: Translators/Process Model Translators
+ *
+ */
+
+#pragma D option quiet
+
+proc_t *T;
+
+BEGIN
+{
+ mypr_addr = xlate < psinfo_t > (T).pr_addr;
+ printf("pr_addr: %d", mypr_addr);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.RepeatDeclaration.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.RepeatDeclaration.d
new file mode 100644
index 000000000000..a928c3e20e7f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.RepeatDeclaration.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Reassign the members of the output struct using another translator
+ * input struct.
+ *
+ * SECTION: Translators/Translator Declarations
+ */
+
+#pragma D option quiet
+
+struct input_struct1 {
+ int ii1;
+ char ic1;
+} *ivar1;
+
+struct input_struct2 {
+ long ii2;
+ long ic2;
+} *ivar2;
+
+struct output_struct {
+ int oi;
+ char oc;
+};
+
+
+translator struct output_struct < struct input_struct1 *ivar1 >
+{
+ oi = ((struct input_struct1 *) ivar1)->ii1;
+ oc = ((struct input_struct1 *) ivar1)->ic1;
+};
+
+translator struct output_struct < struct input_struct2 *ivar2 >
+{
+ oi = ((struct input_struct2 *) ivar2)->ii2;
+ oc = ((struct input_struct2 *) ivar2)->ic2;
+};
+
+BEGIN
+{
+ printf("Reassignment of a struct's members with different input");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.SimultaneousTranslators.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.SimultaneousTranslators.d
new file mode 100644
index 000000000000..63cd72cafd39
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.SimultaneousTranslators.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Assign the different members of the output of the translator using
+ * different translator declarations.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct1 {
+ int ii1;
+ char ic1;
+} *ivar1;
+
+struct input_struct2 {
+ int ii2;
+ char ic2;
+} *ivar2;
+
+struct output_struct {
+ int oi;
+ char oc;
+};
+
+
+translator struct output_struct < struct input_struct1 *ivar1 >
+{
+ oi = ((struct input_struct1 *) ivar1)->ii1;
+};
+
+translator struct output_struct < struct input_struct2 *ivar2 >
+{
+ oc = ((struct input_struct2 *) ivar2)->ic2;
+};
+
+BEGIN
+{
+ printf("Translate members of output with different input structs");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.StructureAssignment.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.StructureAssignment.d
new file mode 100644
index 000000000000..277d95fed290
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.StructureAssignment.d
@@ -0,0 +1,85 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * If the entire output is copied by means of a structure assignment, any
+ * members for which no translation expressions are defined will be filled
+ * with zeroes.
+ *
+ * SECTION: Translators/ Translate Operator
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int ii;
+ char ic;
+};
+
+struct output_struct {
+ int oi;
+ char oc;
+};
+
+
+translator struct output_struct < struct input_struct ivar >
+{
+ oi = ((struct input_struct) ivar).ii;
+};
+
+struct output_struct out;
+struct input_struct in;
+
+BEGIN
+{
+ in.ii = 100;
+ in.ic = 'z';
+
+ printf("Translating via struct assignment\n");
+ out = xlate < struct output_struct > (in);
+
+ printf("out.oi: %d\t out.oc: %d\n", out.oi, out.oc);
+}
+
+BEGIN
+/(100 != out.oi) || (0 != out.oc)/
+{
+ exit(1);
+}
+
+BEGIN
+/(100 == out.oi) && (0 == out.oc)/
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh
new file mode 100644
index 000000000000..16eeda32916b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh
@@ -0,0 +1,62 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Test the output for stable translations.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -v -s /dev/stdin <<EOF
+
+#pragma D option quiet
+
+inline lwpsinfo_t *myinfo = xlate < lwpsinfo_t *> (curthread);
+
+#pragma D attributes Stable/Stable/Common myinfo
+
+BEGIN
+{
+ this->a = myinfo->pr_flag;
+ exit(0);
+}
+
+BEGIN
+{
+ exit(1);
+}
+EOF
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh.out
new file mode 100644
index 000000000000..43c1adb1a54f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh.out
@@ -0,0 +1,14 @@
+
+Stability attributes for script /dev/stdin:
+
+ Minimum Probe Description Attributes
+ Identifier Names: Unstable
+ Data Semantics: Unstable
+ Dependency Class: Common
+
+ Minimum Statement Attributes
+ Identifier Names: Stable
+ Data Semantics: Stable
+ Dependency Class: Common
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh
new file mode 100644
index 000000000000..82070cde9237
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh
@@ -0,0 +1,60 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Test the output of unstable translations.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -v -s /dev/stdin <<EOF
+
+#pragma D option quiet
+
+inline lwpsinfo_t *myinfo = xlate < lwpsinfo_t *> (curthread);
+
+BEGIN
+{
+ this->a = myinfo->pr_flag;
+ exit(0);
+}
+
+BEGIN
+{
+ exit(1);
+}
+EOF
+
+exit $?
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh.out
new file mode 100644
index 000000000000..f4b70f9573db
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh.out
@@ -0,0 +1,14 @@
+
+Stability attributes for script /dev/stdin:
+
+ Minimum Probe Description Attributes
+ Identifier Names: Unstable
+ Data Semantics: Unstable
+ Dependency Class: Common
+
+ Minimum Statement Attributes
+ Identifier Names: Private
+ Data Semantics: Private
+ Dependency Class: Unknown
+
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransNonPointer.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransNonPointer.d
new file mode 100644
index 000000000000..3ec81434e9a7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransNonPointer.d
@@ -0,0 +1,84 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Translate the input expression to output struct type
+ *
+ * SECTION: Translators/ Translator Declarations
+ * SECTION: Translators/ Translate Operator
+ *
+ */
+
+#pragma D option quiet
+
+struct myinput_struct {
+ int i;
+ char c;
+};
+
+struct myoutput_struct {
+ int myi;
+ char myc;
+};
+
+translator struct myoutput_struct < struct myinput_struct ivar >
+{
+ myi = ((struct myinput_struct ) ivar).i;
+ myc = ((struct myinput_struct ) ivar).c;
+
+};
+
+struct myinput_struct f;
+BEGIN
+{
+ f.i = 10;
+ f.c = 'c';
+
+ realmyi = xlate < struct myoutput_struct > (f).myi;
+ realmyc = xlate < struct myoutput_struct > (f).myc;
+}
+
+BEGIN
+/(10 != f.i) || ('c' != f.c)/
+{
+ exit(1);
+}
+
+BEGIN
+/(10 == f.i) && ('c' == f.c)/
+{
+ printf("realmyi: %d\n", realmyi);
+ printf("realmyc: %c\n", realmyc);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransOutputPointer.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransOutputPointer.d
new file mode 100644
index 000000000000..9069bf5d3aa5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransOutputPointer.d
@@ -0,0 +1,80 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Translate an input expression to a pointer to a struct
+ *
+ * SECTION: Translators/ Translator Declarations
+ * SECTION: Translators/ Translate Operator
+ *
+ */
+
+#pragma D option quiet
+
+struct myinput_struct {
+ int i;
+ char c;
+};
+
+struct myoutput_struct {
+ int myi;
+ char myc;
+};
+
+translator struct myoutput_struct < struct myinput_struct ivar >
+{
+ myi = ((struct myinput_struct ) ivar).i;
+ myc = ((struct myinput_struct ) ivar).c;
+
+};
+
+struct myinput_struct f;
+
+BEGIN
+{
+ f.i = 1203;
+ f.c = 'v';
+
+ realmyi = xlate < struct myoutput_struct *> (f)->myi;
+ realmyc = xlate < struct myoutput_struct *> (f)->myc;
+}
+
+BEGIN
+/(1203 != realmyi) || ('v' != realmyc)/
+{
+ printf("Failure");
+ exit(1);
+}
+
+BEGIN
+/(1203 == realmyi) && ('v' == realmyc)/
+{
+ printf("Success");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransPointer.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransPointer.d
new file mode 100644
index 000000000000..34d31d444e00
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TransPointer.d
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the normal declaration of translators.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct myinput_struct {
+ int i;
+ char c;
+};
+
+struct myoutput_struct {
+ int myi;
+ char myc;
+};
+
+translator struct myoutput_struct < struct myinput_struct *ivar >
+{
+ myi = ((struct myinput_struct *) ivar)->i;
+ myc = ((struct myinput_struct *) ivar)->c;
+
+};
+
+struct myinput_struct *f;
+
+BEGIN
+{
+ printf("Good translator defn");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TranslateSelf.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TranslateSelf.d
new file mode 100644
index 000000000000..9059093f33cd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.TranslateSelf.d
@@ -0,0 +1,76 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the translation of a struct to itself.
+ *
+ * SECTION: Translators/ Translator Declarations.
+ * SECTION: Translators/ Translate operator.
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < struct output_struct uvar >
+{
+ myi = ((struct output_struct ) uvar).myi;
+ myc = ((struct output_struct ) uvar).myc;
+};
+
+struct output_struct out;
+struct output_struct outer;
+
+BEGIN
+{
+ out.myi = 1234;
+ out.myc = 'a';
+
+ printf("Test translation of a struct to itself\n");
+ outer = xlate < struct output_struct > (out);
+
+ printf("outer.myi: %d\t outer.myc: %c\n", outer.myi, outer.myc);
+}
+
+BEGIN
+/(1234 != outer.myi) || ('a' != outer.myc)/
+{
+ exit(1);
+}
+
+BEGIN
+/(1234 == outer.myi) && ('a' == outer.myc)/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.UnionInputTrans.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.UnionInputTrans.d
new file mode 100644
index 000000000000..fb2dcf0938d4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.UnionInputTrans.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test the declaration of translators with a union to be the input type.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+union input_union {
+ int i;
+ char c;
+} *ivar;
+
+struct output_struct {
+ int myi;
+ char myc;
+};
+
+translator struct output_struct < union input_union *ivar >
+{
+ myi = ((union input_union *) ivar)->i;
+ myc = ((union input_union *) ivar)->c;
+
+};
+
+BEGIN
+{
+ printf("Translator definition good\n");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.UnionOutputTrans.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.UnionOutputTrans.d
new file mode 100644
index 000000000000..3b2c588d2aa9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/translators/tst.UnionOutputTrans.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * The output type in a translator definition can be a union.
+ *
+ * SECTION: Translators/Translator Declarations
+ *
+ *
+ */
+
+#pragma D option quiet
+
+struct input_struct {
+ int ii;
+ char ic;
+} *ivar;
+
+union output_union {
+ int oi;
+ char oc;
+};
+
+translator union output_union < struct input_struct *ivar >
+{
+ oi = ((struct input_struct *) ivar)->ii;
+ oc = ((struct input_struct *) ivar)->ic;
+
+};
+
+BEGIN
+{
+ printf("Test translator definition with union output");
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_DECL_IDRED.DupTypeDef.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_DECL_IDRED.DupTypeDef.d
new file mode 100644
index 000000000000..47a9fdfed730
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_DECL_IDRED.DupTypeDef.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * ASSERTION: Cannot redeclare identifier using typedef.
+ *
+ * SECTION: Type and Constant Definitions/Typedef
+ *
+ * NOTES:
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+typedef int new_int;
+
+BEGIN
+{
+ exit(0);
+}
+
+typedef char new_int;
+
+END
+{
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_SYNTAX.BadExistingTypedef.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_SYNTAX.BadExistingTypedef.d
new file mode 100644
index 000000000000..38521a05161e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_SYNTAX.BadExistingTypedef.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * ASSERTION:
+ * The typedef keyword throws an D_SYNTAX error when a bad existing type is
+ * used.
+ *
+ * SECTION: Type and Constant Definitions/Typedef
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+typedef pint new_int;
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_SYNTAX.TypedefInClause.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_SYNTAX.TypedefInClause.d
new file mode 100644
index 000000000000..0cb8cf733881
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/err.D_SYNTAX.TypedefInClause.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * ASSERTION:
+ * The typedef keyword can be used outside of the probe clauses only.
+ *
+ * SECTION: Type and Constant Definitions/Typedef
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ typedef int new_int;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/tst.ChainTypedef.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/tst.ChainTypedef.d
new file mode 100644
index 000000000000..00810a52f8f8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/tst.ChainTypedef.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION: An identifier used to alias a primitive data type can be further
+ * used to typedef other aliases. typedef is transitive.
+ *
+ * SECTION: Type and Constant Definitions/Typedef
+ *
+ * NOTES:
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+typedef int new_int;
+typedef new_int latest_int;
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/tst.TypedefDataAssign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/tst.TypedefDataAssign.d
new file mode 100644
index 000000000000..4565be5593ad
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/typedef/tst.TypedefDataAssign.d
@@ -0,0 +1,118 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Test the typedef keyword with the different D data types. Declare different
+ * data types and test some of them with values.
+ *
+ * SECTION: Type and Constant Definitions/Typedef
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+typedef char new_char;
+typedef short new_short;
+typedef int new_int;
+typedef long new_long;
+typedef long long new_long_long;
+typedef int8_t new_int8;
+typedef int16_t new_int16;
+typedef int32_t new_int32;
+typedef int64_t new_int64;
+typedef intptr_t new_intptr;
+typedef uint8_t new_uint8;
+typedef uint16_t new_uint16;
+typedef uint32_t new_uint32;
+typedef uint64_t new_uint64;
+typedef uintptr_t new_uintptr;
+typedef float new_float;
+typedef double new_double;
+typedef long double new_long_double;
+
+typedef int * pointer;
+
+typedef struct {
+ char ch;
+ int in;
+ long lg;
+} new_struct;
+
+typedef union {
+ char ch;
+ int in;
+ long lg;
+} new_union;
+
+typedef enum {
+ RED,
+ GREEN,
+ BLUE
+} new_enum;
+
+new_char c;
+new_short s;
+new_int i;
+new_long l;
+new_long_long ll;
+new_int8 i8;
+new_int16 i16;
+new_int32 i32;
+new_int64 i64;
+new_intptr iptr;
+new_uint8 ui8;
+new_uint16 ui16;
+new_uint32 ui32;
+new_uint64 ui64;
+new_uintptr uiptr;
+new_float f;
+new_double d;
+new_long_double ld;
+new_struct ns;
+new_union nu;
+new_enum ne;
+
+pointer p;
+
+BEGIN
+{
+ ns.ch = 'c';
+ ns.in = 4;
+ ns.lg = 4;
+
+ nu.ch = 'd';
+ nu.in = 5;
+ nu.lg = 5;
+
+ i = 10;
+
+ printf("Struct: %c, %d, %d\n", ns.ch, ns.in, ns.lg);
+ printf("Union: %c, %d, %d\n", nu.ch, nu.in, nu.lg);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CAST_INVAL.badcast.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CAST_INVAL.badcast.d
new file mode 100644
index 000000000000..13d58eac9570
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CAST_INVAL.badcast.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Test an illegal cast - make sure dtrace catches it.
+ *
+ * SECTION: Aggregations/Clearing aggregations
+ *
+ *
+ */
+
+
+BEGIN
+{
+ (char)trace(`kmem_flags);
+ exit();
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CG_DYN.ResultDynType.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CG_DYN.ResultDynType.d
new file mode 100644
index 000000000000..74f2d7011dae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CG_DYN.ResultDynType.d
@@ -0,0 +1,47 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * An expression cannot evaluate to result of dynamic type.
+ *
+ * SECTION: Errtag/D_CG_DYN
+ */
+
+#pragma D option quiet
+
+translator lwpsinfo_t < int i >
+{
+ pr_flag = i;
+};
+
+BEGIN
+{
+ xlate < lwpsinfo_t * > (0);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CHR_OFLOW.charconst.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CHR_OFLOW.charconst.d
new file mode 100644
index 000000000000..b158c3ca1c70
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_CHR_OFLOW.charconst.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * verify the use of multi-char constants in single quotes
+ *
+ * SECTION: Types, Operators, and Expressions/Constants
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ char_bad = 'abc\fefghi';
+
+ printf("decimal value = %d", char_bad);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_BADCLASS.bad.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_BADCLASS.bad.d
new file mode 100644
index 000000000000..5064a5916ffa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_BADCLASS.bad.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invalid class names should be handled as an error.
+ *
+ * SECTION: Types, Operators, and Expressions/Data Types and Sizes
+ *
+ */
+
+register x;
+
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_CHARATTR.badtype3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_CHARATTR.badtype3.d
new file mode 100644
index 000000000000..e1407bc45923
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_CHARATTR.badtype3.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invalid type name
+ *
+ * SECTION: Types, Operators, and Expressions/Data Types and Sizes
+ *
+ */
+
+
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ i = (char long)0;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_COMBO.badtype4.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_COMBO.badtype4.d
new file mode 100644
index 000000000000..e925a8607548
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_COMBO.badtype4.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invalid type name
+ *
+ * SECTION: Types, Operators, and Expressions/Data Types and Sizes
+ *
+ */
+
+
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ i = (char int)0;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_COMBO.badtype5.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_COMBO.badtype5.d
new file mode 100644
index 000000000000..b7a3b050af8e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_COMBO.badtype5.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invalid type name
+ *
+ * SECTION: Types, Operators, and Expressions/Data Types and Sizes
+ *
+ */
+
+
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ i = (double double)0;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENCONST.badeval.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENCONST.badeval.d
new file mode 100644
index 000000000000..5e1c19db4d46
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENCONST.badeval.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Attempt a bogus enum declaration by assigning a non-constant expression
+ * to an enumerator.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ */
+
+enum e {
+ TAG = "i am not an integer constant!"
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENOFLOW.enoflow.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENOFLOW.enoflow.d
new file mode 100644
index 000000000000..25e14a69f19f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENOFLOW.enoflow.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Define an enumerations with a overflow value.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ */
+
+enum e {
+ toobig = 2147483648
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENOFLOW.enuflow.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENOFLOW.enuflow.d
new file mode 100644
index 000000000000..3709cb2f6a5b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_ENOFLOW.enuflow.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Define an enumerations with a overflow value using negative value.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ */
+
+
+enum e {
+ toosmall = -2147483649
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_SCOPE.scopeop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_SCOPE.scopeop.d
new file mode 100644
index 000000000000..ddac451f03f7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_SCOPE.scopeop.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Using the scope operator in a declaration will result in a
+ * D_DECL_SCOPE error.
+ *
+ * SECTION: Variables/External Variables
+ *
+ */
+
+#pragma D option quiet
+
+int `xyz;
+
+BEGIN
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_USELESS.baddec.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_USELESS.baddec.d
new file mode 100644
index 000000000000..7e3606e0b99d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_DECL_USELESS.baddec.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Bad external declarations will result in a D_DECL_USELESS
+ * error.
+ *
+ * SECTION: Types, Operators, and Expressions/Data Types and Sizes
+ *
+ */
+
+extern int;
+
+BEGIN
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_ACT.badcond.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_ACT.badcond.d
new file mode 100644
index 000000000000..b139f9e7ecee
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_ACT.badcond.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Tracing functions may not be second and third expressions
+ * of a conditional expr.
+ *
+ * SECTION: Types, Operators, and Expressions/Conditional Expressions
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ i = 1;
+ x = i == 0 ? trace(0): trace(1);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_ARITH.badoperand.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_ARITH.badoperand.d
new file mode 100644
index 000000000000..9fefb170fee6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_ARITH.badoperand.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Arithmetic operations with a +/- must be followed by an arithmetic
+ * type.
+ *
+ * SECTION: Types, Operators, and Expressions/Arithmetic Operators
+ *
+ */
+
+
+
+BEGIN
+{
+ p = 123 + -trace(0);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INCOMPAT.badassign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INCOMPAT.badassign.d
new file mode 100644
index 000000000000..04815a9d6689
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INCOMPAT.badassign.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Assignment operators do not supported on all types
+ *
+ * SECTION: Types, Operators, and Expressions/Assignment Operators
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = 3;
+ a += "foobar";
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INT.badbitop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INT.badbitop.d
new file mode 100644
index 000000000000..a210ea15ea46
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INT.badbitop.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Bitwise operators not supported on all types
+ *
+ * SECTION: Types, Operators, and Expressions/Bitwise Operators
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+/"char" & "foo"/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INT.badshift.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INT.badshift.d
new file mode 100644
index 000000000000..978df1d43f70
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_INT.badshift.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Shift operators not supported on all types
+ *
+ * SECTION: Types, Operators, and Expressions/Bitwise Operators
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ x = "char" << 2;
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badcond.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badcond.d
new file mode 100644
index 000000000000..2972ac239295
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badcond.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Conditional expressions not supported on all types
+ *
+ * SECTION: Types, Operators, and Expressions/Conditional Expressions
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = "boo";
+ c = "boo" ? "should": "fail";
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badincop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badincop.d
new file mode 100644
index 000000000000..dfd5a315df13
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badincop.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Increment operators not supported on all types
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = "boo";
+ c = a++;
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badlogop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badlogop.d
new file mode 100644
index 000000000000..4f084c779166
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_OP_SCALAR.badlogop.d
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Logical operators not supported on all types
+ *
+ * SECTION: Types, Operators, and Expressions/Logical Operators
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+/"char" && "foo"/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_PROTO_LEN.badcond1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_PROTO_LEN.badcond1.d
new file mode 100644
index 000000000000..8e327509685b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_PROTO_LEN.badcond1.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Conditional expressions do not accept tracing functions in
+ * the second or third expression
+ *
+ * SECTION: Types, Operators, and Expressions/Conditional Expressions
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ a = "boo";
+ c = a == "boo" ? printf("error\n") : trace();
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badenum.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badenum.d
new file mode 100644
index 000000000000..3b5377595cff
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badenum.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test a bogus enum declaration using an invalid identifer.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ */
+
+
+enum foo`bar
+{
+
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badid.d
new file mode 100644
index 000000000000..a28182cdcc29
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badid.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Identifiers cannot begin with a digit
+ *
+ * SECTION: Types, Operators, and Expressions/Identifier Names and Keywords
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+int 0abc;
+
+BEGIN
+{
+ 0abc = 5;
+ printf("0abc is %d", 0abc);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badstruct.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badstruct.d
new file mode 100644
index 000000000000..6c57d215c055
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_SYNTAX.badstruct.d
@@ -0,0 +1,38 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Attempt a bogus struct declaration using an invalid identifer.
+ *
+ * SECTION: Structs and Unions/Structs
+ */
+
+struct foo`bar {
+
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.badtype1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.badtype1.d
new file mode 100644
index 000000000000..4f6d1e321d02
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.badtype1.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invalid type name
+ *
+ * SECTION: Types, Operators, and Expressions/Data Types and Sizes
+ *
+ */
+
+
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ i = (long short)0;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.badtype2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.badtype2.d
new file mode 100644
index 000000000000..f40e95f1d814
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.badtype2.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Invalid type name
+ *
+ * SECTION: Types, Operators, and Expressions/Data Types and Sizes
+ *
+ */
+
+
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ i = (short long)0;
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.dupenum.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.dupenum.d
new file mode 100644
index 000000000000..2282f2d885e9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.dupenum.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Attempt a bogus enum declaration that contains duplicated enumerator names.
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ */
+
+enum foo {
+ x = 3,
+ x = 4
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.dupstruct.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.dupstruct.d
new file mode 100644
index 000000000000..4102cd909ca5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_UNKNOWN.dupstruct.d
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Attempt a bogus struct declaration that contains duplicated member names.
+ *
+ * SECTION: Structs and Unions/Structs
+ */
+
+struct foo {
+ int x;
+ char x;
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_XLATE_REDECL.ResultDynType.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_XLATE_REDECL.ResultDynType.d
new file mode 100644
index 000000000000..f4e7dfd14fd2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/err.D_XLATE_REDECL.ResultDynType.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * An expression cannot evaluate to result of dynamic type.
+ *
+ * SECTION: Errtag/D_CG_DYN
+ */
+
+#pragma D option quiet
+
+translator lwpsinfo_t < kthread_t *T >
+{
+ pr_flag = T->t_flag;
+ pr_lwpid = T->t_tid;
+};
+
+BEGIN
+{
+ xlate < lwpsinfo_t * > (curthread);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.assignops.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.assignops.d
new file mode 100644
index 000000000000..6bc27b092dca
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.assignops.d
@@ -0,0 +1,82 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify assignment operators
+ *
+ * SECTION: Types, Operators, and Expressions/Assignment Operators
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ int_1 = 0x100;
+ int_2 = 0xf0f0;
+ int_3 = 0x0f0f;
+
+ intn = 0x1;
+
+ intn += int_1;
+ printf("%x\n", intn);
+ intn -= int_1;
+ printf("%x\n", intn);
+ intn *= int_1;
+ printf("%x\n", intn);
+ intn /= int_1;
+ printf("%x\n", intn);
+ intn %= int_1;
+ printf("%x\n", intn);
+ printf("\n");
+
+ intb = 0x0000;
+
+ intb |= (int_2 | intb);
+ printf("%x\n", intb);
+ intb &= (int_2 | int_3);
+ printf("%x\n", intb);
+ intb ^= (int_2 | int_3);
+ printf("%x\n", intb);
+ intb |= ~(intb);
+ printf("%x\n", intb);
+ printf("\n");
+
+ intb = int_2;
+
+ printf("%x\n", intb);
+ intb <<= 3;
+ printf("%x\n", intb);
+ intb >>= 3;
+ printf("%x\n", intb);
+
+ exit(0);
+
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.badshiftops.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.badshiftops.d
new file mode 100644
index 000000000000..ac3c014e6375
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.badshiftops.d
@@ -0,0 +1,49 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Negative values and values greater than the LH operand are
+ * accepted.
+ *
+ * SECTION: Types, Operators, and Expressions/Bitwise Operators
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ int_1 = 0xffff;
+
+ nint = int_1 << -6;
+ printf("%x %x\n", int_1, nint);
+ nint = int_1 << 100;
+ printf("%x %x\n", int_1, nint);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.basics.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.basics.d
new file mode 100644
index 000000000000..8e762d5bc152
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.basics.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test declaration processing of all the fundamental kinds of type
+ * declarations. Check their sizes.
+ *
+ * SECTION: Types, Operators, and Expressions/Data Types and Sizes
+ */
+
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("\nsizeof (char) = %u\n", sizeof (char));
+ printf("sizeof (signed char) = %u\n", sizeof (signed char));
+ printf("sizeof (unsigned char) = %u\n", sizeof (unsigned char));
+ printf("sizeof (short) = %u\n", sizeof (short));
+ printf("sizeof (signed short) = %u\n", sizeof (signed short));
+ printf("sizeof (unsigned short) = %u\n", sizeof (unsigned short));
+ printf("sizeof (int) = %u\n", sizeof (int));
+ printf("sizeof (signed int) = %u\n", sizeof (signed int));
+ printf("sizeof (unsigned int) = %u\n", sizeof (unsigned int));
+ printf("sizeof (long long) = %u\n", sizeof (long long));
+ printf("sizeof (signed long long) = %u\n", sizeof (signed long long));
+ printf("sizeof (unsigned long long) = %u\n",
+ sizeof (unsigned long long));
+ printf("sizeof (float) = %u\n", sizeof (float));
+ printf("sizeof (double) = %u\n", sizeof (double));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.basics.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.basics.d.out
new file mode 100644
index 000000000000..fd05217f82e5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.basics.d.out
@@ -0,0 +1,16 @@
+
+sizeof (char) = 1
+sizeof (signed char) = 1
+sizeof (unsigned char) = 1
+sizeof (short) = 2
+sizeof (signed short) = 2
+sizeof (unsigned short) = 2
+sizeof (int) = 4
+sizeof (signed int) = 4
+sizeof (unsigned int) = 4
+sizeof (long long) = 8
+sizeof (signed long long) = 8
+sizeof (unsigned long long) = 8
+sizeof (float) = 4
+sizeof (double) = 8
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.bitops.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.bitops.d
new file mode 100644
index 000000000000..fc643bab9c34
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.bitops.d
@@ -0,0 +1,62 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify relational operators with pointers
+ *
+ * SECTION: Types, Operators, and Expressions/Bitwise Operators
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ int_1 = 0xffff;
+ int_2 = 0;
+ int_3 = 0x0f0f;
+
+
+ printf("%x %x %x\n", int_1 & int_2, int_1 & int_3, int_2 & int_3);
+ printf("%x %x %x\n", int_1 | int_2, int_1 | int_3, int_2 | int_3);
+ printf("%x %x %x\n", int_1 ^ int_2, int_1 ^ int_3, int_2 ^ int_3);
+
+ printf("%x\n", int_1 & int_2 & int_3);
+ printf("%x\n", int_1 & int_2 ^ int_3);
+ printf("%x\n", int_1 & int_2 | int_3);
+ printf("%x\n", int_1 | int_2 & int_3);
+ printf("%x\n", int_1 | int_2 ^ int_3);
+ printf("%x\n", int_1 | int_2 | int_3);
+ printf("%x\n", int_1 ^ int_2 & int_3);
+ printf("%x\n", int_1 ^ int_2 ^ int_3);
+ printf("%x\n", int_1 ^ int_2 | int_3);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.charconstants.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.charconstants.d
new file mode 100644
index 000000000000..84aa61bfbc74
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.charconstants.d
@@ -0,0 +1,68 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * verify the use of char constants
+ *
+ * SECTION: Types, Operators, and Expressions/Constants
+ *
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ char_1 = 'a';
+ char_2 = '\"';
+ char_3 = '\"\ba';
+ char_4 = '\?';
+ char_5 = '\'';
+ char_6 = '\\';
+ char_7 = '\0103';
+ char_8 = '\x4E';
+ char_9 = '\c'; /* Note - this is not an escape sequence */
+ char_10 = 'ab\"d';
+ char_11 = 'a\bcdefgh';
+
+ printf("decimal value = %d; character value = %c\n", char_1, char_1);
+ printf("decimal value = %d; character value = %c\n", char_2, char_2);
+ printf("decimal value = %d; character value = %c\n", char_3, char_3);
+ printf("decimal value = %d; character value = %c\n", char_4, char_4);
+ printf("decimal value = %d; character value = %c\n", char_5, char_5);
+ printf("decimal value = %d; character value = %c\n", char_6, char_6);
+ printf("decimal value = %d; character value = %c\n", char_7, char_7);
+ printf("decimal value = %d; character value = %c\n", char_8, char_8);
+ printf("decimal value = %d; character value = %c\n", char_9, char_9);
+ printf("decimal value = %d; character value = %c\n", char_10, char_10);
+ printf("decimal value = %d\n", char_11);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.complex.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.complex.d
new file mode 100644
index 000000000000..a912670af2af
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.complex.d
@@ -0,0 +1,74 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Test a complex structure and verify that tracemem can be used to
+ * look at it.
+ *
+ * SECTION: Structs and Unions/Structs;
+ * Actions and Subroutines/tracemem()
+ */
+
+
+
+#pragma D option quiet
+
+struct s {
+ int i;
+ char c;
+ double d;
+ float f;
+ long l;
+ long long ll;
+ union sigval u;
+ enum uio_rw e;
+ struct vnode s;
+ struct s1 {
+ int i;
+ char c;
+ double d;
+ float f;
+ long l;
+ long long ll;
+ union sigval u;
+ enum uio_rw e;
+ struct vnode s;
+ } sx;
+ int a[2];
+ int *p;
+ int *ap[4];
+ int (*fp)();
+ int (*afp[2])();
+};
+
+BEGIN
+{
+ tracemem(curthread, sizeof (struct s));
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.condexpr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.condexpr.d
new file mode 100644
index 000000000000..fe23a73b720f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.condexpr.d
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * positive check conditional expressions
+ *
+ * SECTION: Types, Operators, and Expressions/Conditional Expressions
+ *
+ * NOTES: these tests are from the User's Guide
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ i = 0;
+ x = i == 0 ? "zero" : "non-zero";
+
+ c = 'd';
+ hexval = (c >= '0' && c <= '9') ? c - '0':
+ (c >= 'a' && c <= 'z') ? c + 10 - 'a' : c + 10 - 'A';
+}
+
+tick-1
+/x == "zero" && hexval == 13/
+{
+ exit(0);
+}
+
+tick-1
+/x != "zero" || hexval != 13/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.const.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.const.d
new file mode 100644
index 000000000000..dae3d9041ed3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.const.d
@@ -0,0 +1,29 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * Make sure we can scope types with modifiers.
+ */
+
+BEGIN
+{
+ trace((D`int *)0);
+ trace((const D`int *)0);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.constants.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.constants.d
new file mode 100644
index 000000000000..101bb8b8281f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.constants.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * verify that integer constants can be written in decimal
+ * octal or hexadecimal
+ *
+ * SECTION: Types, Operators, and Expressions/Constants
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ decimal = 12345;
+ octal = 012345;
+ hexadecimal_1 = 0x12345;
+ hexadecimal_2 = 0X12345;
+
+ printf("%d %d %d %d", decimal, octal, hexadecimal_1, hexadecimal_2);
+ printf("%d %o %x %x", decimal, octal, hexadecimal_1, hexadecimal_2);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.conv.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.conv.d
new file mode 100644
index 000000000000..9020424572b3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.conv.d
@@ -0,0 +1,109 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * positive type conversion checks
+ *
+ * SECTION: Types, Operators, and Expressions/Type Conversions
+ *
+ * NOTES: not all type conversions are checked. A lot of this section
+ * is tested within other tests.
+ */
+
+#pragma D option quiet
+
+unsigned int i;
+char c;
+short s;
+long l;
+long long ll;
+
+BEGIN
+{
+/* char -> int */
+ c = 'A';
+ i = c;
+ printf("c is %c i is %d\n", c, i);
+
+/* int -> char */
+
+ i = 1601;
+ c = i;
+ printf("i is %d c is %c\n", i, c);
+
+/* char -> short */
+ c = 'A';
+ s = c;
+ printf("c is %c s is %d\n", c, s);
+
+/* short -> char */
+
+ s = 1601;
+ c = s;
+ printf("s is %d c is %c\n", s, c);
+
+/* int -> short */
+
+ i = 1601;
+ s = i;
+ printf("i is %d s is %d\n", i, s);
+
+/* short -> int */
+
+ s = 1601;
+ i = s;
+ printf("s is %d i is %d\n", s, i);
+
+/* int -> long long */
+
+ i = 4294967295;
+ ll = i;
+ printf("i is %d ll is %x\n", i, ll);
+
+/* long long -> int */
+
+ ll = 8589934591;
+ i = ll;
+ printf("ll is %d i is %x\n", ll, i);
+
+/* char -> long long */
+
+ c = 'A';
+ ll = c;
+ printf("c is %c ll is %x\n", c, ll);
+
+/* long long -> char */
+
+ ll = 8589934401;
+ c = ll;
+ printf("ll is %x c is %c\n", ll, c);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.enum.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.enum.d
new file mode 100644
index 000000000000..49a97bff6f3e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.enum.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Positive enumeration test
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ */
+
+#pragma D option quiet
+
+enum my_enum {
+ zero,
+ one = 1,
+ two,
+ three,
+ four = 4,
+ minimum = -2147483648,
+ maximum = 2147483647
+};
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.intincop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.intincop.d
new file mode 100644
index 000000000000..77eb7025978a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.intincop.d
@@ -0,0 +1,70 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify increment operator using integers
+ *
+ * SECTION: Type and Constant Definitions/Enumerations
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ int_orig = 100;
+ int_pos = 100+1;
+ int_neg = 100-1;
+
+ int_pos_before = ++int_orig;
+ int_orig = 100;
+ int_neg_before = --int_orig;
+ int_orig = 100;
+ int_pos_after = int_orig++;
+ int_orig = 100;
+ int_neg_after = int_orig--;
+ int_orig = 100;
+
+}
+
+tick-1
+/int_pos_before == int_pos && int_neg_before == int_neg &&
+ int_pos_after == int_orig && int_pos_after == int_orig/
+{
+ exit(0);
+}
+
+
+tick-1
+/int_pos_before != int_pos || int_neg_before != int_neg ||
+ int_pos_after != int_orig || int_pos_after != int_orig/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.intops.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.intops.d
new file mode 100644
index 000000000000..a374480440ae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.intops.d
@@ -0,0 +1,70 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify relational operators with integers
+ *
+ * SECTION: Types, Operators, and Expressions/Relational Operators;
+ * Types, Operators, and Expressions/Precedence
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ int_1 = 0x100;
+ int_2 = 0x101;
+ int_3 = 0x99;
+}
+
+tick-1
+/int_1 >= int_2 || int_2 <= int_1 || int_1 == int_2/
+{
+ printf("Shouldn't end up here (1)\n");
+ printf("int_1 = %x int_2 = %x int_3 = %x\n",
+ (int) int_1, (int) int_2, (int) int_3);
+ exit(1);
+}
+
+tick-1
+/int_3 > int_1 || int_1 < int_3 || int_3 == int_1/
+{
+ printf("Shouldn't end up here (2)\n");
+ printf("int_1 = %x int_2 = %x int_3 = %x\n",
+ (int) int_1, (int) int_2, (int) int_3);
+ exit(1);
+}
+
+tick-1
+/int_2 > int_3 && int_1 < int_2 ^^ int_3 == int_2 && !(int_1 != int_2)/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.inttypes.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.inttypes.d
new file mode 100644
index 000000000000..80bfa1f2975b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.inttypes.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * Verify integer type aliases
+ *
+ * SECTION: Types, Operators, and Expressions/Data Types and Sizes
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+BEGIN
+{
+ printf("sizeof (int8_t) = %u\n", sizeof (int8_t));
+ printf("sizeof (int16_t) = %u\n", sizeof (int16_t));
+ printf("sizeof (int32_t) = %u\n", sizeof (int32_t));
+ printf("sizeof (int64_t) = %u\n", sizeof (int64_t));
+ printf("sizeof (intptr_t) = %u\n", sizeof (intptr_t));
+ printf("sizeof (uint8_t) = %u\n", sizeof (uint8_t));
+ printf("sizeof (uint16_t) = %u\n", sizeof (uint16_t));
+ printf("sizeof (uint32_t) = %u\n", sizeof (uint32_t));
+ printf("sizeof (uint64_t) = %u\n", sizeof (uint64_t));
+ printf("sizeof (uintptr_t) = %u\n", sizeof (uintptr_t));
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.ptrincop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.ptrincop.d
new file mode 100644
index 000000000000..0fdd561a8208
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.ptrincop.d
@@ -0,0 +1,72 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify increment/decrement operator using pointers
+ *
+ * SECTION: Types, Operators, and Expressions/Increment and Decrement Operators
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ ptr_orig = &`kmem_flags;
+ ptr_pos = &`kmem_flags+1;
+ ptr_neg = &`kmem_flags-1;
+
+ ptr_pos_before = ++ptr_orig;
+ ptr_orig = &`kmem_flags;
+ ptr_neg_before = --ptr_orig;
+
+ ptr_orig = &`kmem_flags;
+ ptr_pos_after = ptr_orig++;
+ ptr_orig = &`kmem_flags;
+ ptr_neg_after = ptr_orig--;
+ ptr_orig = &`kmem_flags;
+
+}
+
+tick-1
+/ptr_pos_before == ptr_pos && ptr_neg_before == ptr_neg &&
+ ptr_pos_after == ptr_orig && ptr_pos_after == ptr_orig/
+{
+ exit(0);
+}
+
+
+tick-1
+/ptr_pos_before != ptr_pos || ptr_neg_before != ptr_neg ||
+ ptr_pos_after != ptr_orig || ptr_pos_after != ptr_orig/
+{
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.ptrops.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.ptrops.d
new file mode 100644
index 000000000000..d4144b09ce21
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.ptrops.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify relational operators with pointers
+ *
+ * SECTION: Types, Operators, and Expressions/Relational Operators;
+ * Types, Operators, and Expressions/Logical Operators;
+ * Types, Operators, and Expressions/Precedence
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ ptr_1 = &`kmem_flags;
+ ptr_2 = (&`kmem_flags) + 1;
+ ptr_3 = (&`kmem_flags) - 1 ;
+}
+
+tick-1
+/ptr_1 >= ptr_2 || ptr_2 <= ptr_1 || ptr_1 == ptr_2/
+{
+ printf("Shouldn't end up here (1)\n");
+ printf("ptr_1 = %x ptr_2 = %x ptr_3 = %x\n",
+ (int) ptr_1, (int) ptr_2, (int) ptr_3);
+ exit(1);
+}
+
+tick-1
+/ptr_3 > ptr_1 || ptr_1 < ptr_3 || ptr_3 == ptr_1/
+{
+ printf("Shouldn't end up here (2)\n");
+ printf("ptr_1 = %x ptr_2 = %x ptr_3 = %x\n",
+ (int) ptr_1, (int) ptr_2, (int) ptr_3);
+ exit(1);
+}
+
+tick-1
+/ptr_3 > ptr_2 || ptr_1 < ptr_2 ^^ ptr_3 == ptr_2 && !(ptr_1 != ptr_2)/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.relenum.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.relenum.d
new file mode 100644
index 000000000000..8fa6d585d3ae
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.relenum.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify relational operators with enumerations
+ *
+ * SECTION: Types, Operators, and Expressions/Relational Operators
+ *
+ */
+
+#pragma D option quiet
+
+enum numbers_1 {
+ zero,
+ one,
+ two
+};
+
+enum numbers_2 {
+ null,
+ first,
+ second
+};
+
+tick-1
+/zero >= one || second <= first || zero == second/
+{
+ printf("Shouldn't end up here (1)\n");
+ printf("zero = %d; one = %d; two = %d", zero, one, two);
+ printf("null = %d; first = %d; second = %d", null, first, second);
+ exit(1);
+}
+
+tick-1
+/second < one || two > second || null == first/
+{
+ printf("Shouldn't end up here (2)\n");
+ printf("zero = %d; one = %d; two = %d", zero, one, two);
+ printf("null = %d; first = %d; second = %d", null, first, second);
+ exit(1);
+}
+
+tick-1
+/first < two && second > one && one != two && zero != first/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.relstring.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.relstring.d
new file mode 100644
index 000000000000..9e9ef29d4c8e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.relstring.d
@@ -0,0 +1,70 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify relational operators with strings
+ *
+ * SECTION: Types, Operators, and Expressions/Relational Operators
+ *
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ string_1 = "abcde";
+ string_2 = "aabcde";
+ string_3 = "abcdef";
+}
+
+tick-1
+/string_1 <= string_2 || string_2 >= string_1 || string_1 == string_2/
+{
+ printf("Shouldn't end up here (1)\n");
+ printf("string_1 = %s string_2 = %s string_3 = %s\n",
+ string_1, string_2, string_3);
+ exit(1);
+}
+
+tick-1
+/string_3 < string_1 || string_1 > string_3 || string_3 == string_1/
+{
+ printf("Shouldn't end up here (2)\n");
+ printf("string_1 = %s string_2 = %s string_3 = %s n",
+ string_1, string_2, string_3);
+ exit(1);
+}
+
+tick-1
+/string_3 > string_1 && string_1 > string_2 &&
+ string_1 != string_2 && string_2 != string_3/
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.shiftops.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.shiftops.d
new file mode 100644
index 000000000000..a26023850f66
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.shiftops.d
@@ -0,0 +1,62 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify shift operators
+ *
+ * SECTION: Types, Operators, and Expressions/Bitwise Operators;
+ * Types, Operators, and Expressions/Precedence
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ int_1 = 0xffff;
+
+ nint = (((((((((((int_1 << 2 >> 2) << 3 >> 3) << 4 >> 4) << 5 >> 5)
+ << 6 >> 6) << 7 >> 7) << 8 >>8) << 9 >> 9) << 10 >> 10)
+ << 11 >> 11) << 12 >> 12);
+
+}
+
+tick-1
+/nint != int_1/
+{
+ printf("Unexpected error nint = %x, expected %x\n", nint, int_1);
+ exit(1);
+}
+
+tick-1
+/nint == int_1/
+{
+ exit(0);
+
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.stringconstants.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.stringconstants.d
new file mode 100644
index 000000000000..9fa080569309
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.stringconstants.d
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * verify the use of char type
+ *
+ * SECTION: Types, Operators, and Expressions/Constants
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+string string_1;
+
+BEGIN
+{
+ string_1 = "abcd\n\n\nefg";
+ string_2 = "abc\"\t\044\?\x4D";
+ string_3 = "\?\\\'\"\0";
+
+ printf("string_1 = %s\n", string_1);
+ printf("string_2 = %s\n", string_2);
+ printf("string_3 = %s\n", string_3);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.struct.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.struct.d
new file mode 100644
index 000000000000..86610f63fe13
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.struct.d
@@ -0,0 +1,84 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declare a dynamic type and then use it to copyin the first 3 environment
+ * variable pointers from the current process.
+ *
+ * SECTION: Structs and Unions/Structs;
+ * Actions and Subroutines/copyin();
+ * Actions and Subroutines/copyinstr();
+ * Variables/External Variables
+ *
+ * NOTES:
+ * This test program declares a dynamic type and then uses it to copyin the
+ * first three environment variable pointers from the current process. We
+ * then use the dynamic type to access the result of our copyin(). The
+ * special "D" module type scope is also tested.
+ */
+
+#pragma D option quiet
+
+struct env_vars_32 {
+ uint32_t e1;
+ uint32_t e2;
+ uint32_t e3;
+};
+
+struct env_vars_64 {
+ uint64_t e1;
+ uint64_t e2;
+ uint64_t e3;
+};
+
+BEGIN
+/curpsinfo->pr_dmodel == PR_MODEL_ILP32/
+{
+ e32 = (struct D`env_vars_32 *)
+ copyin(curpsinfo->pr_envp, sizeof (struct D`env_vars_32));
+
+ printf("e1 = \"%s\"\n", stringof(copyinstr(e32->e1)));
+ printf("e2 = \"%s\"\n", stringof(copyinstr(e32->e2)));
+ printf("e3 = \"%s\"\n", stringof(copyinstr(e32->e3)));
+
+ exit(0);
+}
+
+BEGIN
+/curpsinfo->pr_dmodel == PR_MODEL_LP64/
+{
+ e64 = (struct D`env_vars_64 *)
+ copyin(curpsinfo->pr_envp, sizeof (struct D`env_vars_64));
+
+ printf("e1 = \"%s\"\n", stringof(copyinstr(e64->e1)));
+ printf("e2 = \"%s\"\n", stringof(copyinstr(e64->e2)));
+ printf("e3 = \"%s\"\n", stringof(copyinstr(e64->e3)));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.typedef.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.typedef.d
new file mode 100644
index 000000000000..aabfc9ba78d4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.typedef.d
@@ -0,0 +1,85 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declares a dynamic type and then uses it to copyin the first three
+ * environment variable pointers from the current process.
+ *
+ * SECTION: Structs and Unions/Structs;
+ * Actions and Subroutines/copyin();
+ * Actions and Subroutines/copyinstr();
+ * Variables/External Variables
+ *
+ * NOTES:
+ * This test program declares a dynamic type and then uses it to copyin the
+ * first three environment variable pointers from the current process. We
+ * then use the dynamic type to access the result of our copyin(). The
+ * special "D" module type scope is also tested. This is similar to our
+ * struct declaration test but here we use a typedef.
+ */
+
+#pragma D option quiet
+
+typedef struct env_vars_32 {
+ uint32_t e1;
+ uint32_t e2;
+ uint32_t e3;
+} env_vars_32_t;
+
+typedef struct env_vars_64 {
+ uint64_t e1;
+ uint64_t e2;
+ uint64_t e3;
+} env_vars_64_t;
+
+BEGIN
+/curpsinfo->pr_dmodel == PR_MODEL_ILP32/
+{
+ e32 = (D`env_vars_32_t *)
+ copyin(curpsinfo->pr_envp, sizeof (D`env_vars_32_t));
+
+ printf("e1 = \"%s\"\n", stringof(copyinstr(e32->e1)));
+ printf("e2 = \"%s\"\n", stringof(copyinstr(e32->e2)));
+ printf("e3 = \"%s\"\n", stringof(copyinstr(e32->e3)));
+
+ exit(0);
+}
+
+BEGIN
+/curpsinfo->pr_dmodel == PR_MODEL_LP64/
+{
+ e64 = (D`env_vars_64_t *)
+ copyin(curpsinfo->pr_envp, sizeof (D`env_vars_64_t));
+
+ printf("e1 = \"%s\"\n", stringof(copyinstr(e64->e1)));
+ printf("e2 = \"%s\"\n", stringof(copyinstr(e64->e2)));
+ printf("e3 = \"%s\"\n", stringof(copyinstr(e64->e3)));
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.unaryop.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.unaryop.d
new file mode 100644
index 000000000000..b9938e4ff18d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/types/tst.unaryop.d
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify unary operator
+ *
+ * SECTION: Types, Operators, and Expressions/Bitwise Operators
+ */
+
+#pragma D option quiet
+
+
+BEGIN
+{
+ int_1 = 0xffff;
+ int_2 = 0;
+ int_3 = 0x0f0f;
+
+ printf("%x %x %x\n", int_1, int_2, int_3);
+ printf("%x %x %x\n", ~int_1, ~int_2, ~int_3);
+ printf("%x %x %x\n", ~~int_1, ~~int_2, ~~int_3);
+ printf("%x %x %x\n", ~~~int_1, ~~~int_2, ~~~int_3);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid.d
new file mode 100644
index 000000000000..4865d81ee1e9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid.d
@@ -0,0 +1,21 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ trace((pidfoo`int)0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid2.d
new file mode 100644
index 000000000000..bafed1217279
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid2.d
@@ -0,0 +1,21 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ trace((pid8foo`int)0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid3.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid3.d
new file mode 100644
index 000000000000..fb9443a828ea
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidpid3.d
@@ -0,0 +1,21 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ trace((pid0`int)0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidtype.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidtype.ksh
new file mode 100644
index 000000000000..432a9fccb44f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidtype.ksh
@@ -0,0 +1,35 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# While it's hard to be completely certain that a type of the name we want
+# doesn't exist, we're going to try to pick a name which is rather unique.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="season_8_mountain_of_madness_t"
+pid=$$
+
+$dtrace -n "BEGIN{ trace(pid$pid\`$t)0); }"
+rc=$?
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidtype2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidtype2.ksh
new file mode 100644
index 000000000000..d1b48769ba6c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.invalidtype2.ksh
@@ -0,0 +1,36 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# While it's hard to be completely certain that a type of the name we want
+# doesn't exist, we're going to try to pick a name which is rather
+# unique. This time we're also going to use the pid$target alias.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="season_8_mountain_of_madness_t"
+pid=$$
+
+$dtrace -n "BEGIN{ trace(pid$pid\`$t)0); }" -p $pid
+rc=$?
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.user64mode.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.user64mode.ksh
new file mode 100644
index 000000000000..4eaf169f06dd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/err.user64mode.ksh
@@ -0,0 +1,90 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# This test is purposefully using a 64-bit DTrace and thus 64-bit types
+# when compared with a 32-bit process. This test uses the userland
+# keyword and so the implicit copyin should access illegal memory and
+# thus exit.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="zelda_info_t"
+exe="tst.chasestrings.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -ne 0 ]]; then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -64 -qs /dev/stdin <<EOF
+typedef struct info {
+ char *zi_gamename;
+ int zi_ndungeons;
+ char *zi_villain;
+ int zi_haszelda;
+} info_t;
+
+pid$pid::has_princess:entry
+/next == 0/
+{
+ this->t = (userland info_t *)arg0;
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ stringof(this->t->zi_gamename), this->t->zi_ndungeons,
+ stringof(this->t->zi_villain), this->t->zi_haszelda);
+ next = 1;
+}
+
+pid$pid::has_dungeons:entry
+/next == 1/
+{
+ this->t = (userland info_t *)arg0;
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ stringof(this->t->zi_gamename), this->t->zi_ndungeons,
+ stringof(this->t->zi_villain), this->t->zi_haszelda);
+ next = 2;
+}
+
+pid$pid::has_villain:entry
+/next == 2/
+{
+ this->t = (userland info_t *)arg0;
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ stringof(this->t->zi_gamename), this->t->zi_ndungeons,
+ stringof(this->t->zi_villain), this->t->zi_haszelda);
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
+EOF
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.aouttype.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.aouttype.c
new file mode 100644
index 000000000000..a4d25f8ca872
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.aouttype.c
@@ -0,0 +1,46 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 (c) Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * This test tries to make sure that we have CTF data for a type that only this
+ * binary would reasonably have. In this case, the
+ * season_7_lisa_the_vegetarian_t.
+ */
+#include <unistd.h>
+
+typedef struct season_7_lisa_the_vegetarian {
+ int fr_salad;
+} season_7_lisa_the_vegetarian_t;
+
+int
+sleeper(season_7_lisa_the_vegetarian_t *lp)
+{
+ for (;;) {
+ sleep(lp->fr_salad);
+ }
+ /*NOTREACHED*/
+ return (0);
+}
+
+int
+main(void)
+{
+ season_7_lisa_the_vegetarian_t l;
+ l.fr_salad = 100;
+
+ sleeper(&l);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.aouttype.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.aouttype.ksh
new file mode 100644
index 000000000000..95b26c82d7ab
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.aouttype.ksh
@@ -0,0 +1,45 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# Lookup a type that is inside a.out.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="season_7_lisa_the_vegetarian_t *"
+exe="tst.aouttype.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -ne 0 ]]; then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -n "BEGIN{ trace((pid$pid\`$t)0); exit(0); }"
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.c
new file mode 100644
index 000000000000..595a7cb6c575
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.c
@@ -0,0 +1,79 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 (c) Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * This test takes data from the current binary which is basically running in a
+ * loop between two functions and our goal is to have two unique types that they
+ * contain which we can print.
+ */
+
+#include <unistd.h>
+
+typedef struct zelda_info {
+ char *zi_gamename;
+ int zi_ndungeons;
+ char *zi_villain;
+ int zi_haszelda;
+} zelda_info_t;
+
+static int
+has_princess(zelda_info_t *z)
+{
+ return (z->zi_haszelda);
+}
+
+static int
+has_dungeons(zelda_info_t *z)
+{
+ return (z->zi_ndungeons != 0);
+}
+
+static const char *
+has_villain(zelda_info_t *z)
+{
+ return (z->zi_villain);
+}
+
+int
+main(void)
+{
+ zelda_info_t oot;
+ zelda_info_t la;
+ zelda_info_t lttp;
+
+ oot.zi_gamename = "Ocarina of Time";
+ oot.zi_ndungeons = 10;
+ oot.zi_villain = "Ganondorf";
+ oot.zi_haszelda = 1;
+
+ la.zi_gamename = "Link's Awakening";
+ la.zi_ndungeons = 9;
+ la.zi_villain = "Nightmare";
+ la.zi_haszelda = 0;
+
+ lttp.zi_gamename = "A Link to the Past";
+ lttp.zi_ndungeons = 12;
+ lttp.zi_villain = "Ganon";
+ lttp.zi_haszelda = 1;
+
+ for (;;) {
+ (void) has_princess(&oot);
+ (void) has_dungeons(&la);
+ (void) has_villain(&lttp);
+ sleep(1);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.ksh
new file mode 100644
index 000000000000..d754c194b4b4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.ksh
@@ -0,0 +1,76 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# This test is checking that we can read members and that pointers inside
+# members point to valid data that is intelligible, eg. strings.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="zelda_info_t"
+exe="tst.chasestrings.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -ne 0 ]]; then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -qs /dev/stdin <<EOF
+pid$pid::has_princess:entry
+/next == 0/
+{
+ this->t = (pid$pid\`$t *)(copyin(arg0, sizeof (pid$pid\`$t)));
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ copyinstr((uintptr_t)this->t->zi_gamename), this->t->zi_ndungeons,
+ copyinstr((uintptr_t)this->t->zi_villain), this->t->zi_haszelda);
+ next = 1;
+}
+
+pid$pid::has_dungeons:entry
+/next == 1/
+{
+ this->t = (pid$pid\`$t *)(copyin(arg0, sizeof (pid$pid\`$t)));
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ copyinstr((uintptr_t)this->t->zi_gamename), this->t->zi_ndungeons,
+ copyinstr((uintptr_t)this->t->zi_villain), this->t->zi_haszelda);
+ next = 2;
+}
+
+pid$pid::has_villain:entry
+/next == 2/
+{
+ this->t = (pid$pid\`$t *)(copyin(arg0, sizeof (pid$pid\`$t)));
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ copyinstr((uintptr_t)this->t->zi_gamename), this->t->zi_ndungeons,
+ copyinstr((uintptr_t)this->t->zi_villain), this->t->zi_haszelda);
+ exit(0);
+}
+EOF
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.ksh.out
new file mode 100644
index 000000000000..219e406e61d6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.chasestrings.ksh.out
@@ -0,0 +1,4 @@
+game: Ocarina of Time, dungeon: 10, villain: Ganondorf, zelda: 1
+game: Link's Awakening, dungeon: 9, villain: Nightmare, zelda: 0
+game: A Link to the Past, dungeon: 12, villain: Ganon, zelda: 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.libtype.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.libtype.c
new file mode 100644
index 000000000000..916a5b51b949
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.libtype.c
@@ -0,0 +1,29 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 (c) Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * We're linked against libc which has types, though we do not.
+ */
+#include <unistd.h>
+
+int
+main(void)
+{
+ for (;;) {
+ sleep(1000);
+ }
+ /*NOTREACHED*/
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.libtype.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.libtype.ksh
new file mode 100644
index 000000000000..233616619e7d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.libtype.ksh
@@ -0,0 +1,46 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# Here we want to make sure that the program in question does not have ctf data
+# in its a.out; however, we can get types out of a linked libc.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="int"
+exe="tst.libtype.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -eq 0 ]]; then
+ echo "CTF exists in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -n "BEGIN{ trace((pid$pid\`$t)0); exit(0); }"
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.linkmap.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.linkmap.ksh
new file mode 100644
index 000000000000..f767def53de8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.linkmap.ksh
@@ -0,0 +1,44 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# We should be able to see both strstr from libc and from ld on an
+# alternate linkmap.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -q -p $$ -s /dev/stdin <<EOF
+pid\$target:LM1\`ld.so.1:strstr:entry,
+pid\$target:libc.so.1:strstr:entry
+{
+ exit (0);
+}
+
+BEGIN
+{
+ exit (0);
+}
+EOF
+rc=$?
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.pidprint.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.pidprint.ksh
new file mode 100644
index 000000000000..e5902faf2cb2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.pidprint.ksh
@@ -0,0 +1,69 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# Use print() on userland CTF types and verify we get the data we expect.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="final_fantasy_info_t"
+exe="tst.printtype.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -ne 0 ]]; then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -qs /dev/stdin <<EOF
+pid$pid::ff_getgameid:entry
+/next == 0/
+{
+ print(*args[0]);
+ printf("\n");
+ next = 1;
+}
+
+pid$pid::ff_getpartysize:entry
+/next == 1/
+{
+ print(*args[0]);
+ printf("\n");
+ next = 2;
+}
+
+pid$pid::ff_getsummons:entry
+/next == 2/
+{
+ print(*args[0]);
+ printf("\n");
+ exit(0);
+}
+EOF
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.pidprinttarg.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.pidprinttarg.ksh
new file mode 100644
index 000000000000..5e92cf924c2a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.pidprinttarg.ksh
@@ -0,0 +1,70 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# Use print() on userland CTF types and verify we get the data we
+# expect. This time, use $target to make sure that path works correctly.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="final_fantasy_info_t"
+exe="tst.printtype.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -ne 0 ]]; then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -p $pid -qs /dev/stdin <<EOF
+pid\$target::ff_getgameid:entry
+/next == 0/
+{
+ print(*args[0]);
+ printf("\n");
+ next = 1;
+}
+
+pid\$target::ff_getpartysize:entry
+/next == 1/
+{
+ print(*args[0]);
+ printf("\n");
+ next = 2;
+}
+
+pid\$target::ff_getsummons:entry
+/next == 2/
+{
+ print(*args[0]);
+ printf("\n");
+ exit(0);
+}
+EOF
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.c
new file mode 100644
index 000000000000..6c27593e972b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.c
@@ -0,0 +1,72 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 (c) Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * The point of this is to use print() on various functions to make sure that we
+ * can print basic structures. Note that we purposefully are making sure that
+ * there are no pointers here.
+ */
+#include <unistd.h>
+
+typedef struct final_fantasy_info {
+ int ff_gameid;
+ int ff_partysize;
+ int ff_hassummons;
+} final_fantasy_info_t;
+
+static int
+ff_getgameid(final_fantasy_info_t *f)
+{
+ return (0);
+}
+
+static int
+ff_getpartysize(final_fantasy_info_t *f)
+{
+ return (0);
+}
+
+static int
+ff_getsummons(final_fantasy_info_t *f)
+{
+ return (0);
+}
+
+int
+main(void)
+{
+ final_fantasy_info_t ffiii, ffx, ffi;
+
+ ffi.ff_gameid = 1;
+ ffi.ff_partysize = 4;
+ ffi.ff_hassummons = 0;
+
+ ffiii.ff_gameid = 6;
+ ffiii.ff_partysize = 4;
+ ffiii.ff_hassummons = 1;
+
+ ffx.ff_gameid = 10;
+ ffx.ff_partysize = 3;
+ ffx.ff_hassummons = 1;
+
+ for (;;) {
+ ff_getgameid(&ffi);
+ ff_getpartysize(&ffx);
+ ff_getsummons(&ffiii);
+ sleep(1);
+ }
+ /*NOTREACHED*/
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.ksh
new file mode 100644
index 000000000000..a93a3b8722c3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.ksh
@@ -0,0 +1,69 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# Use print() on userland CTF types and verify we get the data we expect.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="final_fantasy_info_t"
+exe="tst.printtype.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -ne 0 ]]; then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -qs /dev/stdin <<EOF
+pid$pid::ff_getgameid:entry
+/next == 0/
+{
+ print(*(pid$pid\`$t *)(copyin(arg0, sizeof (pid$pid\`$t))));
+ printf("\n");
+ next = 1;
+}
+
+pid$pid::ff_getpartysize:entry
+/next == 1/
+{
+ print(*(pid$pid\`$t *)(copyin(arg0, sizeof (pid$pid\`$t))));
+ printf("\n");
+ next = 2;
+}
+
+pid$pid::ff_getsummons:entry
+/next == 2/
+{
+ print(*(pid$pid\`$t *)(copyin(arg0, sizeof (pid$pid\`$t))));
+ printf("\n");
+ exit(0);
+}
+EOF
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.ksh.out
new file mode 100644
index 000000000000..1770ba23548f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtype.ksh.out
@@ -0,0 +1,16 @@
+final_fantasy_info_t {
+ int ff_gameid = 0x1
+ int ff_partysize = 0x4
+ int ff_hassummons = 0
+}
+final_fantasy_info_t {
+ int ff_gameid = 0xa
+ int ff_partysize = 0x3
+ int ff_hassummons = 0x1
+}
+final_fantasy_info_t {
+ int ff_gameid = 0x6
+ int ff_partysize = 0x4
+ int ff_hassummons = 0x1
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtypetarg.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtypetarg.ksh
new file mode 100644
index 000000000000..fa080a53f3ff
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.printtypetarg.ksh
@@ -0,0 +1,70 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# Use print() on userland CTF types and verify we get the data we
+# expect. Use the pid` alias for $target.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="final_fantasy_info_t"
+exe="tst.printtype.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -ne 0 ]]; then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -p $pid -qs /dev/stdin <<EOF
+pid\$target::ff_getgameid:entry
+/next == 0/
+{
+ print(*(pid\`$t *)(copyin(arg0, sizeof (pid\`$t))));
+ printf("\n");
+ next = 1;
+}
+
+pid\$target::ff_getpartysize:entry
+/next == 1/
+{
+ print(*(pid\`$t *)(copyin(arg0, sizeof (pid\`$t))));
+ printf("\n");
+ next = 2;
+}
+
+pid\$target::ff_getsummons:entry
+/next == 2/
+{
+ print(*(pid\`$t *)(copyin(arg0, sizeof (pid\`$t))));
+ printf("\n");
+ exit(0);
+}
+EOF
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userlandkey.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userlandkey.ksh
new file mode 100644
index 000000000000..54d975f63aff
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userlandkey.ksh
@@ -0,0 +1,83 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# Simple test that if we manually use the userland keyword that it
+# works.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+t="zelda_info_t"
+exe="tst.chasestrings.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -ne 0 ]]; then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -qs /dev/stdin <<EOF
+typedef struct info {
+ char *zi_gamename;
+ int zi_ndungeons;
+ char *zi_villain;
+ int zi_haszelda;
+} info_t;
+
+pid$pid::has_princess:entry
+/next == 0/
+{
+ this->t = (userland info_t *)arg0;
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ stringof(this->t->zi_gamename), this->t->zi_ndungeons,
+ stringof(this->t->zi_villain), this->t->zi_haszelda);
+ next = 1;
+}
+
+pid$pid::has_dungeons:entry
+/next == 1/
+{
+ this->t = (userland info_t *)arg0;
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ stringof(this->t->zi_gamename), this->t->zi_ndungeons,
+ stringof(this->t->zi_villain), this->t->zi_haszelda);
+ next = 2;
+}
+
+pid$pid::has_villain:entry
+/next == 2/
+{
+ this->t = (userland info_t *)arg0;
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ stringof(this->t->zi_gamename), this->t->zi_ndungeons,
+ stringof(this->t->zi_villain), this->t->zi_haszelda);
+ exit(0);
+}
+EOF
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userlandkey.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userlandkey.ksh.out
new file mode 100644
index 000000000000..219e406e61d6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userlandkey.ksh.out
@@ -0,0 +1,4 @@
+game: Ocarina of Time, dungeon: 10, villain: Ganondorf, zelda: 1
+game: Link's Awakening, dungeon: 9, villain: Nightmare, zelda: 0
+game: A Link to the Past, dungeon: 12, villain: Ganon, zelda: 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userstrings.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userstrings.ksh
new file mode 100644
index 000000000000..c5a105b3a55c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userstrings.ksh
@@ -0,0 +1,72 @@
+#! /usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+#
+# This test is checking that we can read members and that pointers inside
+# members point to valid data that is intelligible, eg. strings.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+exe="tst.chasestrings.exe"
+
+elfdump -c "./$exe" | grep -Fq 'sh_name: .SUNW_ctf'
+if [[ $? -ne 0 ]]; then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+./$exe &
+pid=$!
+
+$dtrace -qs /dev/stdin <<EOF
+pid$pid::has_princess:entry
+/next == 0/
+{
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ stringof(args[0]->zi_gamename), args[0]->zi_ndungeons,
+ stringof(args[0]->zi_villain), args[0]->zi_haszelda);
+ next = 1;
+}
+
+pid$pid::has_dungeons:entry
+/next == 1/
+{
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ stringof(args[0]->zi_gamename), args[0]->zi_ndungeons,
+ stringof(args[0]->zi_villain), args[0]->zi_haszelda);
+ next = 2;
+}
+
+pid$pid::has_villain:entry
+/next == 2/
+{
+ printf("game: %s, dungeon: %d, villain: %s, zelda: %d\n",
+ stringof(args[0]->zi_gamename), args[0]->zi_ndungeons,
+ stringof(args[0]->zi_villain), args[0]->zi_haszelda);
+ exit(0);
+}
+EOF
+rc=$?
+
+kill -9 $pid
+
+exit $rc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userstrings.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userstrings.ksh.out
new file mode 100644
index 000000000000..219e406e61d6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/uctf/tst.userstrings.ksh.out
@@ -0,0 +1,4 @@
+game: Ocarina of Time, dungeon: 10, villain: Ganondorf, zelda: 1
+game: Link's Awakening, dungeon: 9, villain: Nightmare, zelda: 0
+game: A Link to the Past, dungeon: 12, villain: Ganon, zelda: 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_ADDROF_VAR.UnionPointer.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_ADDROF_VAR.UnionPointer.d
new file mode 100644
index 000000000000..0a292cdef20d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_ADDROF_VAR.UnionPointer.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Trying to access the members of a user defined union by means of
+ * a pointer to it should throw a D_ADDROF_VAR compiler error.
+ *
+ * SECTION: Structs and Unions/Pointers to Structs
+ *
+ */
+
+#pragma D option quiet
+
+union record {
+ int position;
+ int content;
+
+};
+
+union record var;
+union record *ptr;
+
+BEGIN
+{
+
+ var.position = 1;
+ var.content = 'a';
+
+ ptr = &var;
+
+ printf("ptr->position: %d\tptr->content: %c\n",
+ ptr->position, ptr->content);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_COMBO.UnionWithoutColon.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_COMBO.UnionWithoutColon.d
new file mode 100644
index 000000000000..4adb36e94199
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_COMBO.UnionWithoutColon.d
@@ -0,0 +1,69 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Combining multiple union definitions in a single line should throw a
+ * compiler error.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ */
+
+#pragma D option quiet
+
+union record {
+ int position;
+ char content;
+}
+
+
+union pirate {
+ int position;
+ char content;
+};
+
+union superStruct super;
+union record rec;
+union pirate pir;
+
+BEGIN
+{
+ rec.content = 'a';
+ rec.position = 1;
+
+ pir.content = 'b';
+ pir.position = 2;
+
+ printf(
+ "rec.content: %c\nrec.position: %d\npir.content: %c\npir.position: %d",
+ rec.content, rec.position, pir.content, pir.position);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_COMBO.UnionWithoutColon1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_COMBO.UnionWithoutColon1.d
new file mode 100644
index 000000000000..5506a97645af
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_COMBO.UnionWithoutColon1.d
@@ -0,0 +1,68 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Combining multiple union definitions in a single line should throw a
+ * compiler error.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ */
+
+#pragma D option quiet
+
+union record {
+ int position;
+ char content;
+};
+
+
+union pirate {
+ int position;
+ char content;
+}
+
+union record rec;
+union pirate pir;
+
+BEGIN
+{
+ rec.content = 'a';
+ rec.position = 1;
+
+ pir.content = 'b';
+ pir.position = 2;
+
+ printf(
+ "rec.content: %c\nrec.position: %d\npir.content: %c\npir.position: %d",
+ rec.content, rec.position, pir.content, pir.position);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.circular.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.circular.d
new file mode 100644
index 000000000000..ae6e647f5b8d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.circular.d
@@ -0,0 +1,65 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * A circular definition of unions (two unions defining each other as
+ * members) should throw an error at compile time.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ */
+
+#pragma D option quiet
+
+union record {
+ union pirate p;
+ int position;
+ char content;
+};
+
+
+union pirate {
+ union record r;
+ int position;
+ char content;
+};
+
+union record rec;
+union pirate pir;
+
+BEGIN
+{
+ rec.position = 0;
+ rec.content = 'a';
+ printf(
+ "rec.position: %d\nrec.content: %c\n", rec.position, rec.content);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.order.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.order.d
new file mode 100644
index 000000000000..9e2ec69f4b7f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.order.d
@@ -0,0 +1,69 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * When two unions are defined such that one of them contains the other, the
+ * inner union has to be defined first.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ */
+
+#pragma D option quiet
+
+
+union record {
+ union pirate p;
+ int position;
+ char content;
+};
+
+union pirate {
+ int position;
+ char content;
+};
+
+union record rec;
+union pirate pir;
+
+BEGIN
+{
+ rec.content = 'y';
+ rec.position = 2;
+
+ pir.content = 'z';
+ pir.position = 26;
+
+ printf(
+ "rec.content: %c\nrec.position: %d\npir.content: %c\npir.position: %d",
+ rec.content, rec.position, pir.content, pir.position);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.recursive.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.recursive.d
new file mode 100644
index 000000000000..2a86b9cd3795
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.recursive.d
@@ -0,0 +1,59 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Recursive naming of unions should produce compiler error.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ */
+
+#pragma D option quiet
+
+union record {
+ union record rec;
+ int position;
+ char content;
+};
+
+union record r1;
+union record r2;
+
+BEGIN
+{
+ r1.position = 1;
+ r1.content = 'a';
+
+ r2.position = 2;
+ r2.content = 'b';
+
+ printf("r1.position: %d\nr1.content: %c\n", r1.position, r1.content);
+ printf("r2.position: %d\nr2.content: %c\n", r2.position, r2.content);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.simple.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.simple.d
new file mode 100644
index 000000000000..781d72666764
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_DECL_INCOMPLETE.simple.d
@@ -0,0 +1,58 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declaring an inner union without defining it else where should throw
+ * a compiler error.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ */
+#pragma D option quiet
+
+
+union record {
+ union pirate p;
+ int position;
+ char content;
+};
+
+
+union record rec;
+
+BEGIN
+{
+ rec.position = 0;
+ rec.content = 'a';
+ printf("rec.position: %d\nrec.content: %c\n",
+ rec.position, rec.content);
+
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_PROTO_ARG.DupUnionAssoc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_PROTO_ARG.DupUnionAssoc.d
new file mode 100644
index 000000000000..f91874124079
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/err.D_PROTO_ARG.DupUnionAssoc.d
@@ -0,0 +1,80 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Declaring an associative array with a union to be its key type and trying to
+ * index with another union having the same composition throws an error.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ */
+
+#pragma D option quiet
+
+union record {
+ int position;
+ char content;
+};
+
+union pirate {
+ int position;
+ char content;
+};
+
+union record r1;
+union record r2;
+union pirate p1;
+union pirate p2;
+
+BEGIN
+{
+ r1.position = 1;
+ r1.content = 'a';
+
+ r2.position = 2;
+ r2.content = 'b';
+
+ p1.position = 1;
+ p1.content = 'a';
+
+ p2.position = 2;
+ p2.content = 'b';
+
+ assoc_array[r1] = 1000;
+ assoc_array[r2] = 2000;
+ assoc_array[p1] = 3333;
+ assoc_array[p2] = 4444;
+
+ printf("assoc_array[r1]: %d\n", assoc_array[r1]);
+ printf("assoc_array[r2]: %d\n", assoc_array[r2]);
+ printf("assoc_array[p1]: %d\n", assoc_array[p1]);
+ printf("assoc_array[p2]: %d\n", assoc_array[p2]);
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionAssoc.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionAssoc.d
new file mode 100644
index 000000000000..882b6ae05df9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionAssoc.d
@@ -0,0 +1,71 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * When a union is used as a key for an associative array, the key is formed
+ * by using the values of the members of the union variable and not the
+ * address of the union variable.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ */
+
+#pragma D option quiet
+
+union record {
+ int position;
+ char content;
+};
+
+union record r1;
+union record r2;
+
+BEGIN
+{
+ r1.position = 1;
+ r1.content = 'a';
+
+ r2.position = 1;
+ r2.content = 'a';
+
+ assoc_array[r1] = 1000;
+ assoc_array[r2] = 2000;
+
+ printf("assoc_array[r1]: %d\n", assoc_array[r1]);
+ printf("assoc_array[r2]: %d\n", assoc_array[r2]);
+
+ exit(0);
+}
+
+END
+/assoc_array[r1] != assoc_array[r2]/
+{
+ printf("Error");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionDataTypes.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionDataTypes.d
new file mode 100644
index 000000000000..d5d292d1728f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionDataTypes.d
@@ -0,0 +1,132 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Declaration of the different data types within a union and
+ * their definitions in a later clause should work fine.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ * NOTES: The floats, doubles and strings have not been implemented yet.
+ * When they do, appropriate lines in the code below should be uncommented.
+ * Similarly, the lines with the kmem_flags pointer assignment should be
+ * uncommented when the issues pertaining to it are clarified.
+ *
+ */
+
+#pragma D option quiet
+
+union record {
+ char new_char;
+ short new_short;
+ int new_int;
+ long new_long;
+ long long new_long_long;
+ int8_t new_int8;
+ int16_t new_int16;
+ int32_t new_int32;
+ int64_t new_int64;
+ intptr_t new_intptr;
+ uint8_t new_uint8;
+ uint16_t new_uint16;
+ uint32_t new_uint32;
+ uint64_t new_uint64;
+ uintptr_t new_uintptr;
+
+ /*float new_float;
+ double new_double;
+ long double new_long_double;
+
+ string new_string;
+ */
+
+ struct {
+ char ch;
+ int in;
+ long lg;
+ } new_struct;
+
+ union {
+ char ch;
+ int in;
+ long lg;
+ } new_union;
+
+enum {
+ RED,
+ GREEN,
+ BLUE
+} new_enum;
+
+
+ int *pointer;
+} var;
+
+/*
+ var.pointer = &`kmem_flags;
+*/
+BEGIN
+{
+ var.new_char = 'c';
+ var.new_short = 10;
+ var.new_int = 100;
+ var.new_long = 1234567890;
+ var.new_long_long = 1234512345;
+ var.new_int8 = 'p';
+ var.new_int16 = 20;
+ var.new_int32 = 200;
+ var.new_int64 = 2000000;
+ var.new_intptr = 0x12345;
+ var.new_uint8 = 'q';
+ var.new_uint16 = 30;
+ var.new_uint32 = 300;
+ var.new_uint64 = 3000000;
+ var.new_uintptr = 0x67890;
+
+ /* var.new_float = 1.23456;
+ var.new_double = 2.34567890;
+ var.new_long_double = 3.567890123;
+
+ var.new_string = "hello";
+ */
+
+ /*
+ var.pointer = &`kmem_flags;
+ */
+
+ var.new_struct.ch = 'c';
+ var.new_struct.in = 4;
+ var.new_struct.lg = 4;
+
+ var.new_union.ch = 'd';
+ var.new_union.in = 5;
+ var.new_union.lg = 5;
+
+
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionInside.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionInside.d
new file mode 100644
index 000000000000..9569002b1c92
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/union/tst.UnionInside.d
@@ -0,0 +1,85 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * Verify the nested behavior of unions.
+ *
+ * SECTION: Structs and Unions/Unions
+ *
+ */
+#pragma D option quiet
+
+union InnerMost {
+ int position;
+ char content;
+};
+
+union InnerMore {
+ union InnerMost IMost;
+ int dummy_More;
+};
+
+union Inner {
+ union InnerMore IMore;
+ int dummy_More;
+};
+
+union Outer {
+ union Inner I;
+ int dummy_More;
+};
+
+union OuterMore {
+ union Outer O;
+ int dummy_More;
+};
+
+union OuterMost {
+ union OuterMore OMore;
+ int dummy_More;
+} OMost;
+
+
+BEGIN
+{
+
+ OMost.OMore.O.I.IMore.IMost.position = 5;
+ OMost.OMore.O.I.IMore.IMost.content = 'e';
+
+ printf("OMost.OMore.O.I.IMore.IMost.content: %c\n",
+ OMost.OMore.O.I.IMore.IMost.content);
+
+ exit(0);
+}
+
+END
+/'e' != OMost.OMore.O.I.IMore.IMost.content/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/argmap.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/argmap.d
new file mode 100644
index 000000000000..0a1c36093c1f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/argmap.d
@@ -0,0 +1,31 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+provider test_prov {
+ probe place(int i, int j) : (int j, int i, int i, int j);
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/args.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/args.d
new file mode 100644
index 000000000000..a11984c17a7d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/args.d
@@ -0,0 +1,31 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+provider test_prov {
+ probe place(int i, int j);
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/forker.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/forker.d
new file mode 100644
index 000000000000..f63b965df29b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/forker.d
@@ -0,0 +1,31 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+provider forker {
+ probe fire();
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/prov.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/prov.d
new file mode 100644
index 000000000000..53e5ef3988d1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/prov.d
@@ -0,0 +1,3 @@
+provider tester {
+ probe entry();
+};
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/prov.h b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/prov.h
new file mode 100644
index 000000000000..e29654edb672
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/prov.h
@@ -0,0 +1,46 @@
+/*
+ * Generated by dtrace(1M).
+ */
+
+#ifndef _PROV_H
+#define _PROV_H
+
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if _DTRACE_VERSION
+
+#define TESTER_ENTRY() \
+ __dtrace_tester___entry()
+#ifndef __sparc
+#define TESTER_ENTRY_ENABLED() \
+ __dtraceenabled_tester___entry()
+#else
+#define TESTER_ENTRY_ENABLED() \
+ __dtraceenabled_tester___entry(0)
+#endif
+
+
+extern void __dtrace_tester___entry(void);
+#ifndef __sparc
+extern int __dtraceenabled_tester___entry(void);
+#else
+extern int __dtraceenabled_tester___entry(long);
+#endif
+
+#else
+
+#define TESTER_ENTRY()
+#define TESTER_ENTRY_ENABLED() (0)
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PROV_H */
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.andpid.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.andpid.ksh
new file mode 100644
index 000000000000..2096422b7b7c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.andpid.ksh
@@ -0,0 +1,46 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -c date -s /dev/stdin <<EOF
+plockstat\$target::mutex_lock_impl:,
+pid\$target::mutex_lock_impl:
+{}
+EOF
+
+if [ $? -ne 0 ]; then
+ print -u2 "dtrace failed"
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.argmap.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.argmap.c
new file mode 100644
index 000000000000..5697ef51279f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.argmap.c
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+ for (;;) {
+ DTRACE_PROBE2(test_prov, place, 10, 4);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.argmap.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.argmap.d
new file mode 100644
index 000000000000..fd9f9f4743da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.argmap.d
@@ -0,0 +1,65 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Verify that argN and args[N] variables are properly remapped.
+ */
+
+BEGIN
+{
+ /* Timeout after 5 seconds */
+ timeout = timestamp + 5000000000;
+}
+
+test_prov$1:::place
+/arg0 != 4 || arg1 != 10 || arg2 != 10 || arg3 != 4/
+{
+ printf("args are %d, %d, %d, %d; should be 4, 10, 10, 4",
+ arg0, arg1, arg2, arg3);
+ exit(1);
+}
+
+test_prov$1:::place
+/args[0] != 4 || args[1] != 10 || args[2] != 10 || args[3] != 4/
+{
+ printf("args are %d, %d, %d, %d; should be 4, 10, 10, 4",
+ args[0], args[1], args[2], args[3]);
+ exit(1);
+}
+
+test_prov$1:::place
+{
+ exit(0);
+}
+
+profile:::tick-1
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.args.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.args.c
new file mode 100644
index 000000000000..5697ef51279f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.args.c
@@ -0,0 +1,39 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+ for (;;) {
+ DTRACE_PROBE2(test_prov, place, 10, 4);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.args.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.args.d
new file mode 100644
index 000000000000..bb74e80f72cf
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.args.d
@@ -0,0 +1,60 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * SECTION:
+ *
+ * NOTES:
+ *
+ */
+BEGIN
+{
+ /* Timeout after 5 seconds */
+ timeout = timestamp + 5000000000;
+}
+
+test_prov$1:::place
+/arg0 == 10 && arg1 == 4/
+{
+ exit(0);
+}
+
+test_prov$1:::place
+{
+ printf("args are %d, %d; should be 10, 4", arg0, arg1);
+ exit(1);
+}
+
+profile:::tick-1
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.badguess.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.badguess.ksh
new file mode 100644
index 000000000000..91b6cf06f10d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.badguess.ksh
@@ -0,0 +1,84 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ if (TEST_PROV_GO_ENABLED()) {
+ TEST_PROV_GO();
+ }
+}
+EOF
+
+cc -xarch=generic64 -c -o test64.o test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c 64-bit"
+ exit 1
+fi
+cc -xarch=generic -c -o test32.o test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c 32-bit"
+ exit 1
+fi
+
+$dtrace -G -s prov.d test32.o test64.o
+if [ $? -eq 0 ]; then
+ print -u2 "DOF generation failed to generate a warning"
+ exit 1
+fi
+
+cd /
+/bin/rm -rf $DIR
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.corruptenv.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.corruptenv.ksh
new file mode 100644
index 000000000000..f1887ea78e99
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.corruptenv.ksh
@@ -0,0 +1,107 @@
+#!/usr/bin/ksh
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This test verifies that a program that corrupts its own environment
+# without inducing a crash does not crash solely due to drti.o's use of
+# getenv(3C).
+#
+
+PATH=/usr/bin:/usr/sbin:$PATH
+
+if (( $# != 1 )); then
+ print -u2 'expected one argument: <dtrace-path>'
+ exit 2
+fi
+
+#
+# jdtrace does not implement the -h option that is required to generate
+# C header files.
+#
+if [[ "$1" == */jdtrace ]]; then
+ exit 0
+fi
+
+dtrace="$1"
+startdir="$PWD"
+dir=$(mktemp -d -t drtiXXXXXX)
+if (( $? != 0 )); then
+ print -u2 'Could not create safe temporary directory'
+ exit 2
+fi
+
+cd "$dir"
+
+cat > Makefile <<EOF
+all: main
+
+main: main.o prov.o
+ \$(CC) -o main main.o prov.o
+
+main.o: main.c prov.h
+ \$(CC) -c main.c
+
+prov.h: prov.d
+ $dtrace -h -s prov.d
+
+prov.o: prov.d main.o
+ $dtrace -G -s prov.d main.o
+EOF
+
+cat > prov.d <<EOF
+provider tester {
+ probe entry();
+};
+EOF
+
+cat > main.c <<EOF
+#include <stdlib.h>
+#include <sys/sdt.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv, char **envp)
+{
+ envp[0] = (char*)0xff;
+ TESTER_ENTRY();
+ return 0;
+}
+EOF
+
+make > /dev/null
+status=$?
+if (( $status != 0 )) ; then
+ print -u2 "failed to build"
+else
+ ./main
+ status=$?
+fi
+
+cd "$startdir"
+rm -rf "$dir"
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose1.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose1.ksh
new file mode 100644
index 000000000000..5aaf9a0ab3fe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose1.ksh
@@ -0,0 +1,162 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This test verifies that USDT providers are removed when its associated
+# load object is closed via dlclose(3dl).
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > Makefile <<EOF
+all: main livelib.so deadlib.so
+
+main: main.o prov.o
+ cc -o main main.o
+
+main.o: main.c
+ cc -c main.c
+
+
+livelib.so: livelib.o prov.o
+ cc -shared -o livelib.so livelib.o prov.o -lc
+
+livelib.o: livelib.c prov.h
+ cc -c livelib.c
+
+prov.o: livelib.o prov.d
+ $dtrace -G -s prov.d livelib.o
+
+prov.h: prov.d
+ $dtrace -h -s prov.d
+
+
+deadlib.so: deadlib.o
+ cc -shared -o deadlib.so deadlib.o -lc
+
+deadlib.o: deadlib.c
+ cc -c deadlib.c
+
+clean:
+ rm -f main.o livelib.o prov.o prov.h deadlib.o
+
+clobber: clean
+ rm -f main livelib.so deadlib.so
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+cat > livelib.c <<EOF
+#include "prov.h"
+
+void
+go(void)
+{
+ TEST_PROV_GO();
+}
+EOF
+
+cat > deadlib.c <<EOF
+void
+go(void)
+{
+}
+EOF
+
+
+cat > main.c <<EOF
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+
+int
+main(int argc, char **argv)
+{
+ void *live;
+ sigset_t mask;
+
+ if ((live = dlopen("./livelib.so", RTLD_LAZY | RTLD_LOCAL)) == NULL) {
+ printf("dlopen of livelib.so failed: %s\n", dlerror());
+ return (1);
+ }
+
+ (void) dlclose(live);
+
+ (void) sigemptyset(&mask);
+ (void) sigsuspend(&mask);
+
+ return (0);
+}
+EOF
+
+/usr/bin/make > /dev/null
+if [ $? -ne 0 ]; then
+ print -u2 "failed to build"
+ exit 1
+fi
+
+script() {
+ $dtrace -w -x bufsize=1k -c ./main -qs /dev/stdin <<EOF
+ syscall::sigsuspend:entry
+ /pid == \$target/
+ {
+ system("$dtrace -l -P test_prov*");
+ system("kill %d", \$target);
+ exit(0);
+ }
+
+ tick-1s
+ /i++ == 5/
+ {
+ printf("failed\n");
+ exit(1);
+ }
+EOF
+}
+
+script 2>&1
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose1.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose1.ksh.out
new file mode 100644
index 000000000000..2f5bb15fb5b7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose1.ksh.out
@@ -0,0 +1,3 @@
+dtrace: failed to match test_prov*:::: No probe matches description
+ ID PROVIDER MODULE FUNCTION NAME
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose2.ksh
new file mode 100644
index 000000000000..6ce1329c6ed2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose2.ksh
@@ -0,0 +1,160 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > Makefile <<EOF
+all: main livelib.so deadlib.so
+
+main: main.o prov.o
+ cc -o main main.o
+
+main.o: main.c
+ cc -c main.c
+
+
+livelib.so: livelib.o prov.o
+ cc -shared -o livelib.so livelib.o prov.o -lc
+
+livelib.o: livelib.c prov.h
+ cc -c livelib.c
+
+prov.o: livelib.o prov.d
+ $dtrace -G -s prov.d livelib.o
+
+prov.h: prov.d
+ $dtrace -h -s prov.d
+
+
+deadlib.so: deadlib.o
+ cc -shared -o deadlib.so deadlib.o -lc
+
+deadlib.o: deadlib.c
+ cc -c deadlib.c
+
+clean:
+ rm -f main.o livelib.o prov.o prov.h deadlib.o
+
+clobber: clean
+ rm -f main livelib.so deadlib.so
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+cat > livelib.c <<EOF
+#include "prov.h"
+
+void
+go(void)
+{
+ TEST_PROV_GO();
+}
+EOF
+
+cat > deadlib.c <<EOF
+void
+go(void)
+{
+}
+EOF
+
+
+cat > main.c <<EOF
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ void *live, *dead;
+ void *go;
+
+ if ((live = dlopen("./livelib.so", RTLD_LAZY | RTLD_LOCAL)) == NULL) {
+ printf("dlopen of livelib.so failed: %s\n", dlerror());
+ return (1);
+ }
+
+ (void) dlclose(live);
+
+ if ((dead = dlopen("./deadlib.so", RTLD_LAZY | RTLD_LOCAL)) == NULL) {
+ printf("dlopen of deadlib.so failed: %s\n", dlerror());
+ return (1);
+ }
+
+ if ((live = dlopen("./livelib.so", RTLD_LAZY | RTLD_LOCAL)) == NULL) {
+ printf("dlopen of livelib.so failed: %s\n", dlerror());
+ return (1);
+ }
+
+ if ((go = dlsym(live, "go")) == NULL) {
+ printf("failed to lookup 'go' in livelib.so\n");
+ return (1);
+ }
+
+ ((void (*)(void))go)();
+
+ return (0);
+}
+EOF
+
+/usr/bin/make > /dev/null
+if [ $? -ne 0 ]; then
+ print -u2 "failed to build"
+ exit 1
+fi
+
+script() {
+ $dtrace -w -c ./main -Zqs /dev/stdin <<EOF
+ test_prov*:::
+ {
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose2.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose2.ksh.out
new file mode 100644
index 000000000000..2164eabcf423
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose2.ksh.out
@@ -0,0 +1,2 @@
+livelib.so:go:go
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose3.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose3.ksh
new file mode 100644
index 000000000000..ad668cc1e772
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.dlclose3.ksh
@@ -0,0 +1,170 @@
+#!/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This test verifies that performing a dlclose(3dl) on a library doesn't
+# cause existing pid provider probes to become invalid.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > Makefile <<EOF
+all: main livelib.so deadlib.so
+
+main: main.o prov.o
+ cc -o main main.o
+
+main.o: main.c
+ cc -c main.c
+
+
+livelib.so: livelib.o prov.o
+ cc -shared -o livelib.so livelib.o prov.o -lc
+
+livelib.o: livelib.c prov.h
+ cc -c livelib.c
+
+prov.o: livelib.o prov.d
+ $dtrace -G -s prov.d livelib.o
+
+prov.h: prov.d
+ $dtrace -h -s prov.d
+
+
+deadlib.so: deadlib.o
+ cc -shared -o deadlib.so deadlib.o -lc
+
+deadlib.o: deadlib.c
+ cc -c deadlib.c
+
+clean:
+ rm -f main.o livelib.o prov.o prov.h deadlib.o
+
+clobber: clean
+ rm -f main livelib.so deadlib.so
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+cat > livelib.c <<EOF
+#include "prov.h"
+
+void
+go(void)
+{
+ TEST_PROV_GO();
+}
+EOF
+
+cat > deadlib.c <<EOF
+void
+go(void)
+{
+}
+EOF
+
+
+cat > main.c <<EOF
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdio.h>
+
+static void
+foo(void)
+{
+ (void) close(-1);
+}
+
+int
+main(int argc, char **argv)
+{
+ void *live;
+
+ if ((live = dlopen("./livelib.so", RTLD_LAZY | RTLD_LOCAL)) == NULL) {
+ printf("dlopen of livelib.so failed: %s\n", dlerror());
+ return (1);
+ }
+
+ (void) dlclose(live);
+
+ foo();
+
+ return (0);
+}
+EOF
+
+/usr/bin/make > /dev/null
+if [ $? -ne 0 ]; then
+ print -u2 "failed to build"
+ exit 1
+fi
+
+script() {
+ $dtrace -c ./main -s /dev/stdin <<EOF
+ pid\$target:a.out:foo:entry
+ {
+ gotit = 1;
+ exit(0);
+ }
+
+ tick-1s
+ /i++ == 5/
+ {
+ printf("test timed out");
+ exit(1);
+ }
+
+ END
+ /!gotit/
+ {
+ printf("program ended without hitting probe");
+ exit(1);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.eliminate.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.eliminate.ksh
new file mode 100644
index 000000000000..7dcfd41d807a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.eliminate.ksh
@@ -0,0 +1,106 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# Make sure temporary symbols generated due to DTrace probes in static
+# functions are removed in the final link step.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+static void
+foo(void)
+{
+ TEST_PROV_GO();
+}
+
+int
+main(int argc, char **argv)
+{
+ foo();
+
+ return (0);
+}
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+nm test.o | grep \$dtrace > /dev/null
+if [ $? -ne 0 ]; then
+ print -u2 "no temporary symbols in the object file"
+ exit 1
+fi
+
+nm test | grep \$dtrace > /dev/null
+if [ $? -eq 0 ]; then
+ print -u2 "failed to eliminate temporary symbols"
+ exit 1
+fi
+
+cd /
+/bin/rm -rf $DIR
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled.ksh
new file mode 100644
index 000000000000..2a1f9b6ed784
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled.ksh
@@ -0,0 +1,96 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ if (TEST_PROV_GO_ENABLED()) {
+ TEST_PROV_GO();
+ }
+}
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -c ./test -qs /dev/stdin <<EOF
+ test_prov\$target:::
+ {
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled.ksh.out
new file mode 100644
index 000000000000..b856cc59f44c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled.ksh.out
@@ -0,0 +1,2 @@
+test:main:go
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh
new file mode 100644
index 000000000000..8fd321ae6524
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh
@@ -0,0 +1,113 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# This test is primarily intended to verify a fix for SPARC, but there's no
+# harm in running it on other platforms. Here, we verify that is-enabled
+# probes don't interfere with return values from previously invoked functions.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <stdio.h>
+#include "prov.h"
+
+int
+foo(void)
+{
+ return (24);
+}
+
+int
+main(int argc, char **argv)
+{
+ int a = foo();
+ if (TEST_PROV_GO_ENABLED()) {
+ TEST_PROV_GO();
+ }
+ (void) printf("%d %d %d\n", a, a, a);
+
+ return (0);
+}
+EOF
+
+cc -c -O2 test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ ./test
+
+ $dtrace -c ./test -qs /dev/stdin <<EOF
+ test_prov\$target:::
+ {
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh.out
new file mode 100644
index 000000000000..563d68fd312b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh.out
@@ -0,0 +1,3 @@
+24 24 24
+24 24 24
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.entryreturn.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.entryreturn.ksh
new file mode 100644
index 000000000000..43726a252b8b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.entryreturn.ksh
@@ -0,0 +1,118 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+ DTRACE_PROBE(test_prov, entry);
+ DTRACE_PROBE(test_prov, __entry);
+ DTRACE_PROBE(test_prov, foo__entry);
+ DTRACE_PROBE(test_prov, carpentry);
+ DTRACE_PROBE(test_prov, miniatureturn);
+ DTRACE_PROBE(test_prov, foo__return);
+ DTRACE_PROBE(test_prov, __return);
+ /*
+ * Unfortunately, a "return" probe is not currently possible due to
+ * the conflict with a reserved word.
+ */
+ DTRACE_PROBE(test_prov, done);
+}
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe entry();
+ probe __entry();
+ probe foo__entry();
+ probe carpentry();
+ probe miniatureturn();
+ probe foo__return();
+ probe __return();
+ probe done();
+};
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -wqZFs /dev/stdin <<EOF
+ BEGIN
+ {
+ system("$DIR/test");
+ printf("\n");
+ }
+
+ test_prov*:::done
+ /progenyof(\$pid)/
+ {
+ exit(0);
+ }
+
+ test_prov*:::
+ /progenyof(\$pid)/
+ {
+ printf("\n");
+ }
+EOF
+}
+
+script | cut -c5-
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.entryreturn.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.entryreturn.ksh.out
new file mode 100644
index 000000000000..3bf2890748ef
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.entryreturn.ksh.out
@@ -0,0 +1,10 @@
+FUNCTION
+| :BEGIN
+ -> main
+ -> main
+ -> main
+ | main:carpentry
+ | main:miniatureturn
+ <- main
+ <- main
+ | main:done
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.fork.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.fork.ksh
new file mode 100644
index 000000000000..72304cb74bc5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.fork.ksh
@@ -0,0 +1,105 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ TEST_PROV_GO();
+ if (fork() == 0) {
+ TEST_PROV_GO();
+ return (0);
+ }
+
+ (void) wait(NULL);
+ TEST_PROV_GO();
+
+ return (0);
+}
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script() {
+ $dtrace -c ./test -Zqs /dev/stdin <<EOF
+ test_prov*:::
+ {
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.fork.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.fork.ksh.out
new file mode 100644
index 000000000000..c656c3375762
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.fork.ksh.out
@@ -0,0 +1,4 @@
+test:main:go
+test:main:go
+test:main:go
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.forker.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.forker.c
new file mode 100644
index 000000000000..e229c0c996a8
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.forker.c
@@ -0,0 +1,51 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "forker.h"
+
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ for (i = 0; i < 10000; i++) {
+ FORKER_FIRE();
+ if (fork() == 0)
+ exit(0);
+
+ (void) wait(NULL);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.forker.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.forker.ksh
new file mode 100644
index 000000000000..d35fc4db70df
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.forker.ksh
@@ -0,0 +1,55 @@
+#!/usr/bin/ksh
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+#
+# Test that we don't deadlock between forking and enabling/disabling USDT
+# probes. This test has succeeded if it completes at all.
+#
+
+./tst.forker.exe &
+id=$!
+
+while kill -0 $id >/dev/null 2>&1; do
+ $dtrace -p $id -s /dev/stdin <<-EOF
+ forker*:::fire
+ /i++ == 4/
+ {
+ exit(0);
+ }
+ EOF
+done
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.guess32.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.guess32.ksh
new file mode 100644
index 000000000000..8affb3583f8d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.guess32.ksh
@@ -0,0 +1,96 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ if (TEST_PROV_GO_ENABLED()) {
+ TEST_PROV_GO();
+ }
+}
+EOF
+
+cc -xarch=generic -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -xarch=generic -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -c ./test -qs /dev/stdin <<EOF
+ test_prov\$target:::
+ {
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.guess64.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.guess64.ksh
new file mode 100644
index 000000000000..0c2801872e3f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.guess64.ksh
@@ -0,0 +1,100 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ if (TEST_PROV_GO_ENABLED()) {
+ TEST_PROV_GO();
+ }
+}
+EOF
+
+cc -xarch=generic64 -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -xarch=generic64 -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -c ./test -qs /dev/stdin <<EOF
+ test_prov\$target:::
+ {
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+ }
+EOF
+}
+
+if [ `isainfo -b` -ne '64']; then
+ script
+ status=$?
+else
+ status=0
+fi
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.header.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.header.ksh
new file mode 100644
index 000000000000..ef0752579b2d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.header.ksh
@@ -0,0 +1,85 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe zero();
+ probe one(uintptr_t);
+ probe u_nder(char *);
+ probe d__ash(int **);
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ TEST_PROV_ZERO();
+ TEST_PROV_ONE(1);
+ TEST_PROV_U_NDER("hi there");
+ TEST_PROV_D_ASH(argv);
+}
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+cd /
+/bin/rm -rf $DIR
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.include.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.include.ksh
new file mode 100644
index 000000000000..00da05bb9a07
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.include.ksh
@@ -0,0 +1,61 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+# Make sure <sys/sdt.h> defines _DTRACE_VERSION
+
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+#ifdef _DTRACE_VERSION
+ return (0);
+#else
+ return (1);
+#endif
+}
+EOF
+
+cc -o test test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+
+./test
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.linkpriv.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.linkpriv.ksh
new file mode 100644
index 000000000000..4aa3f59e16f9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.linkpriv.ksh
@@ -0,0 +1,82 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+ DTRACE_PROBE(test_prov, zero);
+ DTRACE_PROBE1(test_prov, one, 1);
+ DTRACE_PROBE2(test_prov, two, 2, 3);
+ DTRACE_PROBE3(test_prov, three, 4, 5, 7);
+ DTRACE_PROBE4(test_prov, four, 7, 8, 9, 10);
+ DTRACE_PROBE5(test_prov, five, 11, 12, 13, 14, 15);
+}
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe zero();
+ probe one(uintptr_t);
+ probe two(uintptr_t, uintptr_t);
+ probe three(uintptr_t, uintptr_t, uintptr_t);
+ probe four(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+ probe five(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+};
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+cd /
+/bin/rm -rf $DIR
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.linkunpriv.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.linkunpriv.ksh
new file mode 100644
index 000000000000..01d127fdd338
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.linkunpriv.ksh
@@ -0,0 +1,84 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+ppriv -s A=basic $$
+
+cat > test.c <<EOF
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+ DTRACE_PROBE(test_prov, zero);
+ DTRACE_PROBE1(test_prov, one, 1);
+ DTRACE_PROBE2(test_prov, two, 2, 3);
+ DTRACE_PROBE3(test_prov, three, 4, 5, 7);
+ DTRACE_PROBE4(test_prov, four, 7, 8, 9, 10);
+ DTRACE_PROBE5(test_prov, five, 11, 12, 13, 14, 15);
+}
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe zero();
+ probe one(uintptr_t);
+ probe two(uintptr_t, uintptr_t);
+ probe three(uintptr_t, uintptr_t, uintptr_t);
+ probe four(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+ probe five(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+};
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+cd /
+/bin/rm -rf $DIR
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiple.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiple.ksh
new file mode 100644
index 000000000000..b517e88e0ab3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiple.ksh
@@ -0,0 +1,99 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ TEST_PROV_GO();
+ TEST_PROV_GO();
+ TEST_PROV_GO();
+ TEST_PROV_GO();
+
+ return (0);
+}
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script() {
+ $dtrace -c ./test -qs /dev/stdin <<EOF
+ test_prov\$target:::
+ {
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiple.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiple.ksh.out
new file mode 100644
index 000000000000..5e826192fed1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiple.ksh.out
@@ -0,0 +1,5 @@
+test:main:go
+test:main:go
+test:main:go
+test:main:go
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiprov.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiprov.ksh
new file mode 100644
index 000000000000..9620b97cb019
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiprov.ksh
@@ -0,0 +1,106 @@
+#
+# 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 (c) 2013, Joyent, Inc. All rights reserved.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+echo '#pragma D option quiet' > test.d
+echo '#pragma D option aggsortkey' >> test.d
+
+cat > test.c <<EOF
+#include <unistd.h>
+
+void
+main()
+{
+EOF
+
+objs=
+
+for oogle in doogle bagnoogle; do
+ cat > $oogle.c <<EOF
+#include <sys/sdt.h>
+
+void
+$oogle()
+{
+ DTRACE_PROBE($oogle, knows);
+}
+EOF
+
+ cat > $oogle.d <<EOF
+provider $oogle {
+ probe knows();
+};
+EOF
+
+ cc -c $oogle.c
+
+ if [ $? -ne 0 ]; then
+ print -u2 "failed to compile $oogle.c"
+ exit 1
+ fi
+
+ $dtrace -G -s $oogle.d $oogle.o -o $oogle.d.o
+
+ if [ $? -ne 0 ]; then
+ print -u2 "failed to process $oogle.d"
+ exit 1
+ fi
+
+ objs="$objs $oogle.o $oogle.d.o"
+ echo $oogle'();' >> test.c
+ echo $oogle'$target:::{@[probefunc] = count()}' >> test.d
+done
+
+echo "}" >> test.c
+
+echo 'END{printa("%-10s %@d\\n", @)}' >> test.d
+
+cc -o test test.c $objs
+
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+
+$dtrace -s ./test.d -Zc ./test
+
+if [ $? -ne 0 ]; then
+ print -u2 "failed to execute test"
+ exit 1
+fi
+
+cd /
+rm -rf $DIR
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiprov.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiprov.ksh.out
new file mode 100644
index 000000000000..966b6f673531
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.multiprov.ksh.out
@@ -0,0 +1,3 @@
+bagnoogle 1
+doogle 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.nodtrace.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.nodtrace.ksh
new file mode 100644
index 000000000000..f766f6d1d1a5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.nodtrace.ksh
@@ -0,0 +1,90 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+# Fake up a scenario where _DTRACE_VERSION is not defined by having our own
+# <unistd.h>. This tests that dtrace -h will produce a header file which can
+# be used on a system where DTrace is not present.
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+touch unistd.h
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ TEST_PROV_GO();
+
+ if (TEST_PROV_GO_ENABLED()) {
+ TEST_PROV_GO();
+ }
+
+ return (0);
+}
+EOF
+
+cc -I. -xarch=generic -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+cc -xarch=generic -o test test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+./test
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noprobes.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noprobes.ksh
new file mode 100644
index 000000000000..4f3264f74a59
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noprobes.ksh
@@ -0,0 +1,59 @@
+#
+# 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 (c) 2013, Joyent, Inc. All rights reserved.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+void
+foo()
+{}
+EOF
+
+cat > doogle.d <<EOF
+provider doogle {
+ probe bagnoogle();
+};
+EOF
+
+cc -c test.c
+$dtrace -G -s doogle.d test.o -o doogle.d.o
+
+if [ $? -eq 0 ]; then
+ print -u2 "dtrace succeeded despite having no probe sites"
+ exit 1
+fi
+
+cd /
+rm -rf $DIR
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noreap.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noreap.ksh
new file mode 100644
index 000000000000..a2837d888cc9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noreap.ksh
@@ -0,0 +1,128 @@
+#
+# 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 (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <unistd.h>
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+ DTRACE_PROBE(test_prov, probe1);
+}
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe probe1();
+};
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -Zwqs /dev/stdin <<EOF
+
+ BEGIN
+ {
+ spec = speculation();
+ speculate(spec);
+ printf("this is speculative!\n");
+ }
+
+ test_prov*:::
+ {
+ probeid = id;
+ }
+
+ tick-1sec
+ /probeid == 0/
+ {
+ printf("launching test\n");
+ system("./test");
+ }
+
+ tick-1sec
+ /probeid != 0/
+ {
+ printf("attempting re-enabling\n");
+ system("dtrace -e -x errtags -i %d", probeid);
+ attempts++;
+ }
+
+ tick-1sec
+ /attempts > 10/
+ {
+ exit(0);
+ }
+EOF
+}
+
+script 2>&1 | tee test.out
+
+#
+# It should be true that our probe was not reaped after the provider was made
+# defunct: the speculative tracing action prevents reaping of any ECB in the
+# enabling.
+#
+status=0
+
+if grep D_PDESC_INVAL test.out 2> /dev/null 1>&2 ; then
+ status=1
+else
+ grep D_PROC_GRAB test.out 2> /dev/null 1>&2
+ status=$?
+fi
+
+cd /
+rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noreapring.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noreapring.ksh
new file mode 100644
index 000000000000..16ff34ae4217
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.noreapring.ksh
@@ -0,0 +1,124 @@
+#
+# 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 (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <unistd.h>
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+ DTRACE_PROBE(test_prov, probe1);
+}
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe probe1();
+};
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -Zwqs /dev/stdin <<EOF
+ test_prov*:::
+ {
+ probeid = id;
+ }
+
+ tick-1sec
+ /probeid == 0/
+ {
+ printf("launching test\n");
+ system("./test");
+ }
+
+ tick-1sec
+ /probeid != 0/
+ {
+ printf("attempting re-enabling\n");
+ system("dtrace -e -x errtags -i %d", probeid);
+ attempts++;
+ }
+
+ tick-1sec
+ /attempts > 10/
+ {
+ exit(0);
+ }
+EOF
+}
+
+$dtrace -x bufpolicy=ring -ZwqP test_prov\* > /dev/null 2>&1 &
+background=$!
+echo launched ring buffered enabling as pid $background
+script 2>&1 | tee test.out
+
+#
+# It should be true that our probe was not reaped after the provider was made
+# defunct: the active ring buffer in the earlier enabling prevents reaping of
+# any of the earlier enabling's ECBs.
+#
+status=0
+
+if grep D_PDESC_INVAL test.out 2> /dev/null 1>&2 ; then
+ status=1
+else
+ grep D_PROC_GRAB test.out 2> /dev/null 1>&2
+ status=$?
+fi
+
+kill $background
+cd /
+rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.onlyenabled.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.onlyenabled.ksh
new file mode 100644
index 000000000000..db2771ab32c0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.onlyenabled.ksh
@@ -0,0 +1,82 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ if (TEST_PROV_GO_ENABLED())
+ return (2);
+
+ return (0);
+}
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+cd /
+/bin/rm -rf $DIR
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.reap.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.reap.ksh
new file mode 100644
index 000000000000..8ce1dc0181d0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.reap.ksh
@@ -0,0 +1,115 @@
+#
+# 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 (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <unistd.h>
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+ DTRACE_PROBE(test_prov, probe1);
+}
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe probe1();
+};
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -Zwqs /dev/stdin <<EOF
+ test_prov*:::
+ {
+ probeid = id;
+ }
+
+ tick-1sec
+ /probeid == 0/
+ {
+ printf("launching test\n");
+ system("./test");
+ }
+
+ tick-1sec
+ /probeid != 0/
+ {
+ printf("attempting re-enabling\n");
+ system("dtrace -e -x errtags -i %d", probeid);
+ attempts++;
+ }
+
+ tick-1sec
+ /attempts > 10/
+ {
+ exit(0);
+ }
+EOF
+}
+
+script 2>&1 | tee test.out
+
+#
+# It should be true that our probe was reaped over the course of the enabling,
+# causing the embedded DTrace invocation to fail on an invalid probe (that is,
+# D_PDESC_INVAL) instead of an inability to grab the underlying process
+# (D_PROC_GRAB).
+#
+grep D_PDESC_INVAL test.out 2> /dev/null 1>&2
+status=$?
+
+cd /
+rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.reeval.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.reeval.ksh
new file mode 100644
index 000000000000..2c6c7bc9f89a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.reeval.ksh
@@ -0,0 +1,98 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <sys/sdt.h>
+
+int
+main(int argc, char **argv)
+{
+ DTRACE_PROBE(test_prov, zero);
+}
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe zero();
+};
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -wZs /dev/stdin <<EOF
+ BEGIN
+ {
+ system("$DIR/test");
+ }
+
+ test_prov*:::
+ {
+ seen = 1;
+ }
+
+ proc:::exit
+ /progenyof(\$pid) && execname == "test"/
+ {
+ exit(seen ? 0 : 2);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.sameprovmulti.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.sameprovmulti.ksh
new file mode 100644
index 000000000000..2e404f4b8df6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.sameprovmulti.ksh
@@ -0,0 +1,99 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
+#
+
+#
+# This test assures that we can have the same provider name across multiple
+# probe definitions, and that the result will be the union of those
+# definitions. In particular, libusdt depends on this when (for example)
+# node modules that create a provider are loaded multiple times due to
+# being included by different modules.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <unistd.h>
+
+void
+main()
+{
+EOF
+
+objs=
+
+for oogle in bagnoogle stalloogle cockoogle; do
+ cat > $oogle.c <<EOF
+#include <sys/sdt.h>
+
+void
+$oogle()
+{
+ DTRACE_PROBE(doogle, $oogle);
+}
+EOF
+
+ cat > $oogle.d <<EOF
+provider doogle {
+ probe $oogle();
+};
+EOF
+
+ cc -c $oogle.c
+
+ if [ $? -ne 0 ]; then
+ print -u2 "failed to compile $oogle.c"
+ exit 1
+ fi
+
+ $dtrace -G -s $oogle.d $oogle.o -o $oogle.d.o
+
+ if [ $? -ne 0 ]; then
+ print -u2 "failed to process $oogle.d"
+ exit 1
+ fi
+
+ objs="$objs $oogle.o $oogle.d.o"
+ echo $oogle'();' >> test.c
+done
+
+echo "}" >> test.c
+
+cc -o test test.c $objs
+
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+
+$dtrace -n 'doogle$target:::{@[probename] = count()}' \
+ -n 'END{printa("%-10s %@d\n", @)}' -x quiet -x aggsortkey -Zc ./test
+
+if [ $? -ne 0 ]; then
+ print -u2 "failed to execute test"
+ exit 1
+fi
+
+cd /
+rm -rf $DIR
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.sameprovmulti.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.sameprovmulti.ksh.out
new file mode 100644
index 000000000000..bdeeb1ef29b9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.sameprovmulti.ksh.out
@@ -0,0 +1,4 @@
+bagnoogle 1
+cockoogle 1
+stalloogle 1
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static.ksh
new file mode 100644
index 000000000000..8a19c77010b6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static.ksh
@@ -0,0 +1,98 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <unistd.h>
+#include <sys/sdt.h>
+
+static void
+foo(void)
+{
+ DTRACE_PROBE(test_prov, probe1);
+ DTRACE_PROBE(test_prov, probe2);
+}
+
+int
+main(int argc, char **argv)
+{
+ DTRACE_PROBE(test_prov, probe1);
+ DTRACE_PROBE(test_prov, probe2);
+ foo();
+}
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe probe1();
+ probe probe2();
+};
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -c ./test -qs /dev/stdin <<EOF
+ test_prov\$target:::
+ {
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static.ksh.out
new file mode 100644
index 000000000000..a559d97a87d0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static.ksh.out
@@ -0,0 +1,5 @@
+test:main:probe1
+test:main:probe2
+test:foo:probe1
+test:foo:probe2
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static2.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static2.ksh
new file mode 100644
index 000000000000..a6ddfe854156
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static2.ksh
@@ -0,0 +1,108 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+# Rebuilding an object file containing DOF changes slightly when the object
+# files containing the probes have already been modified. This tests that
+# case by generating the DOF object, removing it, and building it again.
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.c <<EOF
+#include <unistd.h>
+#include <sys/sdt.h>
+
+static void
+foo(void)
+{
+ DTRACE_PROBE(test_prov, probe1);
+ DTRACE_PROBE(test_prov, probe2);
+}
+
+int
+main(int argc, char **argv)
+{
+ DTRACE_PROBE(test_prov, probe1);
+ DTRACE_PROBE(test_prov, probe2);
+ foo();
+}
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe probe1();
+ probe probe2();
+};
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create initial DOF"
+ exit 1
+fi
+rm -f prov.o
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create final DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script()
+{
+ $dtrace -c ./test -qs /dev/stdin <<EOF
+ test_prov\$target:::
+ {
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static2.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static2.ksh.out
new file mode 100644
index 000000000000..a559d97a87d0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.static2.ksh.out
@@ -0,0 +1,5 @@
+test:main:probe1
+test:main:probe2
+test:foo:probe1
+test:foo:probe2
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.user.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.user.ksh
new file mode 100644
index 000000000000..3c2295837ec7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.user.ksh
@@ -0,0 +1,96 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ print -u2 "failed to generate header file"
+ exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+ TEST_PROV_GO();
+
+ return (0);
+}
+EOF
+
+cc -c test.c
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.c"
+ exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+script() {
+ $dtrace -c 'ppriv -e -s A=basic ./test' -Zqs /dev/stdin <<EOF
+ test_prov\$target:::
+ {
+ printf("%s:%s:%s\n", probemod, probefunc, probename);
+ }
+EOF
+}
+
+script
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.user.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.user.ksh.out
new file mode 100644
index 000000000000..b856cc59f44c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.user.ksh.out
@@ -0,0 +1,2 @@
+test:main:go
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.bigstack.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.bigstack.c
new file mode 100644
index 000000000000..edd3dd157d42
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.bigstack.c
@@ -0,0 +1,61 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void grow1(int);
+
+void
+grow(int frame)
+{
+ /*
+ * Create a ridiculously large stack - enough to push us over
+ * the default setting of 'dtrace_ustackdepth_max' (2048).
+ */
+ if (frame >= 2048)
+ for (;;)
+ getpid();
+
+ grow1(++frame);
+}
+
+void
+grow1(int frame)
+{
+ grow(++frame);
+}
+
+int
+main(int argc, char *argv[])
+{
+ grow(1);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.bigstack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.bigstack.d
new file mode 100644
index 000000000000..66fda5ba2818
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.bigstack.d
@@ -0,0 +1,45 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+syscall::getpid:entry
+/pid == $1/
+{
+ @[ustackdepth] = count();
+}
+
+ERROR
+/arg4 == DTRACEFLT_BADSTACK/
+{
+ exit(0);
+}
+
+profile:::tick-1s
+/++n == 10/
+{
+ exit(1)
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.depth.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.depth.ksh
new file mode 100644
index 000000000000..26cff421aa59
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.depth.ksh
@@ -0,0 +1,110 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+file=out.$$
+dtrace=$1
+
+rm -f $file
+
+$dtrace -o $file -c date -s /dev/stdin <<EOF
+
+ #pragma D option quiet
+ #pragma D option bufsize=1M
+ #pragma D option bufpolicy=fill
+
+ pid\$target:::entry,
+ pid\$target:::return,
+ pid\$target:a.out::,
+ syscall:::return,
+ profile:::profile-997
+ /pid == \$target/
+ {
+ printf("START %s:%s:%s:%s\n",
+ probeprov, probemod, probefunc, probename);
+ trace(ustackdepth);
+ ustack(100);
+ trace("END\n");
+ }
+
+ tick-1sec
+ /n++ == 10/
+ {
+ trace("test timed out...");
+ exit(1);
+ }
+EOF
+
+status=$?
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+ exit $status
+fi
+
+perl /dev/stdin $file <<EOF
+ while (<>) {
+ chomp;
+
+ last if /^\$/;
+
+ die "expected START at \$.\n" unless /^START/;
+
+ \$_ = <>;
+ chomp;
+ die "expected depth (\$_) at \$.\n" unless /^(\d+)\$/;
+ \$depth = \$1;
+
+ for (\$i = 0; \$i < \$depth; \$i++) {
+ \$_ = <>;
+ chomp;
+ die "unexpected END at \$.\n" if /^END/;
+ }
+
+ \$_ = <>;
+ chomp;
+ die "expected END at \$.\n" unless /^END\$/;
+ }
+EOF
+
+status=$?
+
+count=`wc -l $file | cut -f1 -do`
+if [ "$count" -lt 1000 ]; then
+ echo $tst: output was too short
+ status=1
+fi
+
+
+if [ "$status" -eq 0 ]; then
+ rm -f $file
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.spin.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.spin.c
new file mode 100644
index 000000000000..bdeb16d9d73c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.spin.c
@@ -0,0 +1,61 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+
+volatile long long count = 0;
+
+int
+baz(int a)
+{
+ (void) getpid();
+ while (count != -1) {
+ count++;
+ a++;
+ }
+
+ return (a + 1);
+}
+
+int
+bar(int a)
+{
+ return (baz(a + 1) - 1);
+}
+
+int
+foo(int a, int b)
+{
+ return (bar(a) - b);
+}
+
+int
+main(int argc, char **argv)
+{
+ return (foo(argc, (int)argv) == 0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.spin.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.spin.ksh
new file mode 100644
index 000000000000..1a7e0e12365b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/ustack/tst.spin.ksh
@@ -0,0 +1,139 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+file=out.$$
+dtrace=$1
+
+rm -f $file
+
+dir=`dirname $tst`
+
+$dtrace -o $file -c $dir/tst.spin.exe -s /dev/stdin <<EOF
+
+ #pragma D option quiet
+ #pragma D option destructive
+ #pragma D option evaltime=main
+
+ /*
+ * Toss out the first 100 samples to wait for the program to enter
+ * its steady state.
+ */
+
+ profile-1999
+ /pid == \$target && n++ > 100/
+ {
+ @total = count();
+ @stacks[ustack(4)] = count();
+ }
+
+ tick-1s
+ {
+ secs++;
+ }
+
+ tick-1s
+ /secs > 5/
+ {
+ done = 1;
+ }
+
+ tick-1s
+ /secs > 10/
+ {
+ trace("test timed out");
+ exit(1);
+ }
+
+ profile-1999
+ /pid == \$target && done/
+ {
+ raise(SIGINT);
+ exit(0);
+ }
+
+ END
+ {
+ printa("TOTAL %@u\n", @total);
+ printa("START%kEND\n", @stacks);
+ }
+EOF
+
+status=$?
+if [ "$status" -ne 0 ]; then
+ echo $tst: dtrace failed
+ exit $status
+fi
+
+perl /dev/stdin $file <<EOF
+ \$_ = <>;
+ chomp;
+ die "output problem\n" unless /^TOTAL (\d+)/;
+ \$count = \$1;
+ die "too few samples (\$count)\n" unless \$count >= 1000;
+
+ while (<>) {
+ chomp;
+
+ last if /^$/;
+
+ die "expected START at \$.\n" unless /^START/;
+
+
+ \$_ = <>;
+ chomp;
+ die "expected END at \$.\n" unless /\`baz\+/;
+
+ \$_ = <>;
+ chomp;
+ die "expected END at \$.\n" unless /\`bar\+/;
+
+ \$_ = <>;
+ chomp;
+ die "expected END at \$.\n" unless /\`foo\+/;
+
+ \$_ = <>;
+ chomp;
+ die "expected END at \$.\n" unless /\`main\+/;
+
+ \$_ = <>;
+ chomp;
+ die "expected END at \$.\n" unless /^END\$/;
+ }
+
+EOF
+
+status=$?
+if [ "$status" -eq 0 ]; then
+ rm -f $file
+fi
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.gid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.gid.d
new file mode 100644
index 000000000000..23fcf38947d7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.gid.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+/curpsinfo->pr_gid == gid/
+{
+ exit(0);
+}
+
+BEGIN
+{
+ printf("%d != %d\n", curpsinfo->pr_gid, gid);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.nullassign.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.nullassign.d
new file mode 100644
index 000000000000..accc763fe94d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.nullassign.d
@@ -0,0 +1,94 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+{
+ die = "Die";
+ tap = ", SystemTap, ";
+ the = "The";
+}
+
+BEGIN
+{
+ phrase = strjoin(die, tap);
+ phrase = strjoin(phrase, die);
+ expected = "Die, SystemTap, Die";
+}
+
+BEGIN
+/phrase != expected/
+{
+ printf("global: expected '%s', found '%s'\n", expected, phrase);
+ exit(1);
+}
+
+BEGIN
+{
+ this->phrase = strjoin(the, tap);
+}
+
+BEGIN
+{
+ this->phrase = strjoin(this->phrase, the);
+ expected = "The, SystemTap, The";
+}
+
+BEGIN
+/this->phrase != expected/
+{
+ printf("clause-local: expected '%s', found '%s'\n",
+ expected, this->phrase);
+ exit(2);
+}
+
+BEGIN
+{
+ phrase = NULL;
+ this->phrase = NULL;
+}
+
+BEGIN
+/phrase != NULL/
+{
+ printf("expected global to be NULL\n");
+ exit(3);
+}
+
+BEGIN
+/this->phrase != NULL/
+{
+ printf("expected clause-local to be NULL\n");
+ exit(4);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ppid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ppid.d
new file mode 100644
index 000000000000..5f0da5fdcbf0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ppid.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+/curpsinfo->pr_ppid == ppid/
+{
+ exit(0);
+}
+
+BEGIN
+{
+ printf("%d != %d\n", curpsinfo->pr_ppid, ppid);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ucaller.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ucaller.ksh
new file mode 100644
index 000000000000..c09825ec21bc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ucaller.ksh
@@ -0,0 +1,65 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This test is a bit naughty; it's assuming that ld.so.1 has an implementation
+# of calloc(3C), and that it's implemented in terms of the ld.so.1
+# implementation of malloc(3C). If you're reading this comment because
+# those assumptions have become false, please accept my apologies...
+#
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+$dtrace -qs /dev/stdin -c "/bin/echo" <<EOF
+pid\$target:ld.so.1:calloc:entry
+{
+ self->calloc = 1;
+}
+
+pid\$target:ld.so.1:malloc:entry
+/self->calloc/
+{
+ @[umod(ucaller), ufunc(ucaller)] = count();
+}
+
+pid\$target:ld.so.1:calloc:return
+/self->calloc/
+{
+ self->calloc = 0;
+}
+
+END
+{
+ printa("%A %A\n", @);
+}
+EOF
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ucaller.ksh.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ucaller.ksh.out
new file mode 100644
index 000000000000..86c72a4e1631
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.ucaller.ksh.out
@@ -0,0 +1,3 @@
+
+ld.so.1 ld.so.1`calloc
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.uid.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.uid.d
new file mode 100644
index 000000000000..bf1c9dc56695
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.uid.d
@@ -0,0 +1,41 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+BEGIN
+/curpsinfo->pr_uid == uid/
+{
+ exit(0);
+}
+
+BEGIN
+{
+ printf("%d != %d\n", curpsinfo->pr_uid, uid);
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.walltimestamp.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.walltimestamp.d
new file mode 100644
index 000000000000..e17bb946dba5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/vars/tst.walltimestamp.d
@@ -0,0 +1,55 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+uint64_t now;
+
+BEGIN
+{
+ now = 18252813184; /* Jan 1, 2004 00:00:00 */
+}
+
+BEGIN
+/walltimestamp < timestamp/
+{
+ printf("%d < %d", walltimestamp, timestamp);
+ exit(1);
+}
+
+BEGIN
+/walltimestamp < now/
+{
+ printf("%d (%Y) is before %Y", walltimestamp, walltimestamp, now);
+ exit(2);
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/version/tst.1.0.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/version/tst.1.0.d
new file mode 100644
index 000000000000..0ab2af787b10
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/version/tst.1.0.d
@@ -0,0 +1,48 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option version=1.0
+
+/*
+ * The following identifiers were added as D built-ins as of version 1.1.
+ * Using these identifiers as user-specified variables should be illegal in
+ * that and any later versions, but legal in earlier versions.
+ */
+int strstr;
+int strchr;
+int strrchr;
+int strtok;
+int substr;
+int index;
+int freopen;
+
+BEGIN
+{
+ exit(0);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/arrays/tst.uregsarray.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/arrays/tst.uregsarray.d
new file mode 100644
index 000000000000..5543c0a575e6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/arrays/tst.uregsarray.d
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Positive test to make sure that we can invoke x86
+ * ureg[] aliases.
+ *
+ * SECTION: User Process Tracing/uregs Array
+ *
+ * NOTES: This test does no verification - the value of the output
+ * is not deterministic.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("R_GS = 0x%x\n", uregs[R_GS]);
+ printf("R_ES = 0x%x\n", uregs[R_ES]);
+ printf("R_DS = 0x%x\n", uregs[R_DS]);
+ printf("R_EDI = 0x%x\n", uregs[R_EDI]);
+ printf("R_ESI = 0x%x\n", uregs[R_ESI]);
+ printf("R_EBP = 0x%x\n", uregs[R_EBP]);
+ printf("R_EBX = 0x%x\n", uregs[R_EBX]);
+ printf("R_EDX = 0x%x\n", uregs[R_EDX]);
+ printf("R_ECX = 0x%x\n", uregs[R_ECX]);
+ printf("R_EAX = 0x%x\n", uregs[R_EAX]);
+ printf("R_TRAPNO = 0x%x\n", uregs[R_TRAPNO]);
+ printf("R_ERR = 0x%x\n", uregs[R_ERR]);
+ printf("R_EIP = 0x%x\n", uregs[R_EIP]);
+ printf("R_CS = 0x%x\n", uregs[R_CS]);
+ printf("R_EFL = 0x%x\n", uregs[R_EFL]);
+ printf("R_UESP = 0x%x\n", uregs[R_UESP]);
+ printf("R_SS = 0x%x\n", uregs[R_SS]);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyin.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyin.d
new file mode 100644
index 000000000000..f14c8afc8cad
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyin.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ASSERTION:
+ * On IA/32, there is a single 32-bit address space that is partitioned
+ * between user-level and kernel-level. copyin()/copyinstr() and
+ * copyout()/copyoutstr() must check that addresses specified as
+ * user-level addresses are actually at user-level. This test attempts
+ * to perform an illegal copyin() from a kernel address. It asserts that
+ * the fault type is DTRACEFLT_BADADDR and that the bad address is set to
+ * the kernel address from which the copyin() was attempted.
+ *
+ * SECTION: Actions and Subroutines/copyin();
+ * Actions and Subroutines/copyin();
+ * User Process Tracing/copyin() and copyinstr()
+ */
+
+BEGIN
+{
+ dtrace_zero = copyin((uintptr_t)&`dtrace_zero, sizeof (int));
+ exit(1);
+}
+
+ERROR
+{
+ exit(arg4 == DTRACEFLT_BADADDR &&
+ arg5 == (uint64_t)&`dtrace_zero ? 0 : 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyinstr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyinstr.d
new file mode 100644
index 000000000000..ac049936ee64
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyinstr.d
@@ -0,0 +1,52 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * On IA/32, there is a single 32-bit address space that is partitioned
+ * between user-level and kernel-level. copyin()/copyinstr() and
+ * copyout()/copyoutstr() must check that addresses specified as
+ * user-level addresses are actually at user-level. This test attempts
+ * to perform an illegal copyinstr() from a kernel address. It asserts
+ * that the fault type is DTRACEFLT_BADADDR and that the bad address is
+ * set to the kernel address from which the copyinstr() was attempted.
+ *
+ * SECTION: Actions and Subroutines/copyinstr();
+ * User Process Tracing/copyin() and copyinstr()
+ */
+
+BEGIN
+{
+ os = copyinstr((uintptr_t)&`utsname);
+ exit(1);
+}
+
+ERROR
+{
+ exit(arg4 == DTRACEFLT_BADADDR && arg5 == (uint64_t)&`utsname ? 0 : 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyout.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyout.d
new file mode 100644
index 000000000000..8909cd3af2e6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyout.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * On IA/32, there is a single 32-bit address space that is partitioned
+ * between user-level and kernel-level. copyin()/copyinstr() and
+ * copyout()/copyoutstr() must check that addresses specified as
+ * user-level addresses are actually at user-level. This test attempts
+ * to perform an illegal copyout() to a kernel address. It asserts that
+ * the fault type is DTRACEFLT_BADADDR and that the bad address is set to
+ * the kernel address to which the copyout() was attempted.
+ *
+ * SECTION: Actions and Subroutines/copyout()
+ *
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ this->a = (uint32_t *)alloca(4);
+ *this->a = -1;
+ copyout(this->a, (uintptr_t)&`clock, 4);
+ exit(1);
+}
+
+ERROR
+{
+ exit(arg4 == DTRACEFLT_BADADDR && arg5 == (uint64_t)&`clock ? 0 : 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyoutstr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyoutstr.d
new file mode 100644
index 000000000000..d7166cd25674
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/funcs/tst.badcopyoutstr.d
@@ -0,0 +1,56 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ * On IA/32, there is a single 32-bit address space that is partitioned
+ * between user-level and kernel-level. copyin()/copyinstr() and
+ * copyout()/copyoutstr() must check that addresses specified as
+ * user-level addresses are actually at user-level. This test attempts
+ * to perform an illegal copyoutstr() to a kernel address. It asserts
+ * that the fault type is DTRACEFLT_BADADDR and that the bad address is
+ * set to the kernel address to which the copyoutstr() was attempted.
+ *
+ * SECTION: Actions and Subroutines/copyoutstr()
+ *
+ */
+
+#pragma D option destructive
+
+BEGIN
+{
+ this->str = alloca(10);
+ bcopy("kablammo!", this->str, 10);
+ copyoutstr(this->str, (uintptr_t)&`clock, 10);
+ exit(1);
+}
+
+ERROR
+{
+ exit(arg4 == DTRACEFLT_BADADDR && arg5 == (uint64_t)&`clock ? 0 : 1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.badinstr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.badinstr.d
new file mode 100644
index 000000000000..50753b8a1899
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.badinstr.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Make sure that DTrace doesn't explode on an invalid instruction.
+ */
+
+pid$1:a.out:badfunc:entry
+{
+}
+
+BEGIN
+{
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.badinstr.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.badinstr.s
new file mode 100644
index 000000000000..27f7f991635b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.badinstr.s
@@ -0,0 +1,41 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .long 0
+
+ ENTRY(badfunc)
+ .byte 0xff
+ .byte 0xff
+ SET_SIZE(badfunc)
+
+ ENTRY(main)
+1: jmp 1b
+ SET_SIZE(main)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.branch.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.branch.d
new file mode 100644
index 000000000000..cfcf0a715d1a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.branch.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * SECTION:
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option destructive
+
+pid$1:a.out:waiting:entry
+{
+ this->a = (char *)alloca(1);
+ *this->a = 1;
+ copyout(this->a, arg0, 1);
+}
+
+pid$1:a.out:main:,
+pid$1:a.out:other:
+{
+}
+
+pid$1:a.out:bad:entry
+{
+ exit(1);
+}
+
+syscall::rexit:entry
+/pid == $1/
+{
+ exit(0);
+}
+
+
+BEGIN
+{
+ /*
+ * Let's just do this for 5 seconds.
+ */
+ timeout = timestamp + 5000000000;
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.branch.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.branch.s
new file mode 100644
index 000000000000..82a58920814f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.branch.s
@@ -0,0 +1,73 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .long 0
+
+ ENTRY(waiting)
+ pushl %ebp
+ movl %esp, %ebp
+ movl 8(%ebp), %eax
+ movl (%eax), %eax
+ popl %ebp
+ ret
+ SET_SIZE(waiting)
+
+ ENTRY(main)
+ pushl %ebp
+ movl %esp, %ebp
+ subl $0x4, %esp
+ movl $0x0, -4(%ebp)
+
+1:
+ leal -4(%ebp), %eax
+ pushl %eax
+ call waiting
+ addl $0x4, %esp
+
+ testl %eax, %eax
+ jz 1b
+
+ addl $0x4, %esp
+
+ xorl %eax, %eax
+ testl %eax, %eax
+ jz other
+
+ ALTENTRY(bad)
+ movl 0x0, %eax
+ SET_SIZE(bad)
+ SET_SIZE(main)
+
+ ENTRY(other)
+ xorl %eax, %eax
+ popl %ebp
+ ret
+ SET_SIZE(other)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.embedded.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.embedded.d
new file mode 100644
index 000000000000..c484c3f0c721
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.embedded.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * SECTION:
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option destructive
+
+pid$1:a.out:waiting:entry
+{
+ this->a = (char *)alloca(1);
+ *this->a = 1;
+ copyout(this->a, arg0, 1);
+}
+
+pid$1:a.out:main:,
+pid$1:a.out:inner:
+{
+}
+
+syscall::rexit:entry
+/pid == $1/
+{
+ exit(0);
+}
+
+
+BEGIN
+{
+ /*
+ * Let's just do this for 5 seconds.
+ */
+ timeout = timestamp + 5000000000;
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.embedded.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.embedded.s
new file mode 100644
index 000000000000..134a5aff06d5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.embedded.s
@@ -0,0 +1,68 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .long 0
+
+ ENTRY(waiting)
+ pushl %ebp
+ movl %esp, %ebp
+ movl 8(%ebp), %eax
+ movl (%eax), %eax
+ popl %ebp
+ ret
+ SET_SIZE(waiting)
+
+ ENTRY(main)
+ pushl %ebp
+ movl %esp, %ebp
+ subl $0x4, %esp
+ movl $0x0, -4(%ebp)
+1:
+ leal -4(%ebp), %eax
+ pushl %eax
+ call waiting
+ addl $0x4, %esp
+
+ testl %eax, %eax
+ jz 1b
+
+ addl $0x4, %esp
+
+ ALTENTRY(inner)
+ nop
+ nop
+ nop
+ SET_SIZE(inner)
+
+ xorl %eax, %eax
+ popl %ebp
+ ret
+ SET_SIZE(main)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.ret.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.ret.d
new file mode 100644
index 000000000000..358466fe5456
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.ret.d
@@ -0,0 +1,76 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Validated the emulation of various flavors of the return
+ * instruction.
+ */
+
+#pragma D option destructive
+
+pid$1:a.out:waiting:entry
+{
+ this->a = (char *)alloca(1);
+ *this->a = 1;
+ copyout(this->a, arg0, 1);
+}
+
+pid$1:a.out:ret*:
+{
+ printf("%%sp = %x", uregs[R_SP]);
+}
+
+pid$1:a.out:ret*:return
+{
+}
+
+pid$1:a.out:done:entry
+{
+ exit(0);
+}
+
+pid$1:a.out:main:return
+{
+ printf("%%eax = %x", uregs[R_EAX]);
+}
+
+BEGIN
+{
+ /*
+ * Let's just do this for 5 seconds.
+ */
+ timeout = timestamp + 5000000000;
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.ret.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.ret.s
new file mode 100644
index 000000000000..bccdb1a36b34
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.ret.s
@@ -0,0 +1,114 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .long 0
+
+ ENTRY(ret1)
+ ret
+ SET_SIZE(ret1)
+
+ ENTRY(ret2)
+ repz
+ ret
+ SET_SIZE(ret2)
+
+ ENTRY(ret3)
+ ret $0
+ SET_SIZE(ret3)
+
+ ENTRY(ret4)
+ repz
+ ret $0
+ SET_SIZE(ret4)
+
+ ENTRY(ret5)
+ pushl (%esp)
+ ret $4
+ SET_SIZE(ret5)
+
+ ENTRY(ret6)
+ pushl (%esp)
+ repz
+ ret $4
+ SET_SIZE(ret6)
+
+ ENTRY(waiting)
+ pushl %ebp
+ movl %esp, %ebp
+ movl 8(%ebp), %eax
+ movl (%eax), %eax
+ movl %ebp, %esp
+ popl %ebp
+ ret
+ SET_SIZE(waiting)
+
+ ENTRY(main)
+ pushl %ebp
+ movl %esp, %ebp
+ subl $0x4, %esp
+ movl $0x0, -4(%ebp)
+
+1:
+ leal -4(%ebp), %eax
+ pushl %eax
+ call waiting
+ addl $0x4, %esp
+
+ testl %eax, %eax
+ jz 1b
+
+ movl %esp, %esi
+
+ call ret1
+ call ret2
+ call ret3
+ call ret4
+ call ret5
+ call ret6
+
+ cmpl %esp, %esi
+ jne 1f
+
+ ALTENTRY(done)
+ nop
+ SET_SIZE(done)
+
+ movl $0, %eax
+ movl %ebp, %esp
+ popl %ebp
+ ret
+
+1:
+ movl $1, %eax
+ movl %ebp, %esp
+ popl %ebp
+ ret
+ SET_SIZE(main)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.retlist.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.retlist.ksh
new file mode 100644
index 000000000000..5477f5c9f6c3
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.retlist.ksh
@@ -0,0 +1,50 @@
+#!/bin/ksh -p
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+# Make sure we can match against 2-byte rets
+
+./tst.retlist.exe&
+PID=$!
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+match=`$dtrace -l -n pid$PID:a.out:simple: -n pid$PID:a.out:complex: | wc -l`
+
+kill $PID
+
+if [ "$match" -ne 12 ]; then
+ echo wrong number of matched probes: $match
+ exit 1
+fi
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.retlist.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.retlist.s
new file mode 100644
index 000000000000..e85e9f5c8291
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/pid/tst.retlist.s
@@ -0,0 +1,51 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .long 0
+
+ ENTRY(simple)
+ repz
+ ret
+ SET_SIZE(simple)
+
+ ENTRY(complex)
+ pushl %ebp
+ movl %esp, %ebp
+ movl 8(%ebp), %eax
+ movl (%eax), %eax
+ popl %ebp
+ repz
+ ret
+ SET_SIZE(complex)
+
+ ENTRY(main)
+1: jmp 1b
+ SET_SIZE(main)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/annotated_helper.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/annotated_helper.d
new file mode 100644
index 000000000000..3b977097c683
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/annotated_helper.d
@@ -0,0 +1,32 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+dtrace:helper:ustack:
+{
+ "@it's annotated"
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/helper_helper.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/helper_helper.d
new file mode 100644
index 000000000000..8abc47d006dc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/helper_helper.d
@@ -0,0 +1,32 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+dtrace:helper:ustack:
+{
+ "<it's working>"
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.c
new file mode 100644
index 000000000000..8cdf8abad5af
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.c
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+int
+baz(void)
+{
+ return (8);
+}
+
+int
+main(int argc, char **argv)
+{
+ for (;;) {
+ baz();
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.d
new file mode 100644
index 000000000000..dd795bece03f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.d
@@ -0,0 +1,35 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+pid$1:a.out:baz:entry
+{
+ ustack(1, 1024);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.d.out
new file mode 100644
index 000000000000..806d6a2b43dc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.annotated.d.out
@@ -0,0 +1,4 @@
+
+ tst.annotated.exe`baz
+ [ it's annotated ]
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.circstack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.circstack.d
new file mode 100644
index 000000000000..78218bd72aea
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.circstack.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+syscall::getpid:entry
+/pid == $1/
+{
+ @[ustackdepth] = count();
+}
+
+ERROR
+/arg4 == DTRACEFLT_BADSTACK/
+{
+ exit(0);
+}
+
+profile:::tick-1s
+/++n == 10/
+{
+ exit(1)
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.circstack.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.circstack.s
new file mode 100644
index 000000000000..3bf7c0bf4313
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.circstack.s
@@ -0,0 +1,43 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .long 0
+
+ ENTRY(main)
+ pushl %ebp
+ movl %esp, %ebp
+ movl %esp, (%ebp)
+loop:
+ call getpid
+ jmp loop
+ leave
+ ret
+ SET_SIZE(main)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.c
new file mode 100644
index 000000000000..69ab6a85a417
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.c
@@ -0,0 +1,82 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <strings.h>
+
+int
+baz(void)
+{
+ return (8);
+}
+
+static int
+foo(void)
+{
+ /*
+ * In order to assure that our helper is properly employed to identify
+ * the frame, we're going to trampoline through data.
+ */
+ uint8_t instr[] = {
+ 0x55, /* pushl %ebp */
+ 0x8b, 0xec, /* movl %esp, %ebp */
+ 0xe8, 0x0, 0x0, 0x0, 0x0, /* call baz */
+ 0x8b, 0xe5, /* movl %ebp, %esp */
+ 0x5d, /* popl %ebp */
+ 0xc3 /* ret */
+ };
+ uint8_t *fp = malloc(sizeof (instr));
+
+ /*
+ * Do our little relocation dance.
+ */
+ *((int *)&instr[4]) = (uintptr_t)baz - (uintptr_t)&fp[8];
+
+ /*
+ * Copy the code to the heap (it's a pain to build in ON with an
+ * executable stack).
+ */
+ bcopy(instr, fp, sizeof (instr));
+
+ (*(int (*)(void))fp)();
+
+ free(fp);
+
+ return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+ for (;;) {
+ foo();
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.d
new file mode 100644
index 000000000000..ce2b9b30f14f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * SECTION:
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+pid$1:a.out:baz:entry
+{
+ ustack(2, 1024);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.d.out
new file mode 100644
index 000000000000..29646288e7ac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i386/ustack/tst.helper.d.out
@@ -0,0 +1,4 @@
+
+ tst.helper.exe`baz
+ <it's working>
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.basic.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.basic.ksh
new file mode 100755
index 000000000000..3a5ce6f0d064
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.basic.ksh
@@ -0,0 +1,77 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# ASSERTION: Make sure that we can map in and read the Xen trace buffers.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+#
+# Do not fail the test in a domU
+#
+if [ ! -c /dev/xen/privcmd ]; then
+ exit 0
+fi
+
+dtrace=$1
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ xdt:sched::on-cpu
+ /arg0 == 0/
+ {
+ self->on++;
+ }
+
+ xdt:sched::off-cpu
+ /arg0 == 0 && self->on/
+ {
+ self->off++;
+ }
+
+ xdt:sched::off-cpu
+ /self->on > 50 && self->off > 50/
+ {
+ exit(0);
+ }
+
+ profile:::tick-1sec
+ /n++ > 10/
+ {
+ exit(1);
+ }
+EOF
+}
+
+script
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.hvmenable.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.hvmenable.ksh
new file mode 100755
index 000000000000..3719c2026545
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.hvmenable.ksh
@@ -0,0 +1,64 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# ASSERTION: HVM probes should enable successfully.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+#
+# Do not fail the test in a domU
+#
+if [ ! -c /dev/xen/privcmd ]; then
+ exit 0
+fi
+
+dtrace=$1
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ dtrace:::BEGIN
+ {
+ exit(0);
+ }
+
+ xdt:hvm::vmentry,
+ xdt:hvm::vmexit
+ {}
+EOF
+}
+
+script
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.memenable.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.memenable.ksh
new file mode 100755
index 000000000000..25d39cbfbc86
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.memenable.ksh
@@ -0,0 +1,65 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# ASSERTION: Mem probes should enable successfully.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+#
+# Do not fail the test in a domU
+#
+if [ ! -c /dev/xen/privcmd ]; then
+ exit 0
+fi
+
+dtrace=$1
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ dtrace:::BEGIN
+ {
+ exit(0);
+ }
+
+ xdt:mem::page-grant-map,
+ xdt:mem::page-grant-unmap,
+ xdt:mem::page-grant-transfer
+ {}
+EOF
+}
+
+script
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.schedargs.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.schedargs.ksh
new file mode 100755
index 000000000000..5b14fc989138
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.schedargs.ksh
@@ -0,0 +1,121 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# ASSERTION: Sched probe arguments should be valid.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+#
+# do not fail test in a domU
+#
+if [ ! -c /dev/xen/privcmd ]; then
+ exit 0
+fi
+
+dtrace=$1
+outf=/tmp/sched.args.$$
+
+script()
+{
+ $dtrace -c '/usr/bin/sleep 10' -o $outf -qs /dev/stdin <<EOF
+ xdt:sched::off-cpu,
+ xdt:sched::on-cpu,
+ xdt:sched::block,
+ xdt:sched::sleep,
+ xdt:sched::wake,
+ xdt:sched::yield
+ {
+ /* print domid vcpu pcpu probename */
+ printf("%d %d %d %s\n", arg0, arg1, \`xdt_curpcpu, probename);
+ }
+EOF
+}
+
+validate()
+{
+ /usr/bin/nawk '
+ BEGIN {
+ while (("/usr/sbin/xm vcpu-list" | getline)) {
+ if ($1 != "Name") {
+ domid = $2
+ vcpu = $3
+
+ vcpumap[domid, vcpu] = 1
+
+ split($7, affinity, ",")
+ for (i in affinity) {
+ if (split(affinity[i], p, "-") > 1) {
+ for (pcpu = p[1]; pcpu <= p[2];\
+ pcpu++) {
+ cpumap[domid, vcpu,
+ pcpu] = 1
+ }
+ } else {
+ cpumap[domid, vcpu,
+ affinity[i]] = 1
+ }
+ }
+ }
+ }
+ }
+
+ /^$/ { next }
+
+ /wake/ {
+ if (vcpumap[$1, $2]) {
+ next
+ } else {
+ print "error: " $0
+ exit 1
+ }
+ }
+
+ {
+ if (cpumap[$1, $2, "any"] || cpumap[$1, $2, $3]) {
+ next
+ } else {
+ print "error: " $0
+ exit 1
+ }
+ }
+ ' $outf
+}
+
+script
+status=$?
+
+if [ $status == 0 ]; then
+ validate
+ status=$?
+fi
+
+rm $outf
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.schedenable.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.schedenable.ksh
new file mode 100755
index 000000000000..54c3352ea525
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/i86xpv/xdt/tst.schedenable.ksh
@@ -0,0 +1,74 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# ASSERTION: Sched probes should enable successfully.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+#
+# do not fail test in a domU
+#
+if [ ! -c /dev/xen/privcmd ]; then
+ exit 0
+fi
+
+dtrace=$1
+
+script()
+{
+ $dtrace -qs /dev/stdin <<EOF
+ dtrace:::BEGIN
+ {
+ exit(0);
+ }
+
+ xdt:sched::off-cpu,
+ xdt:sched::on-cpu,
+ xdt:sched::idle-off-cpu,
+ xdt:sched::idle-on-cpu,
+ xdt:sched::block,
+ xdt:sched::sleep,
+ xdt:sched::wake,
+ xdt:sched::yield,
+ xdt:sched::shutdown-poweroff,
+ xdt:sched::shutdown-reboot,
+ xdt:sched::shutdown-suspend,
+ xdt:sched::shutdown-crash
+ {}
+EOF
+}
+
+script
+status=$?
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/arrays/tst.uregsarray.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/arrays/tst.uregsarray.d
new file mode 100644
index 000000000000..3ef38983ad52
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/arrays/tst.uregsarray.d
@@ -0,0 +1,85 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * ASSERTION:
+ * Positive test to make sure that we can invoke sparc
+ * ureg[] aliases.
+ *
+ * SECTION: User Process Tracing/uregs Array
+ *
+ * NOTES: This test does no verification - the value of the output
+ * is not deterministic.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("R_G0 = 0x%x\n", uregs[R_G0]);
+ printf("R_G1 = 0x%x\n", uregs[R_G1]);
+ printf("R_G2 = 0x%x\n", uregs[R_G2]);
+ printf("R_G3 = 0x%x\n", uregs[R_G3]);
+ printf("R_G4 = 0x%x\n", uregs[R_G4]);
+ printf("R_G5 = 0x%x\n", uregs[R_G5]);
+ printf("R_G6 = 0x%x\n", uregs[R_G6]);
+ printf("R_G7 = 0x%x\n", uregs[R_G7]);
+ printf("R_O0 = 0x%x\n", uregs[R_O0]);
+ printf("R_O1 = 0x%x\n", uregs[R_O1]);
+ printf("R_O2 = 0x%x\n", uregs[R_O2]);
+ printf("R_O3 = 0x%x\n", uregs[R_O3]);
+ printf("R_O4 = 0x%x\n", uregs[R_O4]);
+ printf("R_O5 = 0x%x\n", uregs[R_O5]);
+ printf("R_O6 = 0x%x\n", uregs[R_O6]);
+ printf("R_O7 = 0x%x\n", uregs[R_O7]);
+ printf("R_L0 = 0x%x\n", uregs[R_L0]);
+ printf("R_L1 = 0x%x\n", uregs[R_L1]);
+ printf("R_L2 = 0x%x\n", uregs[R_L2]);
+ printf("R_L3 = 0x%x\n", uregs[R_L3]);
+ printf("R_L4 = 0x%x\n", uregs[R_L4]);
+ printf("R_L5 = 0x%x\n", uregs[R_L5]);
+ printf("R_L6 = 0x%x\n", uregs[R_L6]);
+ printf("R_L7 = 0x%x\n", uregs[R_L7]);
+ printf("R_I0 = 0x%x\n", uregs[R_I0]);
+ printf("R_I1 = 0x%x\n", uregs[R_I1]);
+ printf("R_I2 = 0x%x\n", uregs[R_I2]);
+ printf("R_I3 = 0x%x\n", uregs[R_I3]);
+ printf("R_I4 = 0x%x\n", uregs[R_I4]);
+ printf("R_I5 = 0x%x\n", uregs[R_I5]);
+ printf("R_I6 = 0x%x\n", uregs[R_I6]);
+ printf("R_I7 = 0x%x\n", uregs[R_I7]);
+ printf("R_CCR = 0x%x\n", uregs[R_CCR]);
+ printf("R_PC = 0x%x\n", uregs[R_PC]);
+ printf("R_NPC = 0x%x\n", uregs[R_NPC]);
+ printf("R_Y = 0x%x\n", uregs[R_Y]);
+ printf("R_ASI = 0x%x\n", uregs[R_ASI]);
+ printf("R_FPRS = 0x%x\n", uregs[R_FPRS]);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/err.D_PROC_ALIGN.misaligned.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/err.D_PROC_ALIGN.misaligned.d
new file mode 100644
index 000000000000..3e4662740816
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/err.D_PROC_ALIGN.misaligned.d
@@ -0,0 +1,40 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: On SPARC, you can't trace misaligned offsets
+ *
+ * SECTION: User Process Tracing/pid Provider
+ *
+ * NOTES:
+ *
+ */
+
+pid$1:a.out:main:7
+{
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/err.D_PROC_ALIGN.misaligned.exe b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/err.D_PROC_ALIGN.misaligned.exe
new file mode 100644
index 000000000000..595db1de33da
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/err.D_PROC_ALIGN.misaligned.exe
@@ -0,0 +1,29 @@
+#!/bin/ksh
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+sleep 1000000
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.d
new file mode 100644
index 000000000000..cf1dc02ec47c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.d
@@ -0,0 +1,70 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION: Trace all instructions in the function 'test' to verify that
+ * the branches are emulated correctly.
+ */
+
+#pragma D option destructive
+#pragma D option quiet
+
+pid$1:a.out:waiting:entry
+{
+ this->a = (char *)alloca(1);
+ *this->a = 1;
+ copyout(this->a, arg0, 1);
+}
+
+pid$1:a.out:test:
+{
+ printf("%s:%s\n", probefunc, probename);
+}
+
+syscall::rexit:entry
+/pid == $1/
+{
+ exit(0);
+}
+
+
+BEGIN
+{
+ /*
+ * Let's just do this for 5 seconds.
+ */
+ timeout = timestamp + 5000000000;
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.d.out
new file mode 100644
index 000000000000..8559271e4aac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.d.out
@@ -0,0 +1,23 @@
+test:entry
+test:0
+test:4
+test:8
+test:c
+test:10
+test:14
+test:18
+test:1c
+test:20
+test:24
+test:28
+test:2c
+test:30
+test:34
+test:38
+test:3c
+test:40
+test:44
+test:48
+test:4c
+test:return
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.s
new file mode 100644
index 000000000000..dfa7d27074f2
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.br.s
@@ -0,0 +1,81 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .word 0
+
+ ENTRY(waiting)
+ retl
+ ldub [%o0], %o0
+ SET_SIZE(waiting)
+
+ ENTRY(test)
+ mov 1, %g1
+
+ brz %g1, 1f
+ nop
+ brlez %g1, 1f
+ nop
+ brlz %g0, 1f
+ nop
+ brlz %g1, 1f
+ nop
+ brnz %g0, 1f
+ sub %g0, 2, %g1
+ brgz %g1, 1f
+ nop
+ brgz %g0, 1f
+ nop
+ brgez %g1, 1f
+ nop
+
+ mov %g1, %o0
+
+1:
+ retl
+ nop
+ SET_SIZE(test)
+
+ ENTRY(main)
+ save %sp, -SA(MINFRAME + 4), %sp
+ stb %g0, [%fp - 4]
+1:
+ call waiting
+ sub %fp, 4, %o0
+ tst %o0
+ bz 1b
+ nop
+
+ call test
+ nop
+
+ ret
+ restore %g0, %g0, %o0
+ SET_SIZE(main)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.branch.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.branch.d
new file mode 100644
index 000000000000..cfcf0a715d1a
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.branch.d
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * SECTION:
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option destructive
+
+pid$1:a.out:waiting:entry
+{
+ this->a = (char *)alloca(1);
+ *this->a = 1;
+ copyout(this->a, arg0, 1);
+}
+
+pid$1:a.out:main:,
+pid$1:a.out:other:
+{
+}
+
+pid$1:a.out:bad:entry
+{
+ exit(1);
+}
+
+syscall::rexit:entry
+/pid == $1/
+{
+ exit(0);
+}
+
+
+BEGIN
+{
+ /*
+ * Let's just do this for 5 seconds.
+ */
+ timeout = timestamp + 5000000000;
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.branch.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.branch.s
new file mode 100644
index 000000000000..3e6531f32190
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.branch.s
@@ -0,0 +1,63 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .word 0
+
+ ENTRY(waiting)
+ retl
+ ldub [%o0], %o0
+ SET_SIZE(waiting)
+
+ ENTRY(main)
+ save %sp, -SA(MINFRAME + 4), %sp
+ stb %g0, [%fp - 4]
+1:
+ call waiting
+ sub %fp, 4, %o0
+ tst %o0
+ bz 1b
+ nop
+
+ restore
+
+ tst %g0
+ be other
+ nop
+
+ ALTENTRY(bad)
+ illtrap
+ SET_SIZE(bad)
+ SET_SIZE(main)
+
+ ENTRY(other)
+ retl
+ clr %o0
+ SET_SIZE(other)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.embedded.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.embedded.d
new file mode 100644
index 000000000000..c484c3f0c721
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.embedded.d
@@ -0,0 +1,73 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * SECTION:
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option destructive
+
+pid$1:a.out:waiting:entry
+{
+ this->a = (char *)alloca(1);
+ *this->a = 1;
+ copyout(this->a, arg0, 1);
+}
+
+pid$1:a.out:main:,
+pid$1:a.out:inner:
+{
+}
+
+syscall::rexit:entry
+/pid == $1/
+{
+ exit(0);
+}
+
+
+BEGIN
+{
+ /*
+ * Let's just do this for 5 seconds.
+ */
+ timeout = timestamp + 5000000000;
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.embedded.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.embedded.s
new file mode 100644
index 000000000000..612f0b926142
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/pid/tst.embedded.s
@@ -0,0 +1,59 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .word 0
+
+ ENTRY(waiting)
+ retl
+ ldub [%o0], %o0
+ SET_SIZE(waiting)
+
+ ENTRY(main)
+ save %sp, -SA(MINFRAME + 4), %sp
+ stb %g0, [%fp - 4]
+1:
+ call waiting
+ sub %fp, 4, %o0
+ tst %o0
+ bz 1b
+ nop
+
+ restore
+
+ ALTENTRY(inner)
+ nop
+ nop
+ nop
+ SET_SIZE(inner)
+
+ retl
+ clr %o0
+ SET_SIZE(main)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/usdt/tst.tailcall.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/usdt/tst.tailcall.ksh
new file mode 100644
index 000000000000..c3651ecf7eb4
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/usdt/tst.tailcall.ksh
@@ -0,0 +1,132 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# ASSERTION: Make sure USDT probes work as tail-calls on SPARC.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+cat > test.s <<EOF
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .word 0
+
+ ENTRY(test)
+ save %sp, -SA(MINFRAME + 4), %sp
+ mov 9, %i0
+ mov 19, %i1
+ mov 2006, %i2
+ call __dtrace_test___fire
+ restore
+ SET_SIZE(test)
+
+ ENTRY(main)
+ save %sp, -SA(MINFRAME + 4), %sp
+
+1:
+ call test
+ nop
+
+ ba 1b
+ nop
+
+ ret
+ restore %g0, %g0, %o0
+ SET_SIZE(main)
+EOF
+
+cat > prov.d <<EOF
+provider test {
+ probe fire(int, int, int);
+};
+EOF
+
+/usr/bin/as -xregsym=no -P -D_ASM -o test.o test.s
+if [ $? -ne 0 ]; then
+ print -u2 "failed to compile test.s"
+ exit 1
+fi
+
+$dtrace -G -32 -s prov.d test.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to create DOF"
+ exit 1
+fi
+
+cc -o test test.o prov.o
+if [ $? -ne 0 ]; then
+ print -u2 "failed to link final executable"
+ exit 1
+fi
+
+$dtrace -c ./test -s /dev/stdin <<EOF
+test\$target:::fire
+/arg0 == 9 && arg1 == 19 && arg2 == 2006/
+{
+ printf("%d/%d/%d", arg0, arg1, arg2);
+ exit(0);
+}
+
+test\$target:::fire
+{
+ printf("%d/%d/%d", arg0, arg1, arg2);
+ exit(1);
+}
+
+BEGIN
+{
+ /*
+ * Let's just do this for 5 seconds.
+ */
+ timeout = timestamp + 5000000000;
+}
+
+profile:::tick-4
+/timestamp > timeout/
+{
+ trace("test timed out");
+ exit(1);
+}
+EOF
+
+status=$?
+
+cd /
+/bin/rm -rf $DIR
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/annotated_helper.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/annotated_helper.d
new file mode 100644
index 000000000000..3577f86f8ee6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/annotated_helper.d
@@ -0,0 +1,32 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ident "%Z%%M% %I% %E% SMI"
+
+dtrace:helper:ustack:
+{
+ "@it's annotated"
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/helper_helper.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/helper_helper.d
new file mode 100644
index 000000000000..8abc47d006dc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/helper_helper.d
@@ -0,0 +1,32 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+dtrace:helper:ustack:
+{
+ "<it's working>"
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.c
new file mode 100644
index 000000000000..8cdf8abad5af
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.c
@@ -0,0 +1,43 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+int
+baz(void)
+{
+ return (8);
+}
+
+int
+main(int argc, char **argv)
+{
+ for (;;) {
+ baz();
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.d
new file mode 100644
index 000000000000..dd795bece03f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.d
@@ -0,0 +1,35 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma D option quiet
+
+pid$1:a.out:baz:entry
+{
+ ustack(1, 1024);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.d.out
new file mode 100644
index 000000000000..806d6a2b43dc
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.annotated.d.out
@@ -0,0 +1,4 @@
+
+ tst.annotated.exe`baz
+ [ it's annotated ]
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.circstack.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.circstack.d
new file mode 100644
index 000000000000..78218bd72aea
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.circstack.d
@@ -0,0 +1,46 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+syscall::getpid:entry
+/pid == $1/
+{
+ @[ustackdepth] = count();
+}
+
+ERROR
+/arg4 == DTRACEFLT_BADSTACK/
+{
+ exit(0);
+}
+
+profile:::tick-1s
+/++n == 10/
+{
+ exit(1)
+}
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.circstack.s b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.circstack.s
new file mode 100644
index 000000000000..a5076c969d92
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.circstack.s
@@ -0,0 +1,44 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+ DGDEF(__fsr_init_value)
+ .word 0
+
+ ENTRY(main)
+ save %sp, -SA(MINFRAME), %sp
+ mov %sp, %fp
+loop:
+ call getpid
+ nop
+ ba loop
+ nop
+ ret
+ restore
+ SET_SIZE(main)
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.c
new file mode 100644
index 000000000000..fa4802acd5d6
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.c
@@ -0,0 +1,81 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <strings.h>
+
+int
+baz(void)
+{
+ return (8);
+}
+
+static int
+foo(void)
+{
+ /*
+ * In order to assure that our helper is properly employed to identify
+ * the frame, we're going to trampoline through data.
+ */
+ uint32_t instr[] = {
+ 0x9de3bfa0, /* save %sp, -0x60, %sp */
+ 0x40000000, /* call baz */
+ 0x01000000, /* nop */
+ 0x81c7e008, /* ret */
+ 0x81e80000 /* restore */
+ };
+ uint32_t *fp = malloc(sizeof (instr));
+
+ /*
+ * Do our little relocation dance.
+ */
+ instr[1] |= ((uintptr_t)baz - (uintptr_t)&fp[1]) >> 2;
+
+ /*
+ * Copy the code to the heap (it's a pain to build in ON with an
+ * executable stack).
+ */
+ bcopy(instr, fp, sizeof (instr));
+
+ (*(int (*)(void))fp)();
+
+ free(fp);
+
+ return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+ for (;;) {
+ foo();
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.d
new file mode 100644
index 000000000000..ce2b9b30f14f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.d
@@ -0,0 +1,44 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ASSERTION:
+ *
+ * SECTION:
+ *
+ * NOTES:
+ *
+ */
+
+#pragma D option quiet
+
+pid$1:a.out:baz:entry
+{
+ ustack(2, 1024);
+ exit(0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.d.out
new file mode 100644
index 000000000000..29646288e7ac
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.helper.d.out
@@ -0,0 +1,4 @@
+
+ tst.helper.exe`baz
+ <it's working>
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.trapstat.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.trapstat.ksh
new file mode 100644
index 000000000000..84af8006768f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/sparc/ustack/tst.trapstat.ksh
@@ -0,0 +1,87 @@
+#/bin/ksh -p
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script verifies that user-land stacks can be walked safely
+# when the trapstat(1M) utility is running. An arbitrary program, w(1),
+# is started once a second to ensure stacks can be walked at all stages
+# of the process lifecycle.
+#
+
+script()
+{
+ $dtrace -o $dtraceout -s /dev/stdin <<EOF
+ fbt:::
+ {
+ @[ustackdepth] = count();
+ }
+EOF
+}
+
+run_commands()
+{
+ cnt=0
+
+ while [ $cnt -lt 10 ]; do
+ w > /dev/null
+ sleep 1
+ cnt=$(($cnt+1))
+ done
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+dtraceout=/tmp/dtrace.out.$$
+script 2>/dev/null &
+timeout=15
+
+#
+# Sleep while the above script fires into life. To guard against dtrace dying
+# and us sleeping forever we allow 15 secs for this to happen. This should be
+# enough for even the slowest systems.
+#
+while [ ! -f $dtraceout ]; do
+ sleep 1
+ timeout=$(($timeout-1))
+ if [ $timeout -eq 0 ]; then
+ echo "dtrace failed to start. Exiting."
+ exit 1
+ fi
+done
+
+run_commands &
+trapstat -t 1 10
+status=$?
+
+rm $dtraceout
+
+exit $status
diff --git a/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1 b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1
new file mode 100644
index 000000000000..552496840d3b
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1
@@ -0,0 +1,402 @@
+'\" te
+.\" 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 (c) 2008, Sun Microsystems, Inc. All Rights Reserved.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 29, 2015
+.Dt LOCKSTAT 1
+.Os
+.Sh NAME
+.Nm lockstat
+.Nd report kernel lock and profiling statistics
+.Sh SYNOPSIS
+.Nm
+.Op Fl ACEHIV
+.Op Fl e Ar event-list
+.Op Fl i Ar rate
+.Op Fl b | t | h | s Ar depth
+.Op Fl n Ar num-records
+.Op Fl l Ar lock Oo Ns , Ns Ar size Oc
+.Op Fl d Ar duration
+.Op Fl f Ar function Oo Ns , Ns Ar size Oc
+.Op Fl T
+.Op Fl kgwWRpP
+.Op Fl D Ar count
+.Op Fl o filename
+.Op Fl x Ar opt Oo Ns = Ns Ar val Oc
+.Ar command
+.Op Oo Ar args Oc
+.Sh DESCRIPTION
+The
+.Nm
+utility gathers and displays kernel locking and profiling statistics.
+.Nm
+allows you to specify which events to watch (for example, spin on adaptive
+mutex, block on read access to rwlock due to waiting writers, and so forth), how
+much data to gather for each event, and how to display the data.
+By default,
+.Nm
+monitors all lock contention events, gathers frequency and timing data about
+those events, and displays the data in decreasing frequency order, so that the
+most common events appear first.
+.Pp
+.Nm
+gathers data until the specified command completes.
+For example, to gather statistics for a fixed-time interval, use
+.Xr sleep 1
+as the command, as follows:
+.Pp
+.Dl # lockstat sleep 5
+.Pp
+When the
+.Fl I
+option is specified,
+.Nm lockstat
+establishes a per-processor high-level periodic interrupt source to gather
+profiling data.
+The interrupt handler simply generates a
+.Nm
+event whose caller is the interrupted PC (program counter).
+The profiling event is just like any other
+.Nm lockstat
+event, so all of the normal
+.Nm lockstat
+options are applicable.
+.Pp
+.Nm
+relies on DTrace to modify the running kernel's text to intercept events of
+interest.
+This imposes a small but measurable overhead on all system activity, so access
+to
+.Nm
+is restricted to super-user by default.
+.Sh OPTIONS
+The following options are supported:
+.Bl -tag -width indent
+.It Fl V
+Print the D program used to gather the requested data.
+.El
+.Ss Event Selection
+If no event selection options are specified, the default is
+.Fl C .
+.Bl -tag -width indent
+.It Fl A
+Watch all lock events.
+.Fl A
+is equivalent to
+.Fl CH .
+.It Fl C
+Watch contention events.
+.It Fl E
+Watch error events.
+.It Fl e Ar event-list
+Only watch the specified events.
+.Ar event-list
+is a comma-separated list of events or ranges of events such as 1,4-7,35.
+Run
+.Nm
+with no arguments to get a brief description of all events.
+.It Fl H
+Watch hold events.
+.It Fl I
+Watch profiling interrupt events.
+.It Fl i Ar rate
+Interrupt rate (per second) for
+.Fl I .
+The default is 97 Hz, so that profiling doesn't run in lockstep with the clock
+interrupt (which runs at 100 Hz).
+.El
+.Ss Data Gathering
+.Bl -tag -width indent
+.It Fl x Ar arg Oo Ns = Ns Ar val Oc
+Enable or modify a
+.Xr dtrace 1
+runtime option or D compiler option.
+Boolean options are enabled by specifying their name.
+Options with values are set by separating the option name and value with an
+equals sign.
+.El
+.Ss "Data Gathering (Mutually Exclusive)"
+.Bl -tag -width indent
+.It Fl b
+Basic statistics: lock, caller, number of events.
+.It Fl h
+Histogram: timing plus time-distribution histograms.
+.It Fl s Ar depth
+Stack trace: histogram plus stack traces up to
+.Ar depth
+frames deep.
+.It Fl t
+Timing: Basic plus timing for all events (default).
+.El
+.Ss "Data Filtering"
+.Bl -tag -width indent
+.It Fl d Ar duration
+Only watch events longer than
+.Ar duration .
+.It Fl f Ar func Ns Oo Ns , Ns Ar size Oc Ns
+Only watch events generated by
+.Ar func ,
+which can be specified as a symbolic name or hex address.
+.Ar size
+defaults to the ELF symbol size if available, or 1 if not.
+.It Fl l Ar lock Ns Oo Ns , Ns Ar size Oc Ns
+Only watch
+.Ar lock ,
+which can be specified as a symbolic name or hex address.
+.Ar size
+defaults to the ELF symbol size or 1 if the symbol size is not available.
+.It Fl n Ar num-records
+Maximum number of data records.
+.It Fl T
+Trace (rather than sample) events.
+This is off by default.
+.El
+.Ss Data Reporting
+.Bl -tag -width indent
+.It Fl D Ar count
+Only display the top
+.Ar count
+events of each type.
+.It Fl g
+Show total events generated by function.
+For example, if
+.Fn foo
+calls
+.Fn bar
+in a loop, the work done by
+.Fn bar
+counts as work generated by
+.Fn foo
+(along with any work done by
+.Fn foo
+itself).
+The
+.Fl g
+option works by counting the total number of stack frames in which each function
+appears.
+This implies two things: (1) the data reported by
+.Fl g
+can be misleading if the stack traces are not deep enough, and (2) functions
+that are called recursively might show greater than 100% activity.
+In light of issue (1), the default data gathering mode when using
+.Fl g
+is
+.Fl s 50 .
+.It Fl k
+Coalesce PCs within functions.
+.It Fl o Ar filename
+Direct output to
+.Ar filename .
+.It Fl P
+Sort data by (\fIcount * time\fR) product.
+.It Fl p
+Parsable output format.
+.It Fl R
+Display rates (events per second) rather than counts.
+.It Fl W
+Whichever: distinguish events only by caller, not by lock.
+.It Fl w
+Wherever: distinguish events only by lock, not by caller.
+.El
+.Sh DISPLAY FORMATS
+The following headers appear over various columns of data.
+.Bl -tag -width indent
+.It Count or ops/s
+Number of times this event occurred, or the rate (times per second) if
+.Fl R
+was specified.
+.It indv
+Percentage of all events represented by this individual event.
+.It genr
+Percentage of all events generated by this function.
+.It cuml
+Cumulative percentage; a running total of the individuals.
+.It rcnt
+Average reference count.
+This will always be 1 for exclusive locks (mutexes,
+spin locks, rwlocks held as writer) but can be greater than 1 for shared locks
+(rwlocks held as reader).
+.It nsec
+Average duration of the events in nanoseconds, as appropriate for the event.
+For the profiling event, duration means interrupt latency.
+.It Lock
+Address of the lock; displayed symbolically if possible.
+.It CPU+Pri_Class
+CPU plus the priority class of the interrupted thread.
+For example, if CPU 4 is interrupted while running a timeshare thread, this
+will be reported as
+.Ql cpu[4]+TShar .
+.It Caller
+Address of the caller; displayed symbolically if possible.
+.El
+.Sh EXAMPLES
+.Bl -tag -width 0n
+.It Example 1 Measuring Kernel Lock Contention
+.Pp
+.Li # lockstat sleep 5
+.Bd -literal
+Adaptive mutex spin: 41411 events in 5.011 seconds (8263 events/sec)
+
+Count indv cuml rcnt nsec Lock Caller
+-------------------------------------------------------------------------------
+13750 33% 33% 0.00 72 vm_page_queue_free_mtx vm_page_free_toq+0x12e
+13648 33% 66% 0.00 66 vm_page_queue_free_mtx vm_page_alloc+0x138
+ 4023 10% 76% 0.00 51 vm_dom+0x80 vm_page_dequeue+0x68
+ 2672 6% 82% 0.00 186 vm_dom+0x80 vm_page_enqueue+0x63
+ 618 1% 84% 0.00 31 0xfffff8000cd83a88 qsyncvp+0x37
+ 506 1% 85% 0.00 164 0xfffff8000cb3f098 vputx+0x5a
+ 477 1% 86% 0.00 69 0xfffff8000c7eb180 uma_dbg_getslab+0x5b
+ 288 1% 87% 0.00 77 0xfffff8000cd8b000 vn_finished_write+0x29
+ 263 1% 88% 0.00 103 0xfffff8000cbad448 vinactive+0xdc
+ 259 1% 88% 0.00 53 0xfffff8000cd8b000 vfs_ref+0x24
+ 237 1% 89% 0.00 20 0xfffff8000cbad448 vfs_hash_get+0xcc
+ 233 1% 89% 0.00 22 0xfffff8000bfd9480 uma_dbg_getslab+0x5b
+ 223 1% 90% 0.00 20 0xfffff8000cb3f098 cache_lookup+0x561
+ 193 0% 90% 0.00 16 0xfffff8000cb40ba8 vref+0x27
+ 175 0% 91% 0.00 34 0xfffff8000cbad448 vputx+0x5a
+ 169 0% 91% 0.00 51 0xfffff8000cd8b000 vfs_unbusy+0x27
+ 164 0% 92% 0.00 31 0xfffff8000cb40ba8 vputx+0x5a
+[...]
+
+Adaptive mutex block: 10 events in 5.011 seconds (2 events/sec)
+
+Count indv cuml rcnt nsec Lock Caller
+-------------------------------------------------------------------------------
+ 3 30% 30% 0.00 17592 vm_page_queue_free_mtx vm_page_alloc+0x138
+ 2 20% 50% 0.00 20528 vm_dom+0x80 vm_page_enqueue+0x63
+ 2 20% 70% 0.00 55502 0xfffff8000cb40ba8 vputx+0x5a
+ 1 10% 80% 0.00 12007 vm_page_queue_free_mtx vm_page_free_toq+0x12e
+ 1 10% 90% 0.00 9125 0xfffff8000cbad448 vfs_hash_get+0xcc
+ 1 10% 100% 0.00 7864 0xfffff8000cd83a88 qsyncvp+0x37
+-------------------------------------------------------------------------------
+[...]
+.Ed
+.It Example 2 Measuring Hold Times
+.Pp
+.Li # lockstat -H -D 10 sleep 1
+.Bd -literal
+Adaptive mutex hold: 109589 events in 1.039 seconds (105526 events/sec)
+
+Count indv cuml rcnt nsec Lock Caller
+-------------------------------------------------------------------------------
+ 8998 8% 8% 0.00 617 0xfffff8000c7eb180 uma_dbg_getslab+0xd4
+ 5901 5% 14% 0.00 917 vm_page_queue_free_mtx vm_object_terminate+0x16a
+ 5040 5% 18% 0.00 902 vm_dom+0x80 vm_page_free_toq+0x88
+ 4884 4% 23% 0.00 1056 vm_page_queue_free_mtx vm_page_alloc+0x44e
+ 4664 4% 27% 0.00 759 vm_dom+0x80 vm_fault_hold+0x1a13
+ 4011 4% 31% 0.00 888 vm_dom vm_page_advise+0x11b
+ 4010 4% 34% 0.00 957 vm_dom+0x80 _vm_page_deactivate+0x5c
+ 3743 3% 38% 0.00 582 0xfffff8000cf04838 pmap_is_prefaultable+0x158
+ 2254 2% 40% 0.00 952 vm_dom vm_page_free_toq+0x88
+ 1639 1% 41% 0.00 591 0xfffff800d60065b8 trap_pfault+0x1f7
+-------------------------------------------------------------------------------
+[...]
+
+R/W writer hold: 64314 events in 1.039 seconds (61929 events/sec)
+
+Count indv cuml rcnt nsec Lock Caller
+-------------------------------------------------------------------------------
+ 7421 12% 12% 0.00 2994 pvh_global_lock pmap_page_is_mapped+0xb6
+ 4668 7% 19% 0.00 3313 pvh_global_lock pmap_enter+0x9ae
+ 1639 3% 21% 0.00 733 0xfffff80168d10200 vm_object_deallocate+0x683
+ 1639 3% 24% 0.00 3061 0xfffff80168d10200 unlock_and_deallocate+0x2b
+ 1639 3% 26% 0.00 2966 0xfffff80168d10200 vm_fault_hold+0x16ee
+ 1567 2% 29% 0.00 733 0xfffff80168d10200 vm_fault_hold+0x19bc
+ 821 1% 30% 0.00 786 0xfffff801eb0cc000 vm_object_madvise+0x32d
+ 649 1% 31% 0.00 4918 0xfffff80191105300 vm_fault_hold+0x16ee
+ 648 1% 32% 0.00 8112 0xfffff80191105300 unlock_and_deallocate+0x2b
+ 647 1% 33% 0.00 1261 0xfffff80191105300 vm_object_deallocate+0x683
+-------------------------------------------------------------------------------
+.Ed
+.It Example 3 Measuring Hold Times for Stack Traces Containing a Specific Function
+.Pp
+.Li # lockstat -H -f tcp_input -s 50 -D 10 sleep 1
+.Bd -literal
+Adaptive mutex hold: 68 events in 1.026 seconds (66 events/sec)
+
+-------------------------------------------------------------------------------
+Count indv cuml rcnt nsec Lock Caller
+ 32 47% 47% 0.00 1631 0xfffff800686f50d8 tcp_do_segment+0x284b
+
+ nsec ------ Time Distribution ------ count Stack
+ 1024 |@@@@@@@@@@ 11 tcp_input+0xf54
+ 2048 |@@@@@@@@@@@@@ 14 ip_input+0xc8
+ 4096 |@@@@@ 6 swi_net+0x192
+ 8192 | 1 intr_event_execute_handlers+0x93
+ ithread_loop+0xa6
+ fork_exit+0x84
+ 0xffffffff808cf9ee
+-------------------------------------------------------------------------------
+Count indv cuml rcnt nsec Lock Caller
+ 29 43% 90% 0.00 4851 0xfffff800686f50d8 sowakeup+0xf8
+
+ nsec ------ Time Distribution ------ count Stack
+ 4096 |@@@@@@@@@@@@@@@ 15 tcp_do_segment+0x2423
+ 8192 |@@@@@@@@@@@@ 12 tcp_input+0xf54
+ 16384 |@@ 2 ip_input+0xc8
+ swi_net+0x192
+ intr_event_execute_handlers+0x93
+ ithread_loop+0xa6
+ fork_exit+0x84
+ 0xffffffff808cf9ee
+-------------------------------------------------------------------------------
+[...]
+.Ed
+.El
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr ksyms 4 ,
+.Xr locking 9
+.Sh NOTES
+Tail-call elimination can affect call sites.
+For example, if
+.Fn foo Ns +0x50
+calls
+.Fn bar
+and the last thing
+.Fn bar
+does is call
+.Fn mtx_unlock ,
+the compiler can arrange for
+.Fn bar
+to branch to
+.Fn mtx_unlock
+with a return address of
+.Fn foo Ns +0x58.
+Thus, the
+.Fn mtx_unlock
+in
+.Fn bar
+will appear as though it occurred at
+.Fn foo Ns +0x58.
+.Pp
+The PC in the stack frame in which an interrupt occurs can be bogus because,
+between function calls, the compiler is free to use the return address register
+for local storage.
+.Pp
+When using the
+.Fl I
+and
+.Fl s
+options together, the interrupted PC will usually not appear anywhere in the
+stack since the interrupt handler is entered asynchronously, not by a function
+call from that PC.
diff --git a/cddl/contrib/opensolaris/cmd/lockstat/lockstat.c b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.c
new file mode 100644
index 000000000000..a7378980bc56
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.c
@@ -0,0 +1,2005 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/modctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <dtrace.h>
+#include <sys/lockstat.h>
+#include <alloca.h>
+#include <signal.h>
+#include <assert.h>
+
+#ifdef illumos
+#define GETOPT_EOF EOF
+#else
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#define mergesort(a, b, c, d) lsmergesort(a, b, c, d)
+#define GETOPT_EOF (-1)
+
+typedef uintptr_t pc_t;
+#endif
+
+#define LOCKSTAT_OPTSTR "x:bths:n:d:i:l:f:e:ckwWgCHEATID:RpPo:V"
+
+#define LS_MAX_STACK_DEPTH 50
+#define LS_MAX_EVENTS 64
+
+typedef struct lsrec {
+ struct lsrec *ls_next; /* next in hash chain */
+#ifdef illumos
+ uintptr_t ls_lock; /* lock address */
+#else
+ char *ls_lock; /* lock name */
+#endif
+ uintptr_t ls_caller; /* caller address */
+ uint32_t ls_count; /* cumulative event count */
+ uint32_t ls_event; /* type of event */
+ uintptr_t ls_refcnt; /* cumulative reference count */
+ uint64_t ls_time; /* cumulative event duration */
+ uint32_t ls_hist[64]; /* log2(duration) histogram */
+ uintptr_t ls_stack[LS_MAX_STACK_DEPTH];
+} lsrec_t;
+
+typedef struct lsdata {
+ struct lsrec *lsd_next; /* next available */
+ int lsd_count; /* number of records */
+} lsdata_t;
+
+/*
+ * Definitions for the types of experiments which can be run. They are
+ * listed in increasing order of memory cost and processing time cost.
+ * The numerical value of each type is the number of bytes needed per record.
+ */
+#define LS_BASIC offsetof(lsrec_t, ls_time)
+#define LS_TIME offsetof(lsrec_t, ls_hist[0])
+#define LS_HIST offsetof(lsrec_t, ls_stack[0])
+#define LS_STACK(depth) offsetof(lsrec_t, ls_stack[depth])
+
+static void report_stats(FILE *, lsrec_t **, size_t, uint64_t, uint64_t);
+static void report_trace(FILE *, lsrec_t **);
+
+extern int symtab_init(void);
+extern char *addr_to_sym(uintptr_t, uintptr_t *, size_t *);
+extern uintptr_t sym_to_addr(char *name);
+extern size_t sym_size(char *name);
+extern char *strtok_r(char *, const char *, char **);
+
+#define DEFAULT_NRECS 10000
+#define DEFAULT_HZ 97
+#define MAX_HZ 1000
+#define MIN_AGGSIZE (16 * 1024)
+#define MAX_AGGSIZE (32 * 1024 * 1024)
+
+static int g_stkdepth;
+static int g_topn = INT_MAX;
+static hrtime_t g_elapsed;
+static int g_rates = 0;
+static int g_pflag = 0;
+static int g_Pflag = 0;
+static int g_wflag = 0;
+static int g_Wflag = 0;
+static int g_cflag = 0;
+static int g_kflag = 0;
+static int g_gflag = 0;
+static int g_Vflag = 0;
+static int g_tracing = 0;
+static size_t g_recsize;
+static size_t g_nrecs;
+static int g_nrecs_used;
+static uchar_t g_enabled[LS_MAX_EVENTS];
+static hrtime_t g_min_duration[LS_MAX_EVENTS];
+static dtrace_hdl_t *g_dtp;
+static char *g_predicate;
+static char *g_ipredicate;
+static char *g_prog;
+static int g_proglen;
+static int g_dropped;
+
+typedef struct ls_event_info {
+ char ev_type;
+ char ev_lhdr[20];
+ char ev_desc[80];
+ char ev_units[10];
+ char ev_name[DTRACE_NAMELEN];
+ char *ev_predicate;
+ char *ev_acquire;
+} ls_event_info_t;
+
+static ls_event_info_t g_event_info[LS_MAX_EVENTS] = {
+ { 'C', "Lock", "Adaptive mutex spin", "nsec",
+ "lockstat:::adaptive-spin" },
+ { 'C', "Lock", "Adaptive mutex block", "nsec",
+ "lockstat:::adaptive-block" },
+ { 'C', "Lock", "Spin lock spin", "nsec",
+ "lockstat:::spin-spin" },
+ { 'C', "Lock", "Thread lock spin", "nsec",
+ "lockstat:::thread-spin" },
+ { 'C', "Lock", "R/W writer blocked by writer", "nsec",
+ "lockstat:::rw-block", "arg2 == 0 && arg3 == 1" },
+ { 'C', "Lock", "R/W writer blocked by readers", "nsec",
+ "lockstat:::rw-block", "arg2 == 0 && arg3 == 0 && arg4" },
+ { 'C', "Lock", "R/W reader blocked by writer", "nsec",
+ "lockstat:::rw-block", "arg2 == 1 && arg3 == 1" },
+ { 'C', "Lock", "R/W reader blocked by write wanted", "nsec",
+ "lockstat:::rw-block", "arg2 == 1 && arg3 == 0 && arg4" },
+ { 'C', "Lock", "R/W writer spin on writer", "nsec",
+ "lockstat:::rw-spin", "arg2 == 0 && arg3 == 1" },
+ { 'C', "Lock", "R/W writer spin on readers", "nsec",
+ "lockstat:::rw-spin", "arg2 == 0 && arg3 == 0 && arg4" },
+ { 'C', "Lock", "R/W reader spin on writer", "nsec",
+ "lockstat:::rw-spin", "arg2 == 1 && arg3 == 1" },
+ { 'C', "Lock", "R/W reader spin on write wanted", "nsec",
+ "lockstat:::rw-spin", "arg2 == 1 && arg3 == 0 && arg4" },
+ { 'C', "Lock", "SX exclusive block", "nsec",
+ "lockstat:::sx-block", "arg2 == 0" },
+ { 'C', "Lock", "SX shared block", "nsec",
+ "lockstat:::sx-block", "arg2 == 1" },
+ { 'C', "Lock", "SX exclusive spin", "nsec",
+ "lockstat:::sx-spin", "arg2 == 0" },
+ { 'C', "Lock", "SX shared spin", "nsec",
+ "lockstat:::sx-spin", "arg2 == 1" },
+ { 'C', "Lock", "lockmgr writer blocked by writer", "nsec",
+ "lockstat:::lockmgr-block", "arg2 == 0 && arg3 == 1" },
+ { 'C', "Lock", "lockmgr writer blocked by readers", "nsec",
+ "lockstat:::lockmgr-block", "arg2 == 0 && arg3 == 0 && arg4" },
+ { 'C', "Lock", "lockmgr reader blocked by writer", "nsec",
+ "lockstat:::lockmgr-block", "arg2 == 1 && arg3 == 1" },
+ { 'C', "Lock", "lockmgr reader blocked by write wanted", "nsec",
+ "lockstat:::lockmgr-block", "arg2 == 1 && arg3 == 0 && arg4" },
+ { 'C', "Lock", "Unknown event (type 20)", "units" },
+ { 'C', "Lock", "Unknown event (type 21)", "units" },
+ { 'C', "Lock", "Unknown event (type 22)", "units" },
+ { 'C', "Lock", "Unknown event (type 23)", "units" },
+ { 'C', "Lock", "Unknown event (type 24)", "units" },
+ { 'C', "Lock", "Unknown event (type 25)", "units" },
+ { 'C', "Lock", "Unknown event (type 26)", "units" },
+ { 'C', "Lock", "Unknown event (type 27)", "units" },
+ { 'C', "Lock", "Unknown event (type 28)", "units" },
+ { 'C', "Lock", "Unknown event (type 29)", "units" },
+ { 'C', "Lock", "Unknown event (type 30)", "units" },
+ { 'C', "Lock", "Unknown event (type 31)", "units" },
+ { 'H', "Lock", "Adaptive mutex hold", "nsec",
+ "lockstat:::adaptive-release", NULL,
+ "lockstat:::adaptive-acquire" },
+ { 'H', "Lock", "Spin lock hold", "nsec",
+ "lockstat:::spin-release", NULL,
+ "lockstat:::spin-acquire" },
+ { 'H', "Lock", "R/W writer hold", "nsec",
+ "lockstat:::rw-release", "arg1 == 0",
+ "lockstat:::rw-acquire" },
+ { 'H', "Lock", "R/W reader hold", "nsec",
+ "lockstat:::rw-release", "arg1 == 1",
+ "lockstat:::rw-acquire" },
+ { 'H', "Lock", "SX shared hold", "nsec",
+ "lockstat:::sx-release", "arg1 == 1",
+ "lockstat:::sx-acquire" },
+ { 'H', "Lock", "SX exclusive hold", "nsec",
+ "lockstat:::sx-release", "arg1 == 0",
+ "lockstat:::sx-acquire" },
+ { 'H', "Lock", "lockmgr shared hold", "nsec",
+ "lockstat:::lockmgr-release", "arg1 == 1",
+ "lockstat:::lockmgr-acquire" },
+ { 'H', "Lock", "lockmgr exclusive hold", "nsec",
+ "lockstat:::lockmgr-release,lockstat:::lockmgr-disown", "arg1 == 0",
+ "lockstat:::lockmgr-acquire" },
+ { 'H', "Lock", "Unknown event (type 40)", "units" },
+ { 'H', "Lock", "Unknown event (type 41)", "units" },
+ { 'H', "Lock", "Unknown event (type 42)", "units" },
+ { 'H', "Lock", "Unknown event (type 43)", "units" },
+ { 'H', "Lock", "Unknown event (type 44)", "units" },
+ { 'H', "Lock", "Unknown event (type 45)", "units" },
+ { 'H', "Lock", "Unknown event (type 46)", "units" },
+ { 'H', "Lock", "Unknown event (type 47)", "units" },
+ { 'H', "Lock", "Unknown event (type 48)", "units" },
+ { 'H', "Lock", "Unknown event (type 49)", "units" },
+ { 'H', "Lock", "Unknown event (type 50)", "units" },
+ { 'H', "Lock", "Unknown event (type 51)", "units" },
+ { 'H', "Lock", "Unknown event (type 52)", "units" },
+ { 'H', "Lock", "Unknown event (type 53)", "units" },
+ { 'H', "Lock", "Unknown event (type 54)", "units" },
+ { 'H', "Lock", "Unknown event (type 55)", "units" },
+#ifdef illumos
+ { 'I', "CPU+PIL", "Profiling interrupt", "nsec",
+#else
+ { 'I', "CPU+Pri_Class", "Profiling interrupt", "nsec",
+#endif
+ "profile:::profile-97", NULL },
+ { 'I', "Lock", "Unknown event (type 57)", "units" },
+ { 'I', "Lock", "Unknown event (type 58)", "units" },
+ { 'I', "Lock", "Unknown event (type 59)", "units" },
+ { 'E', "Lock", "Recursive lock entry detected", "(N/A)",
+ "lockstat:::rw-release", NULL, "lockstat:::rw-acquire" },
+ { 'E', "Lock", "Lockstat enter failure", "(N/A)" },
+ { 'E', "Lock", "Lockstat exit failure", "nsec" },
+ { 'E', "Lock", "Lockstat record failure", "(N/A)" },
+};
+
+#ifndef illumos
+static char *g_pri_class[] = {
+ "",
+ "Intr",
+ "RealT",
+ "TShar",
+ "Idle"
+};
+#endif
+
+static void
+fail(int do_perror, const char *message, ...)
+{
+ va_list args;
+ int save_errno = errno;
+
+ va_start(args, message);
+ (void) fprintf(stderr, "lockstat: ");
+ (void) vfprintf(stderr, message, args);
+ va_end(args);
+ if (do_perror)
+ (void) fprintf(stderr, ": %s", strerror(save_errno));
+ (void) fprintf(stderr, "\n");
+ exit(2);
+}
+
+static void
+dfail(const char *message, ...)
+{
+ va_list args;
+
+ va_start(args, message);
+ (void) fprintf(stderr, "lockstat: ");
+ (void) vfprintf(stderr, message, args);
+ va_end(args);
+ (void) fprintf(stderr, ": %s\n",
+ dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
+
+ exit(2);
+}
+
+static void
+show_events(char event_type, char *desc)
+{
+ int i, first = -1, last;
+
+ for (i = 0; i < LS_MAX_EVENTS; i++) {
+ ls_event_info_t *evp = &g_event_info[i];
+ if (evp->ev_type != event_type ||
+ strncmp(evp->ev_desc, "Unknown event", 13) == 0)
+ continue;
+ if (first == -1)
+ first = i;
+ last = i;
+ }
+
+ (void) fprintf(stderr,
+ "\n%s events (lockstat -%c or lockstat -e %d-%d):\n\n",
+ desc, event_type, first, last);
+
+ for (i = first; i <= last; i++)
+ (void) fprintf(stderr,
+ "%4d = %s\n", i, g_event_info[i].ev_desc);
+}
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr,
+ "Usage: lockstat [options] command [args]\n"
+ "\nGeneral options:\n\n"
+ " -V print the corresponding D program\n"
+ "\nEvent selection options:\n\n"
+ " -C watch contention events [on by default]\n"
+ " -E watch error events [off by default]\n"
+ " -H watch hold events [off by default]\n"
+ " -I watch interrupt events [off by default]\n"
+ " -A watch all lock events [equivalent to -CH]\n"
+ " -e event_list only watch the specified events (shown below);\n"
+ " <event_list> is a comma-separated list of\n"
+ " events or ranges of events, e.g. 1,4-7,35\n"
+ " -i rate interrupt rate for -I [default: %d Hz]\n"
+ "\nData gathering options:\n\n"
+ " -b basic statistics (lock, caller, event count)\n"
+ " -t timing for all events [default]\n"
+ " -h histograms for event times\n"
+ " -s depth stack traces <depth> deep\n"
+ " -x opt[=val] enable or modify DTrace options\n"
+ "\nData filtering options:\n\n"
+ " -n nrecords maximum number of data records [default: %d]\n"
+ " -l lock[,size] only watch <lock>, which can be specified as a\n"
+ " symbolic name or hex address; <size> defaults\n"
+ " to the ELF symbol size if available, 1 if not\n"
+ " -f func[,size] only watch events generated by <func>\n"
+ " -d duration only watch events longer than <duration>\n"
+ " -T trace (rather than sample) events\n"
+ "\nData reporting options:\n\n"
+#ifdef illumos
+ " -c coalesce lock data for arrays like pse_mutex[]\n"
+#endif
+ " -k coalesce PCs within functions\n"
+ " -g show total events generated by function\n"
+ " -w wherever: don't distinguish events by caller\n"
+ " -W whichever: don't distinguish events by lock\n"
+ " -R display rates rather than counts\n"
+ " -p parsable output format (awk(1)-friendly)\n"
+ " -P sort lock data by (count * avg_time) product\n"
+ " -D n only display top <n> events of each type\n"
+ " -o filename send output to <filename>\n",
+ DEFAULT_HZ, DEFAULT_NRECS);
+
+ show_events('C', "Contention");
+ show_events('H', "Hold-time");
+ show_events('I', "Interrupt");
+ show_events('E', "Error");
+ (void) fprintf(stderr, "\n");
+
+ exit(1);
+}
+
+static int
+lockcmp(lsrec_t *a, lsrec_t *b)
+{
+ int i;
+
+ if (a->ls_event < b->ls_event)
+ return (-1);
+ if (a->ls_event > b->ls_event)
+ return (1);
+
+ for (i = g_stkdepth - 1; i >= 0; i--) {
+ if (a->ls_stack[i] < b->ls_stack[i])
+ return (-1);
+ if (a->ls_stack[i] > b->ls_stack[i])
+ return (1);
+ }
+
+ if (a->ls_caller < b->ls_caller)
+ return (-1);
+ if (a->ls_caller > b->ls_caller)
+ return (1);
+
+#ifdef illumos
+ if (a->ls_lock < b->ls_lock)
+ return (-1);
+ if (a->ls_lock > b->ls_lock)
+ return (1);
+
+ return (0);
+#else
+ return (strcmp(a->ls_lock, b->ls_lock));
+#endif
+}
+
+static int
+countcmp(lsrec_t *a, lsrec_t *b)
+{
+ if (a->ls_event < b->ls_event)
+ return (-1);
+ if (a->ls_event > b->ls_event)
+ return (1);
+
+ return (b->ls_count - a->ls_count);
+}
+
+static int
+timecmp(lsrec_t *a, lsrec_t *b)
+{
+ if (a->ls_event < b->ls_event)
+ return (-1);
+ if (a->ls_event > b->ls_event)
+ return (1);
+
+ if (a->ls_time < b->ls_time)
+ return (1);
+ if (a->ls_time > b->ls_time)
+ return (-1);
+
+ return (0);
+}
+
+static int
+lockcmp_anywhere(lsrec_t *a, lsrec_t *b)
+{
+ if (a->ls_event < b->ls_event)
+ return (-1);
+ if (a->ls_event > b->ls_event)
+ return (1);
+
+#ifdef illumos
+ if (a->ls_lock < b->ls_lock)
+ return (-1);
+ if (a->ls_lock > b->ls_lock)
+ return (1);
+
+ return (0);
+#else
+ return (strcmp(a->ls_lock, b->ls_lock));
+#endif
+}
+
+static int
+lock_and_count_cmp_anywhere(lsrec_t *a, lsrec_t *b)
+{
+#ifndef illumos
+ int cmp;
+#endif
+
+ if (a->ls_event < b->ls_event)
+ return (-1);
+ if (a->ls_event > b->ls_event)
+ return (1);
+
+#ifdef illumos
+ if (a->ls_lock < b->ls_lock)
+ return (-1);
+ if (a->ls_lock > b->ls_lock)
+ return (1);
+#else
+ cmp = strcmp(a->ls_lock, b->ls_lock);
+ if (cmp != 0)
+ return (cmp);
+#endif
+
+ return (b->ls_count - a->ls_count);
+}
+
+static int
+sitecmp_anylock(lsrec_t *a, lsrec_t *b)
+{
+ int i;
+
+ if (a->ls_event < b->ls_event)
+ return (-1);
+ if (a->ls_event > b->ls_event)
+ return (1);
+
+ for (i = g_stkdepth - 1; i >= 0; i--) {
+ if (a->ls_stack[i] < b->ls_stack[i])
+ return (-1);
+ if (a->ls_stack[i] > b->ls_stack[i])
+ return (1);
+ }
+
+ if (a->ls_caller < b->ls_caller)
+ return (-1);
+ if (a->ls_caller > b->ls_caller)
+ return (1);
+
+ return (0);
+}
+
+static int
+site_and_count_cmp_anylock(lsrec_t *a, lsrec_t *b)
+{
+ int i;
+
+ if (a->ls_event < b->ls_event)
+ return (-1);
+ if (a->ls_event > b->ls_event)
+ return (1);
+
+ for (i = g_stkdepth - 1; i >= 0; i--) {
+ if (a->ls_stack[i] < b->ls_stack[i])
+ return (-1);
+ if (a->ls_stack[i] > b->ls_stack[i])
+ return (1);
+ }
+
+ if (a->ls_caller < b->ls_caller)
+ return (-1);
+ if (a->ls_caller > b->ls_caller)
+ return (1);
+
+ return (b->ls_count - a->ls_count);
+}
+
+static void
+lsmergesort(int (*cmp)(lsrec_t *, lsrec_t *), lsrec_t **a, lsrec_t **b, int n)
+{
+ int m = n / 2;
+ int i, j;
+
+ if (m > 1)
+ lsmergesort(cmp, a, b, m);
+ if (n - m > 1)
+ lsmergesort(cmp, a + m, b + m, n - m);
+ for (i = m; i > 0; i--)
+ b[i - 1] = a[i - 1];
+ for (j = m - 1; j < n - 1; j++)
+ b[n + m - j - 2] = a[j + 1];
+ while (i < j)
+ *a++ = cmp(b[i], b[j]) < 0 ? b[i++] : b[j--];
+ *a = b[i];
+}
+
+static void
+coalesce(int (*cmp)(lsrec_t *, lsrec_t *), lsrec_t **lock, int n)
+{
+ int i, j;
+ lsrec_t *target, *current;
+
+ target = lock[0];
+
+ for (i = 1; i < n; i++) {
+ current = lock[i];
+ if (cmp(current, target) != 0) {
+ target = current;
+ continue;
+ }
+ current->ls_event = LS_MAX_EVENTS;
+ target->ls_count += current->ls_count;
+ target->ls_refcnt += current->ls_refcnt;
+ if (g_recsize < LS_TIME)
+ continue;
+ target->ls_time += current->ls_time;
+ if (g_recsize < LS_HIST)
+ continue;
+ for (j = 0; j < 64; j++)
+ target->ls_hist[j] += current->ls_hist[j];
+ }
+}
+
+static void
+coalesce_symbol(uintptr_t *addrp)
+{
+ uintptr_t symoff;
+ size_t symsize;
+
+ if (addr_to_sym(*addrp, &symoff, &symsize) != NULL && symoff < symsize)
+ *addrp -= symoff;
+}
+
+static void
+predicate_add(char **pred, char *what, char *cmp, uintptr_t value)
+{
+ char *new;
+ int len, newlen;
+
+ if (what == NULL)
+ return;
+
+ if (*pred == NULL) {
+ *pred = malloc(1);
+ *pred[0] = '\0';
+ }
+
+ len = strlen(*pred);
+ newlen = len + strlen(what) + 32 + strlen("( && )");
+ new = malloc(newlen);
+
+ if (*pred[0] != '\0') {
+ if (cmp != NULL) {
+ (void) sprintf(new, "(%s) && (%s %s 0x%p)",
+ *pred, what, cmp, (void *)value);
+ } else {
+ (void) sprintf(new, "(%s) && (%s)", *pred, what);
+ }
+ } else {
+ if (cmp != NULL) {
+ (void) sprintf(new, "%s %s 0x%p",
+ what, cmp, (void *)value);
+ } else {
+ (void) sprintf(new, "%s", what);
+ }
+ }
+
+ free(*pred);
+ *pred = new;
+}
+
+static void
+predicate_destroy(char **pred)
+{
+ free(*pred);
+ *pred = NULL;
+}
+
+static void
+filter_add(char **filt, char *what, uintptr_t base, uintptr_t size)
+{
+ char buf[256], *c = buf, *new;
+ int len, newlen;
+
+ if (*filt == NULL) {
+ *filt = malloc(1);
+ *filt[0] = '\0';
+ }
+
+#ifdef illumos
+ (void) sprintf(c, "%s(%s >= 0x%p && %s < 0x%p)", *filt[0] != '\0' ?
+ " || " : "", what, (void *)base, what, (void *)(base + size));
+#else
+ (void) sprintf(c, "%s(%s >= %p && %s < %p)", *filt[0] != '\0' ?
+ " || " : "", what, (void *)base, what, (void *)(base + size));
+#endif
+
+ newlen = (len = strlen(*filt) + 1) + strlen(c);
+ new = malloc(newlen);
+ bcopy(*filt, new, len);
+ (void) strcat(new, c);
+ free(*filt);
+ *filt = new;
+}
+
+static void
+filter_destroy(char **filt)
+{
+ free(*filt);
+ *filt = NULL;
+}
+
+static void
+dprog_add(const char *fmt, ...)
+{
+ va_list args;
+ int size, offs;
+ char c;
+
+ va_start(args, fmt);
+ size = vsnprintf(&c, 1, fmt, args) + 1;
+ va_end(args);
+
+ if (g_proglen == 0) {
+ offs = 0;
+ } else {
+ offs = g_proglen - 1;
+ }
+
+ g_proglen = offs + size;
+
+ if ((g_prog = realloc(g_prog, g_proglen)) == NULL)
+ fail(1, "failed to reallocate program text");
+
+ va_start(args, fmt);
+ (void) vsnprintf(&g_prog[offs], size, fmt, args);
+ va_end(args);
+}
+
+/*
+ * This function may read like an open sewer, but keep in mind that programs
+ * that generate other programs are rarely pretty. If one has the unenviable
+ * task of maintaining or -- worse -- extending this code, use the -V option
+ * to examine the D program as generated by this function.
+ */
+static void
+dprog_addevent(int event)
+{
+ ls_event_info_t *info = &g_event_info[event];
+ char *pred = NULL;
+ char stack[20];
+ const char *arg0, *caller;
+ char *arg1 = "arg1";
+ char buf[80];
+ hrtime_t dur;
+ int depth;
+
+ if (info->ev_name[0] == '\0')
+ return;
+
+ if (info->ev_type == 'I') {
+ /*
+ * For interrupt events, arg0 (normally the lock pointer) is
+ * the CPU address plus the current pil, and arg1 (normally
+ * the number of nanoseconds) is the number of nanoseconds
+ * late -- and it's stored in arg2.
+ */
+#ifdef illumos
+ arg0 = "(uintptr_t)curthread->t_cpu + \n"
+ "\t curthread->t_cpu->cpu_profile_pil";
+#else
+ arg0 = "(uintptr_t)(curthread->td_oncpu << 16) + \n"
+ "\t 0x01000000 + curthread->td_pri_class";
+#endif
+ caller = "(uintptr_t)arg0";
+ arg1 = "arg2";
+ } else {
+#ifdef illumos
+ arg0 = "(uintptr_t)arg0";
+#else
+ arg0 = "stringof(args[0]->lock_object.lo_name)";
+#endif
+ caller = "caller";
+ }
+
+ if (g_recsize > LS_HIST) {
+ for (depth = 0; g_recsize > LS_STACK(depth); depth++)
+ continue;
+
+ if (g_tracing) {
+ (void) sprintf(stack, "\tstack(%d);\n", depth);
+ } else {
+ (void) sprintf(stack, ", stack(%d)", depth);
+ }
+ } else {
+ (void) sprintf(stack, "");
+ }
+
+ if (info->ev_acquire != NULL) {
+ /*
+ * If this is a hold event, we need to generate an additional
+ * clause for the acquire; the clause for the release will be
+ * generated with the aggregating statement, below.
+ */
+ dprog_add("%s\n", info->ev_acquire);
+ predicate_add(&pred, info->ev_predicate, NULL, 0);
+ predicate_add(&pred, g_predicate, NULL, 0);
+ if (pred != NULL)
+ dprog_add("/%s/\n", pred);
+
+ dprog_add("{\n");
+ (void) sprintf(buf, "self->ev%d[(uintptr_t)arg0]", event);
+
+ if (info->ev_type == 'H') {
+ dprog_add("\t%s = timestamp;\n", buf);
+ } else {
+ /*
+ * If this isn't a hold event, it's the recursive
+ * error event. For this, we simply bump the
+ * thread-local, per-lock count.
+ */
+ dprog_add("\t%s++;\n", buf);
+ }
+
+ dprog_add("}\n\n");
+ predicate_destroy(&pred);
+ pred = NULL;
+
+ if (info->ev_type == 'E') {
+ /*
+ * If this is the recursive lock error event, we need
+ * to generate an additional clause to decrement the
+ * thread-local, per-lock count. This assures that we
+ * only execute the aggregating clause if we have
+ * recursive entry.
+ */
+ dprog_add("%s\n", info->ev_name);
+ dprog_add("/%s/\n{\n\t%s--;\n}\n\n", buf, buf);
+ }
+
+ predicate_add(&pred, buf, NULL, 0);
+
+ if (info->ev_type == 'H') {
+ (void) sprintf(buf, "timestamp -\n\t "
+ "self->ev%d[(uintptr_t)arg0]", event);
+ }
+
+ arg1 = buf;
+ } else {
+ predicate_add(&pred, info->ev_predicate, NULL, 0);
+ if (info->ev_type != 'I')
+ predicate_add(&pred, g_predicate, NULL, 0);
+ else
+ predicate_add(&pred, g_ipredicate, NULL, 0);
+ }
+
+ if ((dur = g_min_duration[event]) != 0)
+ predicate_add(&pred, arg1, ">=", dur);
+
+ dprog_add("%s\n", info->ev_name);
+
+ if (pred != NULL)
+ dprog_add("/%s/\n", pred);
+ predicate_destroy(&pred);
+
+ dprog_add("{\n");
+
+ if (g_tracing) {
+ dprog_add("\ttrace(%dULL);\n", event);
+ dprog_add("\ttrace(%s);\n", arg0);
+ dprog_add("\ttrace(%s);\n", caller);
+ dprog_add(stack);
+ } else {
+ /*
+ * The ordering here is important: when we process the
+ * aggregate, we count on the fact that @avg appears before
+ * @hist in program order to assure that @avg is assigned the
+ * first aggregation variable ID and @hist assigned the
+ * second; see the comment in process_aggregate() for details.
+ */
+ dprog_add("\t@avg[%dULL, %s, %s%s] = avg(%s);\n",
+ event, arg0, caller, stack, arg1);
+
+ if (g_recsize >= LS_HIST) {
+ dprog_add("\t@hist[%dULL, %s, %s%s] = quantize"
+ "(%s);\n", event, arg0, caller, stack, arg1);
+ }
+ }
+
+ if (info->ev_acquire != NULL)
+ dprog_add("\tself->ev%d[arg0] = 0;\n", event);
+
+ dprog_add("}\n\n");
+}
+
+static void
+dprog_compile()
+{
+ dtrace_prog_t *prog;
+ dtrace_proginfo_t info;
+
+ if (g_Vflag) {
+ (void) fprintf(stderr, "lockstat: vvvv D program vvvv\n");
+ (void) fputs(g_prog, stderr);
+ (void) fprintf(stderr, "lockstat: ^^^^ D program ^^^^\n");
+ }
+
+ if ((prog = dtrace_program_strcompile(g_dtp, g_prog,
+ DTRACE_PROBESPEC_NAME, 0, 0, NULL)) == NULL)
+ dfail("failed to compile program");
+
+ if (dtrace_program_exec(g_dtp, prog, &info) == -1)
+ dfail("failed to enable probes");
+
+ if (dtrace_go(g_dtp) != 0)
+ dfail("couldn't start tracing");
+}
+
+static void
+#ifdef illumos
+status_fire(void)
+#else
+status_fire(int i)
+#endif
+{}
+
+static void
+status_init(void)
+{
+ dtrace_optval_t val, status, agg;
+ struct sigaction act;
+ struct itimerspec ts;
+ struct sigevent ev;
+ timer_t tid;
+
+ if (dtrace_getopt(g_dtp, "statusrate", &status) == -1)
+ dfail("failed to get 'statusrate'");
+
+ if (dtrace_getopt(g_dtp, "aggrate", &agg) == -1)
+ dfail("failed to get 'statusrate'");
+
+ /*
+ * We would want to awaken at a rate that is the GCD of the statusrate
+ * and the aggrate -- but that seems a bit absurd. Instead, we'll
+ * simply awaken at a rate that is the more frequent of the two, which
+ * assures that we're never later than the interval implied by the
+ * more frequent rate.
+ */
+ val = status < agg ? status : agg;
+
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = status_fire;
+ (void) sigaction(SIGUSR1, &act, NULL);
+
+ ev.sigev_notify = SIGEV_SIGNAL;
+ ev.sigev_signo = SIGUSR1;
+
+ if (timer_create(CLOCK_REALTIME, &ev, &tid) == -1)
+ dfail("cannot create CLOCK_REALTIME timer");
+
+ ts.it_value.tv_sec = val / NANOSEC;
+ ts.it_value.tv_nsec = val % NANOSEC;
+ ts.it_interval = ts.it_value;
+
+ if (timer_settime(tid, TIMER_RELTIME, &ts, NULL) == -1)
+ dfail("cannot set time on CLOCK_REALTIME timer");
+}
+
+static void
+status_check(void)
+{
+ if (!g_tracing && dtrace_aggregate_snap(g_dtp) != 0)
+ dfail("failed to snap aggregate");
+
+ if (dtrace_status(g_dtp) == -1)
+ dfail("dtrace_status()");
+}
+
+static void
+lsrec_fill(lsrec_t *lsrec, const dtrace_recdesc_t *rec, int nrecs, caddr_t data)
+{
+ bzero(lsrec, g_recsize);
+ lsrec->ls_count = 1;
+
+ if ((g_recsize > LS_HIST && nrecs < 4) || (nrecs < 3))
+ fail(0, "truncated DTrace record");
+
+ if (rec->dtrd_size != sizeof (uint64_t))
+ fail(0, "bad event size in first record");
+
+ /* LINTED - alignment */
+ lsrec->ls_event = (uint32_t)*((uint64_t *)(data + rec->dtrd_offset));
+ rec++;
+
+#ifdef illumos
+ if (rec->dtrd_size != sizeof (uintptr_t))
+ fail(0, "bad lock address size in second record");
+
+ /* LINTED - alignment */
+ lsrec->ls_lock = *((uintptr_t *)(data + rec->dtrd_offset));
+ rec++;
+#else
+ lsrec->ls_lock = strdup((const char *)(data + rec->dtrd_offset));
+ rec++;
+#endif
+
+ if (rec->dtrd_size != sizeof (uintptr_t))
+ fail(0, "bad caller size in third record");
+
+ /* LINTED - alignment */
+ lsrec->ls_caller = *((uintptr_t *)(data + rec->dtrd_offset));
+ rec++;
+
+ if (g_recsize > LS_HIST) {
+ int frames, i;
+ pc_t *stack;
+
+ frames = rec->dtrd_size / sizeof (pc_t);
+ /* LINTED - alignment */
+ stack = (pc_t *)(data + rec->dtrd_offset);
+
+ for (i = 1; i < frames; i++)
+ lsrec->ls_stack[i - 1] = stack[i];
+ }
+}
+
+/*ARGSUSED*/
+static int
+count_aggregate(const dtrace_aggdata_t *agg, void *arg)
+{
+ *((size_t *)arg) += 1;
+
+ return (DTRACE_AGGWALK_NEXT);
+}
+
+static int
+process_aggregate(const dtrace_aggdata_t *agg, void *arg)
+{
+ const dtrace_aggdesc_t *aggdesc = agg->dtada_desc;
+ caddr_t data = agg->dtada_data;
+ lsdata_t *lsdata = arg;
+ lsrec_t *lsrec = lsdata->lsd_next;
+ const dtrace_recdesc_t *rec;
+ uint64_t *avg, *quantized;
+ int i, j;
+
+ assert(lsdata->lsd_count < g_nrecs);
+
+ /*
+ * Aggregation variable IDs are guaranteed to be generated in program
+ * order, and they are guaranteed to start from DTRACE_AGGVARIDNONE
+ * plus one. As "avg" appears before "hist" in program order, we know
+ * that "avg" will be allocated the first aggregation variable ID, and
+ * "hist" will be allocated the second aggregation variable ID -- and
+ * we therefore use the aggregation variable ID to differentiate the
+ * cases.
+ */
+ if (aggdesc->dtagd_varid > DTRACE_AGGVARIDNONE + 1) {
+ /*
+ * If this is the histogram entry. We'll copy the quantized
+ * data into lc_hist, and jump over the rest.
+ */
+ rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
+
+ if (aggdesc->dtagd_varid != DTRACE_AGGVARIDNONE + 2)
+ fail(0, "bad variable ID in aggregation record");
+
+ if (rec->dtrd_size !=
+ DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
+ fail(0, "bad quantize size in aggregation record");
+
+ /* LINTED - alignment */
+ quantized = (uint64_t *)(data + rec->dtrd_offset);
+
+ for (i = DTRACE_QUANTIZE_ZEROBUCKET, j = 0;
+ i < DTRACE_QUANTIZE_NBUCKETS; i++, j++)
+ lsrec->ls_hist[j] = quantized[i];
+
+ goto out;
+ }
+
+ lsrec_fill(lsrec, &aggdesc->dtagd_rec[1],
+ aggdesc->dtagd_nrecs - 1, data);
+
+ rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
+
+ if (rec->dtrd_size != 2 * sizeof (uint64_t))
+ fail(0, "bad avg size in aggregation record");
+
+ /* LINTED - alignment */
+ avg = (uint64_t *)(data + rec->dtrd_offset);
+ lsrec->ls_count = (uint32_t)avg[0];
+ lsrec->ls_time = (uintptr_t)avg[1];
+
+ if (g_recsize >= LS_HIST)
+ return (DTRACE_AGGWALK_NEXT);
+
+out:
+ lsdata->lsd_next = (lsrec_t *)((uintptr_t)lsrec + g_recsize);
+ lsdata->lsd_count++;
+
+ return (DTRACE_AGGWALK_NEXT);
+}
+
+static int
+process_trace(const dtrace_probedata_t *pdata, void *arg)
+{
+ lsdata_t *lsdata = arg;
+ lsrec_t *lsrec = lsdata->lsd_next;
+ dtrace_eprobedesc_t *edesc = pdata->dtpda_edesc;
+ caddr_t data = pdata->dtpda_data;
+
+ if (lsdata->lsd_count >= g_nrecs)
+ return (DTRACE_CONSUME_NEXT);
+
+ lsrec_fill(lsrec, edesc->dtepd_rec, edesc->dtepd_nrecs, data);
+
+ lsdata->lsd_next = (lsrec_t *)((uintptr_t)lsrec + g_recsize);
+ lsdata->lsd_count++;
+
+ return (DTRACE_CONSUME_NEXT);
+}
+
+static int
+process_data(FILE *out, char *data)
+{
+ lsdata_t lsdata;
+
+ /* LINTED - alignment */
+ lsdata.lsd_next = (lsrec_t *)data;
+ lsdata.lsd_count = 0;
+
+ if (g_tracing) {
+ if (dtrace_consume(g_dtp, out,
+ process_trace, NULL, &lsdata) != 0)
+ dfail("failed to consume buffer");
+
+ return (lsdata.lsd_count);
+ }
+
+ if (dtrace_aggregate_walk_keyvarsorted(g_dtp,
+ process_aggregate, &lsdata) != 0)
+ dfail("failed to walk aggregate");
+
+ return (lsdata.lsd_count);
+}
+
+/*ARGSUSED*/
+static int
+drophandler(const dtrace_dropdata_t *data, void *arg)
+{
+ g_dropped++;
+ (void) fprintf(stderr, "lockstat: warning: %s", data->dtdda_msg);
+ return (DTRACE_HANDLE_OK);
+}
+
+int
+main(int argc, char **argv)
+{
+ char *data_buf;
+ lsrec_t *lsp, **current, **first, **sort_buf, **merge_buf;
+ FILE *out = stdout;
+ int c;
+ pid_t child;
+ int status;
+ int i, j;
+ hrtime_t duration;
+ char *addrp, *offp, *sizep, *evp, *lastp, *p;
+ uintptr_t addr;
+ size_t size, off;
+ int events_specified = 0;
+ int exec_errno = 0;
+ uint32_t event;
+ char *filt = NULL, *ifilt = NULL;
+ static uint64_t ev_count[LS_MAX_EVENTS + 1];
+ static uint64_t ev_time[LS_MAX_EVENTS + 1];
+ dtrace_optval_t aggsize;
+ char aggstr[10];
+ long ncpus;
+ int dynvar = 0;
+ int err;
+
+ if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
+ fail(0, "cannot open dtrace library: %s",
+ dtrace_errmsg(NULL, err));
+ }
+
+ if (dtrace_handle_drop(g_dtp, &drophandler, NULL) == -1)
+ dfail("couldn't establish drop handler");
+
+ if (symtab_init() == -1)
+ fail(1, "can't load kernel symbols");
+
+ g_nrecs = DEFAULT_NRECS;
+
+ while ((c = getopt(argc, argv, LOCKSTAT_OPTSTR)) != GETOPT_EOF) {
+ switch (c) {
+ case 'b':
+ g_recsize = LS_BASIC;
+ break;
+
+ case 't':
+ g_recsize = LS_TIME;
+ break;
+
+ case 'h':
+ g_recsize = LS_HIST;
+ break;
+
+ case 's':
+ if (!isdigit(optarg[0]))
+ usage();
+ g_stkdepth = atoi(optarg);
+ if (g_stkdepth > LS_MAX_STACK_DEPTH)
+ fail(0, "max stack depth is %d",
+ LS_MAX_STACK_DEPTH);
+ g_recsize = LS_STACK(g_stkdepth);
+ break;
+
+ case 'n':
+ if (!isdigit(optarg[0]))
+ usage();
+ g_nrecs = atoi(optarg);
+ break;
+
+ case 'd':
+ if (!isdigit(optarg[0]))
+ usage();
+ duration = atoll(optarg);
+
+ /*
+ * XXX -- durations really should be per event
+ * since the units are different, but it's hard
+ * to express this nicely in the interface.
+ * Not clear yet what the cleanest solution is.
+ */
+ for (i = 0; i < LS_MAX_EVENTS; i++)
+ if (g_event_info[i].ev_type != 'E')
+ g_min_duration[i] = duration;
+
+ break;
+
+ case 'i':
+ if (!isdigit(optarg[0]))
+ usage();
+ i = atoi(optarg);
+ if (i <= 0)
+ usage();
+ if (i > MAX_HZ)
+ fail(0, "max interrupt rate is %d Hz", MAX_HZ);
+
+ for (j = 0; j < LS_MAX_EVENTS; j++)
+ if (strcmp(g_event_info[j].ev_desc,
+ "Profiling interrupt") == 0)
+ break;
+
+ (void) sprintf(g_event_info[j].ev_name,
+ "profile:::profile-%d", i);
+ break;
+
+ case 'l':
+ case 'f':
+ addrp = strtok(optarg, ",");
+ sizep = strtok(NULL, ",");
+ addrp = strtok(optarg, ",+");
+ offp = strtok(NULL, ",");
+
+ size = sizep ? strtoul(sizep, NULL, 0) : 1;
+ off = offp ? strtoul(offp, NULL, 0) : 0;
+
+ if (addrp[0] == '0') {
+ addr = strtoul(addrp, NULL, 16) + off;
+ } else {
+ addr = sym_to_addr(addrp) + off;
+ if (sizep == NULL)
+ size = sym_size(addrp) - off;
+ if (addr - off == 0)
+ fail(0, "symbol '%s' not found", addrp);
+ if (size == 0)
+ size = 1;
+ }
+
+
+ if (c == 'l') {
+ filter_add(&filt, "arg0", addr, size);
+ } else {
+ filter_add(&filt, "caller", addr, size);
+ filter_add(&ifilt, "arg0", addr, size);
+ }
+ break;
+
+ case 'e':
+ evp = strtok_r(optarg, ",", &lastp);
+ while (evp) {
+ int ev1, ev2;
+ char *evp2;
+
+ (void) strtok(evp, "-");
+ evp2 = strtok(NULL, "-");
+ ev1 = atoi(evp);
+ ev2 = evp2 ? atoi(evp2) : ev1;
+ if ((uint_t)ev1 >= LS_MAX_EVENTS ||
+ (uint_t)ev2 >= LS_MAX_EVENTS || ev1 > ev2)
+ fail(0, "-e events out of range");
+ for (i = ev1; i <= ev2; i++)
+ g_enabled[i] = 1;
+ evp = strtok_r(NULL, ",", &lastp);
+ }
+ events_specified = 1;
+ break;
+
+#ifdef illumos
+ case 'c':
+ g_cflag = 1;
+ break;
+#endif
+
+ case 'k':
+ g_kflag = 1;
+ break;
+
+ case 'w':
+ g_wflag = 1;
+ break;
+
+ case 'W':
+ g_Wflag = 1;
+ break;
+
+ case 'g':
+ g_gflag = 1;
+ break;
+
+ case 'C':
+ case 'E':
+ case 'H':
+ case 'I':
+ for (i = 0; i < LS_MAX_EVENTS; i++)
+ if (g_event_info[i].ev_type == c)
+ g_enabled[i] = 1;
+ events_specified = 1;
+ break;
+
+ case 'A':
+ for (i = 0; i < LS_MAX_EVENTS; i++)
+ if (strchr("CH", g_event_info[i].ev_type))
+ g_enabled[i] = 1;
+ events_specified = 1;
+ break;
+
+ case 'T':
+ g_tracing = 1;
+ break;
+
+ case 'D':
+ if (!isdigit(optarg[0]))
+ usage();
+ g_topn = atoi(optarg);
+ break;
+
+ case 'R':
+ g_rates = 1;
+ break;
+
+ case 'p':
+ g_pflag = 1;
+ break;
+
+ case 'P':
+ g_Pflag = 1;
+ break;
+
+ case 'o':
+ if ((out = fopen(optarg, "w")) == NULL)
+ fail(1, "error opening file");
+ break;
+
+ case 'V':
+ g_Vflag = 1;
+ break;
+
+ default:
+ if (strchr(LOCKSTAT_OPTSTR, c) == NULL)
+ usage();
+ }
+ }
+
+ if (filt != NULL) {
+ predicate_add(&g_predicate, filt, NULL, 0);
+ filter_destroy(&filt);
+ }
+
+ if (ifilt != NULL) {
+ predicate_add(&g_ipredicate, ifilt, NULL, 0);
+ filter_destroy(&ifilt);
+ }
+
+ if (g_recsize == 0) {
+ if (g_gflag) {
+ g_stkdepth = LS_MAX_STACK_DEPTH;
+ g_recsize = LS_STACK(g_stkdepth);
+ } else {
+ g_recsize = LS_TIME;
+ }
+ }
+
+ if (g_gflag && g_recsize <= LS_STACK(0))
+ fail(0, "'-g' requires at least '-s 1' data gathering");
+
+ /*
+ * Make sure the alignment is reasonable
+ */
+ g_recsize = -(-g_recsize & -sizeof (uint64_t));
+
+ for (i = 0; i < LS_MAX_EVENTS; i++) {
+ /*
+ * If no events were specified, enable -C.
+ */
+ if (!events_specified && g_event_info[i].ev_type == 'C')
+ g_enabled[i] = 1;
+ }
+
+ for (i = 0; i < LS_MAX_EVENTS; i++) {
+ if (!g_enabled[i])
+ continue;
+
+ if (g_event_info[i].ev_acquire != NULL) {
+ /*
+ * If we've enabled a hold event, we must explicitly
+ * allocate dynamic variable space.
+ */
+ dynvar = 1;
+ }
+
+ dprog_addevent(i);
+ }
+
+ /*
+ * Make sure there are remaining arguments to specify a child command
+ * to execute.
+ */
+ if (argc <= optind)
+ usage();
+
+ if ((ncpus = sysconf(_SC_NPROCESSORS_ONLN)) == -1)
+ dfail("couldn't determine number of online CPUs");
+
+ /*
+ * By default, we set our data buffer size to be the number of records
+ * multiplied by the size of the record, doubled to account for some
+ * DTrace slop and divided by the number of CPUs. We silently clamp
+ * the aggregation size at both a minimum and a maximum to prevent
+ * absurdly low or high values.
+ */
+ if ((aggsize = (g_nrecs * g_recsize * 2) / ncpus) < MIN_AGGSIZE)
+ aggsize = MIN_AGGSIZE;
+
+ if (aggsize > MAX_AGGSIZE)
+ aggsize = MAX_AGGSIZE;
+
+ (void) sprintf(aggstr, "%lld", (long long)aggsize);
+
+ if (!g_tracing) {
+ if (dtrace_setopt(g_dtp, "bufsize", "4k") == -1)
+ dfail("failed to set 'bufsize'");
+
+ if (dtrace_setopt(g_dtp, "aggsize", aggstr) == -1)
+ dfail("failed to set 'aggsize'");
+
+ if (dynvar) {
+ /*
+ * If we're using dynamic variables, we set our
+ * dynamic variable size to be one megabyte per CPU,
+ * with a hard-limit of 32 megabytes. This may still
+ * be too small in some cases, but it can be tuned
+ * manually via -x if need be.
+ */
+ (void) sprintf(aggstr, "%ldm", ncpus < 32 ? ncpus : 32);
+
+ if (dtrace_setopt(g_dtp, "dynvarsize", aggstr) == -1)
+ dfail("failed to set 'dynvarsize'");
+ }
+ } else {
+ if (dtrace_setopt(g_dtp, "bufsize", aggstr) == -1)
+ dfail("failed to set 'bufsize'");
+ }
+
+ if (dtrace_setopt(g_dtp, "statusrate", "10sec") == -1)
+ dfail("failed to set 'statusrate'");
+
+ optind = 1;
+ while ((c = getopt(argc, argv, LOCKSTAT_OPTSTR)) != GETOPT_EOF) {
+ switch (c) {
+ case 'x':
+ if ((p = strchr(optarg, '=')) != NULL)
+ *p++ = '\0';
+
+ if (dtrace_setopt(g_dtp, optarg, p) != 0)
+ dfail("failed to set -x %s", optarg);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ dprog_compile();
+ status_init();
+
+ g_elapsed = -gethrtime();
+
+ /*
+ * Spawn the specified command and wait for it to complete.
+ */
+ child = fork();
+ if (child == -1)
+ fail(1, "cannot fork");
+ if (child == 0) {
+ (void) dtrace_close(g_dtp);
+ (void) execvp(argv[0], &argv[0]);
+ exec_errno = errno;
+ exit(127);
+ }
+
+#ifdef illumos
+ while (waitpid(child, &status, WEXITED) != child)
+#else
+ while (waitpid(child, &status, 0) != child)
+#endif
+ status_check();
+
+ g_elapsed += gethrtime();
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0) {
+ if (exec_errno != 0) {
+ errno = exec_errno;
+ fail(1, "could not execute %s", argv[0]);
+ }
+ (void) fprintf(stderr,
+ "lockstat: warning: %s exited with code %d\n",
+ argv[0], WEXITSTATUS(status));
+ }
+ } else {
+ (void) fprintf(stderr,
+ "lockstat: warning: %s died on signal %d\n",
+ argv[0], WTERMSIG(status));
+ }
+
+ if (dtrace_stop(g_dtp) == -1)
+ dfail("failed to stop dtrace");
+
+ /*
+ * Before we read out the results, we need to allocate our buffer.
+ * If we're tracing, then we'll just use the precalculated size. If
+ * we're not, then we'll take a snapshot of the aggregate, and walk
+ * it to count the number of records.
+ */
+ if (!g_tracing) {
+ if (dtrace_aggregate_snap(g_dtp) != 0)
+ dfail("failed to snap aggregate");
+
+ g_nrecs = 0;
+
+ if (dtrace_aggregate_walk(g_dtp,
+ count_aggregate, &g_nrecs) != 0)
+ dfail("failed to walk aggregate");
+ }
+
+#ifdef illumos
+ if ((data_buf = memalign(sizeof (uint64_t),
+ (g_nrecs + 1) * g_recsize)) == NULL)
+#else
+ if (posix_memalign((void **)&data_buf, sizeof (uint64_t),
+ (g_nrecs + 1) * g_recsize) )
+#endif
+ fail(1, "Memory allocation failed");
+
+ /*
+ * Read out the DTrace data.
+ */
+ g_nrecs_used = process_data(out, data_buf);
+
+ if (g_nrecs_used > g_nrecs || g_dropped)
+ (void) fprintf(stderr, "lockstat: warning: "
+ "ran out of data records (use -n for more)\n");
+
+ /* LINTED - alignment */
+ for (i = 0, lsp = (lsrec_t *)data_buf; i < g_nrecs_used; i++,
+ /* LINTED - alignment */
+ lsp = (lsrec_t *)((char *)lsp + g_recsize)) {
+ ev_count[lsp->ls_event] += lsp->ls_count;
+ ev_time[lsp->ls_event] += lsp->ls_time;
+ }
+
+ /*
+ * If -g was specified, convert stacks into individual records.
+ */
+ if (g_gflag) {
+ lsrec_t *newlsp, *oldlsp;
+
+#ifdef illumos
+ newlsp = memalign(sizeof (uint64_t),
+ g_nrecs_used * LS_TIME * (g_stkdepth + 1));
+#else
+ posix_memalign((void **)&newlsp, sizeof (uint64_t),
+ g_nrecs_used * LS_TIME * (g_stkdepth + 1));
+#endif
+ if (newlsp == NULL)
+ fail(1, "Cannot allocate space for -g processing");
+ lsp = newlsp;
+ /* LINTED - alignment */
+ for (i = 0, oldlsp = (lsrec_t *)data_buf; i < g_nrecs_used; i++,
+ /* LINTED - alignment */
+ oldlsp = (lsrec_t *)((char *)oldlsp + g_recsize)) {
+ int fr;
+ int caller_in_stack = 0;
+
+ if (oldlsp->ls_count == 0)
+ continue;
+
+ for (fr = 0; fr < g_stkdepth; fr++) {
+ if (oldlsp->ls_stack[fr] == 0)
+ break;
+ if (oldlsp->ls_stack[fr] == oldlsp->ls_caller)
+ caller_in_stack = 1;
+ bcopy(oldlsp, lsp, LS_TIME);
+ lsp->ls_caller = oldlsp->ls_stack[fr];
+#ifndef illumos
+ lsp->ls_lock = strdup(oldlsp->ls_lock);
+#endif
+ /* LINTED - alignment */
+ lsp = (lsrec_t *)((char *)lsp + LS_TIME);
+ }
+ if (!caller_in_stack) {
+ bcopy(oldlsp, lsp, LS_TIME);
+ /* LINTED - alignment */
+ lsp = (lsrec_t *)((char *)lsp + LS_TIME);
+ }
+#ifndef illumos
+ free(oldlsp->ls_lock);
+#endif
+ }
+ g_nrecs = g_nrecs_used =
+ ((uintptr_t)lsp - (uintptr_t)newlsp) / LS_TIME;
+ g_recsize = LS_TIME;
+ g_stkdepth = 0;
+ free(data_buf);
+ data_buf = (char *)newlsp;
+ }
+
+ if ((sort_buf = calloc(2 * (g_nrecs + 1),
+ sizeof (void *))) == NULL)
+ fail(1, "Sort buffer allocation failed");
+ merge_buf = sort_buf + (g_nrecs + 1);
+
+ /*
+ * Build the sort buffer, discarding zero-count records along the way.
+ */
+ /* LINTED - alignment */
+ for (i = 0, lsp = (lsrec_t *)data_buf; i < g_nrecs_used; i++,
+ /* LINTED - alignment */
+ lsp = (lsrec_t *)((char *)lsp + g_recsize)) {
+ if (lsp->ls_count == 0)
+ lsp->ls_event = LS_MAX_EVENTS;
+ sort_buf[i] = lsp;
+ }
+
+ if (g_nrecs_used == 0)
+ exit(0);
+
+ /*
+ * Add a sentinel after the last record
+ */
+ sort_buf[i] = lsp;
+ lsp->ls_event = LS_MAX_EVENTS;
+
+ if (g_tracing) {
+ report_trace(out, sort_buf);
+ return (0);
+ }
+
+ /*
+ * Application of -g may have resulted in multiple records
+ * with the same signature; coalesce them.
+ */
+ if (g_gflag) {
+ mergesort(lockcmp, sort_buf, merge_buf, g_nrecs_used);
+ coalesce(lockcmp, sort_buf, g_nrecs_used);
+ }
+
+ /*
+ * Coalesce locks within the same symbol if -c option specified.
+ * Coalesce PCs within the same function if -k option specified.
+ */
+ if (g_cflag || g_kflag) {
+ for (i = 0; i < g_nrecs_used; i++) {
+ int fr;
+ lsp = sort_buf[i];
+#ifdef illumos
+ if (g_cflag)
+ coalesce_symbol(&lsp->ls_lock);
+#endif
+ if (g_kflag) {
+ for (fr = 0; fr < g_stkdepth; fr++)
+ coalesce_symbol(&lsp->ls_stack[fr]);
+ coalesce_symbol(&lsp->ls_caller);
+ }
+ }
+ mergesort(lockcmp, sort_buf, merge_buf, g_nrecs_used);
+ coalesce(lockcmp, sort_buf, g_nrecs_used);
+ }
+
+ /*
+ * Coalesce callers if -w option specified
+ */
+ if (g_wflag) {
+ mergesort(lock_and_count_cmp_anywhere,
+ sort_buf, merge_buf, g_nrecs_used);
+ coalesce(lockcmp_anywhere, sort_buf, g_nrecs_used);
+ }
+
+ /*
+ * Coalesce locks if -W option specified
+ */
+ if (g_Wflag) {
+ mergesort(site_and_count_cmp_anylock,
+ sort_buf, merge_buf, g_nrecs_used);
+ coalesce(sitecmp_anylock, sort_buf, g_nrecs_used);
+ }
+
+ /*
+ * Sort data by contention count (ls_count) or total time (ls_time),
+ * depending on g_Pflag. Override g_Pflag if time wasn't measured.
+ */
+ if (g_recsize < LS_TIME)
+ g_Pflag = 0;
+
+ if (g_Pflag)
+ mergesort(timecmp, sort_buf, merge_buf, g_nrecs_used);
+ else
+ mergesort(countcmp, sort_buf, merge_buf, g_nrecs_used);
+
+ /*
+ * Display data by event type
+ */
+ first = &sort_buf[0];
+ while ((event = (*first)->ls_event) < LS_MAX_EVENTS) {
+ current = first;
+ while ((lsp = *current)->ls_event == event)
+ current++;
+ report_stats(out, first, current - first, ev_count[event],
+ ev_time[event]);
+ first = current;
+ }
+
+#ifndef illumos
+ /*
+ * Free lock name buffers
+ */
+ for (i = 0, lsp = (lsrec_t *)data_buf; i < g_nrecs_used; i++,
+ lsp = (lsrec_t *)((char *)lsp + g_recsize))
+ free(lsp->ls_lock);
+#endif
+
+ return (0);
+}
+
+static char *
+format_symbol(char *buf, uintptr_t addr, int show_size)
+{
+ uintptr_t symoff;
+ char *symname;
+ size_t symsize;
+
+ symname = addr_to_sym(addr, &symoff, &symsize);
+
+ if (show_size && symoff == 0)
+ (void) sprintf(buf, "%s[%ld]", symname, (long)symsize);
+ else if (symoff == 0)
+ (void) sprintf(buf, "%s", symname);
+ else if (symoff < 16 && bcmp(symname, "cpu[", 4) == 0) /* CPU+PIL */
+#ifdef illumos
+ (void) sprintf(buf, "%s+%ld", symname, (long)symoff);
+#else
+ (void) sprintf(buf, "%s+%s", symname, g_pri_class[(int)symoff]);
+#endif
+ else if (symoff <= symsize || (symoff < 256 && addr != symoff))
+ (void) sprintf(buf, "%s+0x%llx", symname,
+ (unsigned long long)symoff);
+ else
+ (void) sprintf(buf, "0x%llx", (unsigned long long)addr);
+ return (buf);
+}
+
+static void
+report_stats(FILE *out, lsrec_t **sort_buf, size_t nrecs, uint64_t total_count,
+ uint64_t total_time)
+{
+ uint32_t event = sort_buf[0]->ls_event;
+ lsrec_t *lsp;
+ double ptotal = 0.0;
+ double percent;
+ int i, j, fr;
+ int displayed;
+ int first_bin, last_bin, max_bin_count, total_bin_count;
+ int rectype;
+ char buf[256];
+ char lhdr[80], chdr[80];
+
+ rectype = g_recsize;
+
+ if (g_topn == 0) {
+ (void) fprintf(out, "%20llu %s\n",
+ g_rates == 0 ? total_count :
+ ((unsigned long long)total_count * NANOSEC) / g_elapsed,
+ g_event_info[event].ev_desc);
+ return;
+ }
+
+ (void) sprintf(lhdr, "%s%s",
+ g_Wflag ? "Hottest " : "", g_event_info[event].ev_lhdr);
+ (void) sprintf(chdr, "%s%s",
+ g_wflag ? "Hottest " : "", "Caller");
+
+ if (!g_pflag)
+ (void) fprintf(out,
+ "\n%s: %.0f events in %.3f seconds (%.0f events/sec)\n\n",
+ g_event_info[event].ev_desc, (double)total_count,
+ (double)g_elapsed / NANOSEC,
+ (double)total_count * NANOSEC / g_elapsed);
+
+ if (!g_pflag && rectype < LS_HIST) {
+ (void) sprintf(buf, "%s", g_event_info[event].ev_units);
+ (void) fprintf(out, "%5s %4s %4s %4s %8s %-22s %-24s\n",
+ g_rates ? "ops/s" : "Count",
+ g_gflag ? "genr" : "indv",
+ "cuml", "rcnt", rectype >= LS_TIME ? buf : "", lhdr, chdr);
+ (void) fprintf(out, "---------------------------------"
+ "----------------------------------------------\n");
+ }
+
+ displayed = 0;
+ for (i = 0; i < nrecs; i++) {
+ lsp = sort_buf[i];
+
+ if (displayed++ >= g_topn)
+ break;
+
+ if (g_pflag) {
+ int j;
+
+ (void) fprintf(out, "%u %u",
+ lsp->ls_event, lsp->ls_count);
+#ifdef illumos
+ (void) fprintf(out, " %s",
+ format_symbol(buf, lsp->ls_lock, g_cflag));
+#else
+ (void) fprintf(out, " %s", lsp->ls_lock);
+#endif
+ (void) fprintf(out, " %s",
+ format_symbol(buf, lsp->ls_caller, 0));
+ (void) fprintf(out, " %f",
+ (double)lsp->ls_refcnt / lsp->ls_count);
+ if (rectype >= LS_TIME)
+ (void) fprintf(out, " %llu",
+ (unsigned long long)lsp->ls_time);
+ if (rectype >= LS_HIST) {
+ for (j = 0; j < 64; j++)
+ (void) fprintf(out, " %u",
+ lsp->ls_hist[j]);
+ }
+ for (j = 0; j < LS_MAX_STACK_DEPTH; j++) {
+ if (rectype <= LS_STACK(j) ||
+ lsp->ls_stack[j] == 0)
+ break;
+ (void) fprintf(out, " %s",
+ format_symbol(buf, lsp->ls_stack[j], 0));
+ }
+ (void) fprintf(out, "\n");
+ continue;
+ }
+
+ if (rectype >= LS_HIST) {
+ (void) fprintf(out, "---------------------------------"
+ "----------------------------------------------\n");
+ (void) sprintf(buf, "%s",
+ g_event_info[event].ev_units);
+ (void) fprintf(out, "%5s %4s %4s %4s %8s %-22s %-24s\n",
+ g_rates ? "ops/s" : "Count",
+ g_gflag ? "genr" : "indv",
+ "cuml", "rcnt", buf, lhdr, chdr);
+ }
+
+ if (g_Pflag && total_time != 0)
+ percent = (lsp->ls_time * 100.00) / total_time;
+ else
+ percent = (lsp->ls_count * 100.00) / total_count;
+
+ ptotal += percent;
+
+ if (rectype >= LS_TIME)
+ (void) sprintf(buf, "%llu",
+ (unsigned long long)(lsp->ls_time / lsp->ls_count));
+ else
+ buf[0] = '\0';
+
+ (void) fprintf(out, "%5llu ",
+ g_rates == 0 ? lsp->ls_count :
+ ((uint64_t)lsp->ls_count * NANOSEC) / g_elapsed);
+
+ (void) fprintf(out, "%3.0f%% ", percent);
+
+ if (g_gflag)
+ (void) fprintf(out, "---- ");
+ else
+ (void) fprintf(out, "%3.0f%% ", ptotal);
+
+ (void) fprintf(out, "%4.2f %8s ",
+ (double)lsp->ls_refcnt / lsp->ls_count, buf);
+
+#ifdef illumos
+ (void) fprintf(out, "%-22s ",
+ format_symbol(buf, lsp->ls_lock, g_cflag));
+#else
+ (void) fprintf(out, "%-22s ", lsp->ls_lock);
+#endif
+
+ (void) fprintf(out, "%-24s\n",
+ format_symbol(buf, lsp->ls_caller, 0));
+
+ if (rectype < LS_HIST)
+ continue;
+
+ (void) fprintf(out, "\n");
+ (void) fprintf(out, "%10s %31s %-9s %-24s\n",
+ g_event_info[event].ev_units,
+ "------ Time Distribution ------",
+ g_rates ? "ops/s" : "count",
+ rectype > LS_STACK(0) ? "Stack" : "");
+
+ first_bin = 0;
+ while (lsp->ls_hist[first_bin] == 0)
+ first_bin++;
+
+ last_bin = 63;
+ while (lsp->ls_hist[last_bin] == 0)
+ last_bin--;
+
+ max_bin_count = 0;
+ total_bin_count = 0;
+ for (j = first_bin; j <= last_bin; j++) {
+ total_bin_count += lsp->ls_hist[j];
+ if (lsp->ls_hist[j] > max_bin_count)
+ max_bin_count = lsp->ls_hist[j];
+ }
+
+ /*
+ * If we went a few frames below the caller, ignore them
+ */
+ for (fr = 3; fr > 0; fr--)
+ if (lsp->ls_stack[fr] == lsp->ls_caller)
+ break;
+
+ for (j = first_bin; j <= last_bin; j++) {
+ uint_t depth = (lsp->ls_hist[j] * 30) / total_bin_count;
+ (void) fprintf(out, "%10llu |%s%s %-9u ",
+ 1ULL << j,
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 30 - depth,
+ " " + depth,
+ g_rates == 0 ? lsp->ls_hist[j] :
+ (uint_t)(((uint64_t)lsp->ls_hist[j] * NANOSEC) /
+ g_elapsed));
+ if (rectype <= LS_STACK(fr) || lsp->ls_stack[fr] == 0) {
+ (void) fprintf(out, "\n");
+ continue;
+ }
+ (void) fprintf(out, "%-24s\n",
+ format_symbol(buf, lsp->ls_stack[fr], 0));
+ fr++;
+ }
+ while (rectype > LS_STACK(fr) && lsp->ls_stack[fr] != 0) {
+ (void) fprintf(out, "%15s %-36s %-24s\n", "", "",
+ format_symbol(buf, lsp->ls_stack[fr], 0));
+ fr++;
+ }
+ }
+
+ if (!g_pflag)
+ (void) fprintf(out, "---------------------------------"
+ "----------------------------------------------\n");
+
+ (void) fflush(out);
+}
+
+static void
+report_trace(FILE *out, lsrec_t **sort_buf)
+{
+ lsrec_t *lsp;
+ int i, fr;
+ int rectype;
+ char buf[256], buf2[256];
+
+ rectype = g_recsize;
+
+ if (!g_pflag) {
+ (void) fprintf(out, "%5s %7s %11s %-24s %-24s\n",
+ "Event", "Time", "Owner", "Lock", "Caller");
+ (void) fprintf(out, "---------------------------------"
+ "----------------------------------------------\n");
+ }
+
+ for (i = 0; i < g_nrecs_used; i++) {
+
+ lsp = sort_buf[i];
+
+ if (lsp->ls_event >= LS_MAX_EVENTS || lsp->ls_count == 0)
+ continue;
+
+ (void) fprintf(out, "%2d %10llu %11p %-24s %-24s\n",
+ lsp->ls_event, (unsigned long long)lsp->ls_time,
+ (void *)lsp->ls_next,
+#ifdef illumos
+ format_symbol(buf, lsp->ls_lock, 0),
+#else
+ lsp->ls_lock,
+#endif
+ format_symbol(buf2, lsp->ls_caller, 0));
+
+ if (rectype <= LS_STACK(0))
+ continue;
+
+ /*
+ * If we went a few frames below the caller, ignore them
+ */
+ for (fr = 3; fr > 0; fr--)
+ if (lsp->ls_stack[fr] == lsp->ls_caller)
+ break;
+
+ while (rectype > LS_STACK(fr) && lsp->ls_stack[fr] != 0) {
+ (void) fprintf(out, "%53s %-24s\n", "",
+ format_symbol(buf, lsp->ls_stack[fr], 0));
+ fr++;
+ }
+ (void) fprintf(out, "\n");
+ }
+
+ (void) fflush(out);
+}
diff --git a/cddl/contrib/opensolaris/cmd/lockstat/sym.c b/cddl/contrib/opensolaris/cmd/lockstat/sym.c
new file mode 100644
index 000000000000..f2987a028e74
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/lockstat/sym.c
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <libelf.h>
+#include <link.h>
+#include <elf.h>
+#ifdef illumos
+#include <sys/machelf.h>
+
+#include <kstat.h>
+#else
+#include <sys/elf.h>
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/linker.h>
+#endif
+#include <sys/cpuvar.h>
+
+typedef struct syment {
+ uintptr_t addr;
+ char *name;
+ size_t size;
+} syment_t;
+
+static syment_t *symbol_table;
+static int nsyms, maxsyms;
+static char maxsymname[64];
+
+#ifdef illumos
+#ifdef _ELF64
+#define elf_getshdr elf64_getshdr
+#else
+#define elf_getshdr elf32_getshdr
+#endif
+#endif
+
+static void
+add_symbol(char *name, uintptr_t addr, size_t size)
+{
+ syment_t *sep;
+
+ if (nsyms >= maxsyms) {
+ maxsyms += 10000;
+ symbol_table = realloc(symbol_table, maxsyms * sizeof (*sep));
+ if (symbol_table == NULL) {
+ (void) fprintf(stderr, "can't allocate symbol table\n");
+ exit(3);
+ }
+ }
+ sep = &symbol_table[nsyms++];
+
+ sep->name = name;
+ sep->addr = addr;
+ sep->size = size;
+}
+
+static void
+remove_symbol(uintptr_t addr)
+{
+ int i;
+ syment_t *sep = symbol_table;
+
+ for (i = 0; i < nsyms; i++, sep++)
+ if (sep->addr == addr)
+ sep->addr = 0;
+}
+
+#ifdef illumos
+static void
+fake_up_certain_popular_kernel_symbols(void)
+{
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ char *name;
+
+ if ((kc = kstat_open()) == NULL)
+ return;
+
+ for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
+ if (strcmp(ksp->ks_module, "cpu_info") == 0) {
+ if ((name = malloc(20)) == NULL)
+ break;
+ /*
+ * For consistency, keep cpu[0] and toss cpu0
+ * or any other such symbols.
+ */
+ if (ksp->ks_instance == 0)
+ remove_symbol((uintptr_t)ksp->ks_private);
+ (void) sprintf(name, "cpu[%d]", ksp->ks_instance);
+ add_symbol(name, (uintptr_t)ksp->ks_private,
+ sizeof (struct cpu));
+ }
+ }
+ (void) kstat_close(kc);
+}
+#else /* !illumos */
+static void
+fake_up_certain_popular_kernel_symbols(void)
+{
+ char *name;
+ uintptr_t addr;
+ int i;
+
+ /* Good for up to 256 CPUs */
+ for(i=0; i < 256; i++) {
+ if ((name = malloc(20)) == NULL)
+ break;
+ (void) sprintf(name, "cpu[%d]", i);
+ addr = 0x01000000 + (i << 16);
+ add_symbol(name, addr, sizeof (uintptr_t));
+ }
+}
+#endif /* illumos */
+
+static int
+symcmp(const void *p1, const void *p2)
+{
+ uintptr_t a1 = ((syment_t *)p1)->addr;
+ uintptr_t a2 = ((syment_t *)p2)->addr;
+
+ if (a1 < a2)
+ return (-1);
+ if (a1 > a2)
+ return (1);
+ return (0);
+}
+
+int
+symtab_init(void)
+{
+ Elf *elf;
+ Elf_Scn *scn = NULL;
+ Sym *symtab, *symp, *lastsym;
+ char *strtab;
+ uint_t cnt;
+ int fd;
+ int i;
+ int strindex = -1;
+
+#ifndef illumos
+ if ((fd = open("/dev/ksyms", O_RDONLY)) == -1) {
+ if (errno == ENOENT && modfind("ksyms") == -1) {
+ kldload("ksyms");
+ fd = open("/dev/ksyms", O_RDONLY);
+ }
+ if (fd == -1)
+ return (-1);
+ }
+#else
+ if ((fd = open("/dev/ksyms", O_RDONLY)) == -1)
+ return (-1);
+#endif
+
+ (void) elf_version(EV_CURRENT);
+
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+
+ for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) {
+ Shdr *shdr = elf_getshdr(scn);
+ if (shdr->sh_type == SHT_SYMTAB) {
+ symtab = (Sym *)elf_getdata(scn, NULL)->d_buf;
+ nsyms = shdr->sh_size / shdr->sh_entsize;
+ strindex = shdr->sh_link;
+ }
+ }
+
+ for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) {
+ if (cnt == strindex)
+ strtab = (char *)elf_getdata(scn, NULL)->d_buf;
+ }
+
+ lastsym = symtab + nsyms;
+ nsyms = 0;
+ for (symp = symtab; symp < lastsym; symp++)
+ if ((uint_t)ELF32_ST_TYPE(symp->st_info) <= STT_FUNC &&
+ symp->st_size != 0)
+ add_symbol(symp->st_name + strtab,
+ (uintptr_t)symp->st_value, (size_t)symp->st_size);
+
+ fake_up_certain_popular_kernel_symbols();
+ (void) sprintf(maxsymname, "0x%lx", ULONG_MAX);
+ add_symbol(maxsymname, ULONG_MAX, 1);
+
+ qsort(symbol_table, nsyms, sizeof (syment_t), symcmp);
+
+ /*
+ * Destroy all duplicate symbols, then sort it again.
+ */
+ for (i = 0; i < nsyms - 1; i++)
+ if (symbol_table[i].addr == symbol_table[i + 1].addr)
+ symbol_table[i].addr = 0;
+
+ qsort(symbol_table, nsyms, sizeof (syment_t), symcmp);
+
+ while (symbol_table[1].addr == 0) {
+ symbol_table++;
+ nsyms--;
+ }
+ symbol_table[0].name = "(usermode)";
+ symbol_table[0].addr = 0;
+ symbol_table[0].size = 1;
+
+ close(fd);
+ return (0);
+}
+
+char *
+addr_to_sym(uintptr_t addr, uintptr_t *offset, size_t *sizep)
+{
+ int lo = 0;
+ int hi = nsyms - 1;
+ int mid;
+ syment_t *sep;
+
+ while (hi - lo > 1) {
+ mid = (lo + hi) / 2;
+ if (addr >= symbol_table[mid].addr) {
+ lo = mid;
+ } else {
+ hi = mid;
+ }
+ }
+ sep = &symbol_table[lo];
+ *offset = addr - sep->addr;
+ *sizep = sep->size;
+ return (sep->name);
+}
+
+uintptr_t
+sym_to_addr(char *name)
+{
+ int i;
+ syment_t *sep = symbol_table;
+
+ for (i = 0; i < nsyms; i++) {
+ if (strcmp(name, sep->name) == 0)
+ return (sep->addr);
+ sep++;
+ }
+ return (0);
+}
+
+size_t
+sym_size(char *name)
+{
+ int i;
+ syment_t *sep = symbol_table;
+
+ for (i = 0; i < nsyms; i++) {
+ if (strcmp(name, sep->name) == 0)
+ return (sep->size);
+ sep++;
+ }
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/mdb/tools/common/die.c b/cddl/contrib/opensolaris/cmd/mdb/tools/common/die.c
new file mode 100644
index 000000000000..7bfc06bf2285
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/mdb/tools/common/die.c
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <elf.h>
+
+#include <util.h>
+
+void
+die(char *format, ...)
+{
+ va_list ap;
+ int err = errno;
+#ifndef illumos
+ const char *progname = getprogname();
+#endif
+
+ (void) fprintf(stderr, "%s: ", progname);
+
+ va_start(ap, format);
+ /* LINTED - variable format specifier */
+ (void) vfprintf(stderr, format, ap);
+ va_end(ap);
+
+ if (format[strlen(format) - 1] != '\n')
+ (void) fprintf(stderr, ": %s\n", strerror(err));
+
+#ifndef illumos
+ exit(0);
+#else
+ exit(1);
+#endif
+}
+
+void
+elfdie(char *format, ...)
+{
+ va_list ap;
+#ifndef illumos
+ const char *progname = getprogname();
+#endif
+
+ (void) fprintf(stderr, "%s: ", progname);
+
+ va_start(ap, format);
+ /* LINTED - variable format specifier */
+ (void) vfprintf(stderr, format, ap);
+ va_end(ap);
+
+ if (format[strlen(format) - 1] != '\n')
+ (void) fprintf(stderr, ": %s\n", elf_errmsg(elf_errno()));
+
+#ifndef illumos
+ exit(0);
+#else
+ exit(1);
+#endif
+}
diff --git a/cddl/contrib/opensolaris/cmd/mdb/tools/common/util.h b/cddl/contrib/opensolaris/cmd/mdb/tools/common/util.h
new file mode 100644
index 000000000000..737d2221f62f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/mdb/tools/common/util.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libelf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int findelfsecidx(Elf *, char *);
+
+extern void die(char *, ...);
+extern void elfdie(char *, ...);
+
+#ifdef illumos
+extern const char *progname;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_H */
diff --git a/cddl/contrib/opensolaris/cmd/plockstat/plockstat.c b/cddl/contrib/opensolaris/cmd/plockstat/plockstat.c
new file mode 100644
index 000000000000..e21567be5c52
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/plockstat/plockstat.c
@@ -0,0 +1,1022 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifdef illumos
+#pragma ident "%Z%%M% %I% %E% SMI"
+#endif
+
+#include <assert.h>
+#include <dtrace.h>
+#include <limits.h>
+#include <link.h>
+#include <priv.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <libgen.h>
+#include <libproc.h>
+#include <libproc_compat.h>
+
+static char *g_pname;
+static dtrace_hdl_t *g_dtp;
+struct ps_prochandle *g_pr;
+
+#define E_SUCCESS 0
+#define E_ERROR 1
+#define E_USAGE 2
+
+/*
+ * For hold times we use a global associative array since for mutexes, in
+ * user-land, it's not invalid to release a sychonization primitive that
+ * another thread acquired; rwlocks require a thread-local associative array
+ * since multiple thread can hold the same lock for reading. Note that we
+ * ignore recursive mutex acquisitions and releases as they don't truly
+ * affect lock contention.
+ */
+static const char *g_hold_init =
+"plockstat$target:::rw-acquire\n"
+"{\n"
+" self->rwhold[arg0] = timestamp;\n"
+"}\n"
+"plockstat$target:::mutex-acquire\n"
+"/arg1 == 0/\n"
+"{\n"
+" mtxhold[arg0] = timestamp;\n"
+"}\n";
+
+static const char *g_hold_histogram =
+"plockstat$target:::rw-release\n"
+"/self->rwhold[arg0] && arg1 == 1/\n"
+"{\n"
+" @rw_w_hold[arg0, ustack()] =\n"
+" quantize(timestamp - self->rwhold[arg0]);\n"
+" self->rwhold[arg0] = 0;\n"
+" rw_w_hold_found = 1;\n"
+"}\n"
+"plockstat$target:::rw-release\n"
+"/self->rwhold[arg0]/\n"
+"{\n"
+" @rw_r_hold[arg0, ustack()] =\n"
+" quantize(timestamp - self->rwhold[arg0]);\n"
+" self->rwhold[arg0] = 0;\n"
+" rw_r_hold_found = 1;\n"
+"}\n"
+"plockstat$target:::mutex-release\n"
+"/mtxhold[arg0] && arg1 == 0/\n"
+"{\n"
+" @mtx_hold[arg0, ustack()] = quantize(timestamp - mtxhold[arg0]);\n"
+" mtxhold[arg0] = 0;\n"
+" mtx_hold_found = 1;\n"
+"}\n"
+"\n"
+"END\n"
+"/mtx_hold_found/\n"
+"{\n"
+" trace(\"Mutex hold\");\n"
+" printa(@mtx_hold);\n"
+"}\n"
+"END\n"
+"/rw_r_hold_found/\n"
+"{\n"
+" trace(\"R/W reader hold\");\n"
+" printa(@rw_r_hold);\n"
+"}\n"
+"END\n"
+"/rw_w_hold_found/\n"
+"{\n"
+" trace(\"R/W writer hold\");\n"
+" printa(@rw_w_hold);\n"
+"}\n";
+
+static const char *g_hold_times =
+"plockstat$target:::rw-release\n"
+"/self->rwhold[arg0] && arg1 == 1/\n"
+"{\n"
+" @rw_w_hold[arg0, ustack(5)] = sum(timestamp - self->rwhold[arg0]);\n"
+" @rw_w_hold_count[arg0, ustack(5)] = count();\n"
+" self->rwhold[arg0] = 0;\n"
+" rw_w_hold_found = 1;\n"
+"}\n"
+"plockstat$target:::rw-release\n"
+"/self->rwhold[arg0]/\n"
+"{\n"
+" @rw_r_hold[arg0, ustack(5)] = sum(timestamp - self->rwhold[arg0]);\n"
+" @rw_r_hold_count[arg0, ustack(5)] = count();\n"
+" self->rwhold[arg0] = 0;\n"
+" rw_r_hold_found = 1;\n"
+"}\n"
+"plockstat$target:::mutex-release\n"
+"/mtxhold[arg0] && arg1 == 0/\n"
+"{\n"
+" @mtx_hold[arg0, ustack(5)] = sum(timestamp - mtxhold[arg0]);\n"
+" @mtx_hold_count[arg0, ustack(5)] = count();\n"
+" mtxhold[arg0] = 0;\n"
+" mtx_hold_found = 1;\n"
+"}\n"
+"\n"
+"END\n"
+"/mtx_hold_found/\n"
+"{\n"
+" trace(\"Mutex hold\");\n"
+" printa(@mtx_hold, @mtx_hold_count);\n"
+"}\n"
+"END\n"
+"/rw_r_hold_found/\n"
+"{\n"
+" trace(\"R/W reader hold\");\n"
+" printa(@rw_r_hold, @rw_r_hold_count);\n"
+"}\n"
+"END\n"
+"/rw_w_hold_found/\n"
+"{\n"
+" trace(\"R/W writer hold\");\n"
+" printa(@rw_w_hold, @rw_w_hold_count);\n"
+"}\n";
+
+
+/*
+ * For contention, we use thread-local associative arrays since we're tracing
+ * a single thread's activity in libc and multiple threads can be blocking or
+ * spinning on the same sychonization primitive.
+ */
+static const char *g_ctnd_init =
+"plockstat$target:::rw-block\n"
+"{\n"
+" self->rwblock[arg0] = timestamp;\n"
+"}\n"
+"plockstat$target:::mutex-block\n"
+"{\n"
+" self->mtxblock[arg0] = timestamp;\n"
+"}\n"
+"plockstat$target:::mutex-spin\n"
+"{\n"
+" self->mtxspin[arg0] = timestamp;\n"
+"}\n";
+
+static const char *g_ctnd_histogram =
+"plockstat$target:::rw-blocked\n"
+"/self->rwblock[arg0] && arg1 == 1 && arg2 != 0/\n"
+"{\n"
+" @rw_w_block[arg0, ustack()] =\n"
+" quantize(timestamp - self->rwblock[arg0]);\n"
+" self->rwblock[arg0] = 0;\n"
+" rw_w_block_found = 1;\n"
+"}\n"
+"plockstat$target:::rw-blocked\n"
+"/self->rwblock[arg0] && arg2 != 0/\n"
+"{\n"
+" @rw_r_block[arg0, ustack()] =\n"
+" quantize(timestamp - self->rwblock[arg0]);\n"
+" self->rwblock[arg0] = 0;\n"
+" rw_r_block_found = 1;\n"
+"}\n"
+"plockstat$target:::rw-blocked\n"
+"/self->rwblock[arg0]/\n"
+"{\n"
+" self->rwblock[arg0] = 0;\n"
+"}\n"
+"plockstat$target:::mutex-spun\n"
+"/self->mtxspin[arg0] && arg1 != 0/\n"
+"{\n"
+" @mtx_spin[arg0, ustack()] =\n"
+" quantize(timestamp - self->mtxspin[arg0]);\n"
+" self->mtxspin[arg0] = 0;\n"
+" mtx_spin_found = 1;\n"
+"}\n"
+"plockstat$target:::mutex-spun\n"
+"/self->mtxspin[arg0]/\n"
+"{\n"
+" @mtx_vain_spin[arg0, ustack()] =\n"
+" quantize(timestamp - self->mtxspin[arg0]);\n"
+" self->mtxspin[arg0] = 0;\n"
+" mtx_vain_spin_found = 1;\n"
+"}\n"
+"plockstat$target:::mutex-blocked\n"
+"/self->mtxblock[arg0] && arg1 != 0/\n"
+"{\n"
+" @mtx_block[arg0, ustack()] =\n"
+" quantize(timestamp - self->mtxblock[arg0]);\n"
+" self->mtxblock[arg0] = 0;\n"
+" mtx_block_found = 1;\n"
+"}\n"
+"plockstat$target:::mutex-blocked\n"
+"/self->mtxblock[arg0]/\n"
+"{\n"
+" self->mtxblock[arg0] = 0;\n"
+"}\n"
+"\n"
+"END\n"
+"/mtx_block_found/\n"
+"{\n"
+" trace(\"Mutex block\");\n"
+" printa(@mtx_block);\n"
+"}\n"
+"END\n"
+"/mtx_spin_found/\n"
+"{\n"
+" trace(\"Mutex spin\");\n"
+" printa(@mtx_spin);\n"
+"}\n"
+"END\n"
+"/mtx_vain_spin_found/\n"
+"{\n"
+" trace(\"Mutex unsuccessful spin\");\n"
+" printa(@mtx_vain_spin);\n"
+"}\n"
+"END\n"
+"/rw_r_block_found/\n"
+"{\n"
+" trace(\"R/W reader block\");\n"
+" printa(@rw_r_block);\n"
+"}\n"
+"END\n"
+"/rw_w_block_found/\n"
+"{\n"
+" trace(\"R/W writer block\");\n"
+" printa(@rw_w_block);\n"
+"}\n";
+
+
+static const char *g_ctnd_times =
+"plockstat$target:::rw-blocked\n"
+"/self->rwblock[arg0] && arg1 == 1 && arg2 != 0/\n"
+"{\n"
+" @rw_w_block[arg0, ustack(5)] =\n"
+" sum(timestamp - self->rwblock[arg0]);\n"
+" @rw_w_block_count[arg0, ustack(5)] = count();\n"
+" self->rwblock[arg0] = 0;\n"
+" rw_w_block_found = 1;\n"
+"}\n"
+"plockstat$target:::rw-blocked\n"
+"/self->rwblock[arg0] && arg2 != 0/\n"
+"{\n"
+" @rw_r_block[arg0, ustack(5)] =\n"
+" sum(timestamp - self->rwblock[arg0]);\n"
+" @rw_r_block_count[arg0, ustack(5)] = count();\n"
+" self->rwblock[arg0] = 0;\n"
+" rw_r_block_found = 1;\n"
+"}\n"
+"plockstat$target:::rw-blocked\n"
+"/self->rwblock[arg0]/\n"
+"{\n"
+" self->rwblock[arg0] = 0;\n"
+"}\n"
+"plockstat$target:::mutex-spun\n"
+"/self->mtxspin[arg0] && arg1 != 0/\n"
+"{\n"
+" @mtx_spin[arg0, ustack(5)] =\n"
+" sum(timestamp - self->mtxspin[arg0]);\n"
+" @mtx_spin_count[arg0, ustack(5)] = count();\n"
+" self->mtxspin[arg0] = 0;\n"
+" mtx_spin_found = 1;\n"
+"}\n"
+"plockstat$target:::mutex-spun\n"
+"/self->mtxspin[arg0]/\n"
+"{\n"
+" @mtx_vain_spin[arg0, ustack(5)] =\n"
+" sum(timestamp - self->mtxspin[arg0]);\n"
+" @mtx_vain_spin_count[arg0, ustack(5)] = count();\n"
+" self->mtxspin[arg0] = 0;\n"
+" mtx_vain_spin_found = 1;\n"
+"}\n"
+"plockstat$target:::mutex-blocked\n"
+"/self->mtxblock[arg0] && arg1 != 0/\n"
+"{\n"
+" @mtx_block[arg0, ustack(5)] =\n"
+" sum(timestamp - self->mtxblock[arg0]);\n"
+" @mtx_block_count[arg0, ustack(5)] = count();\n"
+" self->mtxblock[arg0] = 0;\n"
+" mtx_block_found = 1;\n"
+"}\n"
+"plockstat$target:::mutex-blocked\n"
+"/self->mtxblock[arg0]/\n"
+"{\n"
+" self->mtxblock[arg0] = 0;\n"
+"}\n"
+"\n"
+"END\n"
+"/mtx_block_found/\n"
+"{\n"
+" trace(\"Mutex block\");\n"
+" printa(@mtx_block, @mtx_block_count);\n"
+"}\n"
+"END\n"
+"/mtx_spin_found/\n"
+"{\n"
+" trace(\"Mutex spin\");\n"
+" printa(@mtx_spin, @mtx_spin_count);\n"
+"}\n"
+"END\n"
+"/mtx_vain_spin_found/\n"
+"{\n"
+" trace(\"Mutex unsuccessful spin\");\n"
+" printa(@mtx_vain_spin, @mtx_vain_spin_count);\n"
+"}\n"
+"END\n"
+"/rw_r_block_found/\n"
+"{\n"
+" trace(\"R/W reader block\");\n"
+" printa(@rw_r_block, @rw_r_block_count);\n"
+"}\n"
+"END\n"
+"/rw_w_block_found/\n"
+"{\n"
+" trace(\"R/W writer block\");\n"
+" printa(@rw_w_block, @rw_w_block_count);\n"
+"}\n";
+
+static char g_prog[4096];
+static size_t g_proglen;
+static int g_opt_V, g_opt_s;
+static int g_intr;
+static int g_exited;
+static dtrace_optval_t g_nframes;
+static ulong_t g_nent = ULONG_MAX;
+
+#define PLOCKSTAT_OPTSTR "n:ps:e:vx:ACHV"
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "Usage:\n"
+ "\t%s [-vACHV] [-n count] [-s depth] [-e secs] [-x opt[=val]]\n"
+ "\t command [arg...]\n"
+ "\t%s [-vACHV] [-n count] [-s depth] [-e secs] [-x opt[=val]]\n"
+ "\t -p pid\n", g_pname, g_pname);
+
+ exit(E_USAGE);
+}
+
+static void
+verror(const char *fmt, va_list ap)
+{
+ int error = errno;
+
+ (void) fprintf(stderr, "%s: ", g_pname);
+ (void) vfprintf(stderr, fmt, ap);
+
+ if (fmt[strlen(fmt) - 1] != '\n')
+ (void) fprintf(stderr, ": %s\n", strerror(error));
+}
+
+/*PRINTFLIKE1*/
+static void
+fatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ verror(fmt, ap);
+ va_end(ap);
+
+ if (g_pr != NULL && g_dtp != NULL)
+ dtrace_proc_release(g_dtp, g_pr);
+
+ exit(E_ERROR);
+}
+
+/*PRINTFLIKE1*/
+static void
+dfatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ (void) fprintf(stderr, "%s: ", g_pname);
+ if (fmt != NULL)
+ (void) vfprintf(stderr, fmt, ap);
+
+ va_end(ap);
+
+ if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') {
+ (void) fprintf(stderr, ": %s\n",
+ dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
+ } else if (fmt == NULL) {
+ (void) fprintf(stderr, "%s\n",
+ dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
+ }
+
+ if (g_pr != NULL) {
+ dtrace_proc_continue(g_dtp, g_pr);
+ dtrace_proc_release(g_dtp, g_pr);
+ }
+
+ exit(E_ERROR);
+}
+
+/*PRINTFLIKE1*/
+static void
+notice(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ verror(fmt, ap);
+ va_end(ap);
+}
+
+static void
+dprog_add(const char *prog)
+{
+ size_t len = strlen(prog);
+ bcopy(prog, g_prog + g_proglen, len + 1);
+ g_proglen += len;
+ assert(g_proglen < sizeof (g_prog));
+}
+
+static void
+dprog_compile(void)
+{
+ dtrace_prog_t *prog;
+ dtrace_proginfo_t info;
+
+ if (g_opt_V) {
+ (void) fprintf(stderr, "%s: vvvv D program vvvv\n", g_pname);
+ (void) fputs(g_prog, stderr);
+ (void) fprintf(stderr, "%s: ^^^^ D program ^^^^\n", g_pname);
+ }
+
+ if ((prog = dtrace_program_strcompile(g_dtp, g_prog,
+ DTRACE_PROBESPEC_NAME, 0, 0, NULL)) == NULL)
+ dfatal("failed to compile program");
+
+ if (dtrace_program_exec(g_dtp, prog, &info) == -1)
+ dfatal("failed to enable probes");
+}
+
+void
+print_legend(void)
+{
+ (void) printf("%5s %8s %-28s %s\n", "Count", "nsec", "Lock", "Caller");
+}
+
+void
+print_bar(void)
+{
+ (void) printf("---------------------------------------"
+ "----------------------------------------\n");
+}
+
+void
+print_histogram_header(void)
+{
+ (void) printf("\n%10s ---- Time Distribution --- %5s %s\n",
+ "nsec", "count", "Stack");
+}
+
+/*
+ * Convert an address to a symbolic string or a numeric string. If nolocks
+ * is set, we return an error code if this symbol appears to be a mutex- or
+ * rwlock-related symbol in libc so the caller has a chance to find a more
+ * helpful symbol.
+ */
+static int
+getsym(struct ps_prochandle *P, uintptr_t addr, char *buf, size_t size,
+ int nolocks)
+{
+ char name[256];
+ GElf_Sym sym;
+#ifdef illumos
+ prsyminfo_t info;
+#else
+ prmap_t *map;
+ int info; /* XXX unused */
+#endif
+ size_t len;
+
+ if (P == NULL || Pxlookup_by_addr(P, addr, name, sizeof (name),
+ &sym, &info) != 0) {
+ (void) snprintf(buf, size, "%#lx", (unsigned long)addr);
+ return (0);
+ }
+#ifdef illumos
+ if (info.prs_object == NULL)
+ info.prs_object = "<unknown>";
+
+ if (info.prs_lmid != LM_ID_BASE) {
+ len = snprintf(buf, size, "LM%lu`", info.prs_lmid);
+ buf += len;
+ size -= len;
+ }
+
+ len = snprintf(buf, size, "%s`%s", info.prs_object, info.prs_name);
+#else
+ map = proc_addr2map(P, addr);
+ len = snprintf(buf, size, "%s`%s", map->pr_mapname, name);
+#endif
+ buf += len;
+ size -= len;
+
+ if (sym.st_value != addr)
+ len = snprintf(buf, size, "+%#lx", (unsigned long)(addr - sym.st_value));
+
+ if (nolocks && strcmp("libc.so.1", map->pr_mapname) == 0 &&
+ (strstr("mutex", name) == 0 ||
+ strstr("rw", name) == 0))
+ return (-1);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+process_aggregate(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
+{
+ const dtrace_recdesc_t *rec;
+ uintptr_t lock;
+ uint64_t *stack;
+ caddr_t data;
+ pid_t pid;
+ struct ps_prochandle *P;
+ char buf[256];
+ int i, j;
+ uint64_t sum, count, avg;
+
+ if ((*(uint_t *)arg)++ >= g_nent)
+ return (DTRACE_AGGWALK_NEXT);
+
+ rec = aggsdata[0]->dtada_desc->dtagd_rec;
+ data = aggsdata[0]->dtada_data;
+
+ /*LINTED - alignment*/
+ lock = (uintptr_t)*(uint64_t *)(data + rec[1].dtrd_offset);
+ /*LINTED - alignment*/
+ stack = (uint64_t *)(data + rec[2].dtrd_offset);
+
+ if (!g_opt_s) {
+ /*LINTED - alignment*/
+ sum = *(uint64_t *)(aggsdata[1]->dtada_data +
+ aggsdata[1]->dtada_desc->dtagd_rec[3].dtrd_offset);
+ /*LINTED - alignment*/
+ count = *(uint64_t *)(aggsdata[2]->dtada_data +
+ aggsdata[2]->dtada_desc->dtagd_rec[3].dtrd_offset);
+ } else {
+ uint64_t *a;
+
+ /*LINTED - alignment*/
+ a = (uint64_t *)(aggsdata[1]->dtada_data +
+ aggsdata[1]->dtada_desc->dtagd_rec[3].dtrd_offset);
+
+ print_bar();
+ print_legend();
+
+ for (count = sum = 0, i = DTRACE_QUANTIZE_ZEROBUCKET, j = 0;
+ i < DTRACE_QUANTIZE_NBUCKETS; i++, j++) {
+ count += a[i];
+ sum += a[i] << (j - 64);
+ }
+ }
+
+ avg = sum / count;
+ (void) printf("%5llu %8llu ", (u_longlong_t)count, (u_longlong_t)avg);
+
+ pid = stack[0];
+ P = dtrace_proc_grab(g_dtp, pid, PGRAB_RDONLY);
+
+ (void) getsym(P, lock, buf, sizeof (buf), 0);
+ (void) printf("%-28s ", buf);
+
+ for (i = 2; i <= 5; i++) {
+ if (getsym(P, stack[i], buf, sizeof (buf), 1) == 0)
+ break;
+ }
+ (void) printf("%s\n", buf);
+
+ if (g_opt_s) {
+ int stack_done = 0;
+ int quant_done = 0;
+ int first_bin, last_bin;
+ uint64_t bin_size, *a;
+
+ /*LINTED - alignment*/
+ a = (uint64_t *)(aggsdata[1]->dtada_data +
+ aggsdata[1]->dtada_desc->dtagd_rec[3].dtrd_offset);
+
+ print_histogram_header();
+
+ for (first_bin = DTRACE_QUANTIZE_ZEROBUCKET;
+ a[first_bin] == 0; first_bin++)
+ continue;
+ for (last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 63;
+ a[last_bin] == 0; last_bin--)
+ continue;
+
+ for (i = 0; !stack_done || !quant_done; i++) {
+ if (!stack_done) {
+ (void) getsym(P, stack[i + 2], buf,
+ sizeof (buf), 0);
+ } else {
+ buf[0] = '\0';
+ }
+
+ if (!quant_done) {
+ bin_size = a[first_bin];
+
+ (void) printf("%10llu |%-24.*s| %5llu %s\n",
+ 1ULL <<
+ (first_bin - DTRACE_QUANTIZE_ZEROBUCKET),
+ (int)(24.0 * bin_size / count),
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@",
+ (u_longlong_t)bin_size, buf);
+ } else {
+ (void) printf("%43s %s\n", "", buf);
+ }
+
+ if (i + 1 >= g_nframes || stack[i + 3] == 0)
+ stack_done = 1;
+
+ if (first_bin++ == last_bin)
+ quant_done = 1;
+ }
+ }
+
+ dtrace_proc_release(g_dtp, P);
+
+ return (DTRACE_AGGWALK_NEXT);
+}
+
+/*ARGSUSED*/
+static void
+prochandler(struct ps_prochandle *P, const char *msg, void *arg)
+{
+#ifdef illumos
+ const psinfo_t *prp = Ppsinfo(P);
+ int pid = Pstatus(P)->pr_pid;
+#else
+ int pid = proc_getpid(P);
+ int wstat = proc_getwstat(P);
+#endif
+ char name[SIG2STR_MAX];
+
+ if (msg != NULL) {
+ notice("pid %d: %s\n", pid, msg);
+ return;
+ }
+
+ switch (Pstate(P)) {
+ case PS_UNDEAD:
+ /*
+ * Ideally we would like to always report pr_wstat here, but it
+ * isn't possible given current /proc semantics. If we grabbed
+ * the process, Ppsinfo() will either fail or return a zeroed
+ * psinfo_t depending on how far the parent is in reaping it.
+ * When /proc provides a stable pr_wstat in the status file,
+ * this code can be improved by examining this new pr_wstat.
+ */
+ if (WIFSIGNALED(wstat)) {
+ notice("pid %d terminated by %s\n", pid,
+ proc_signame(WTERMSIG(wstat),
+ name, sizeof (name)));
+ } else if (WEXITSTATUS(wstat) != 0) {
+ notice("pid %d exited with status %d\n",
+ pid, WEXITSTATUS(wstat));
+ } else {
+ notice("pid %d has exited\n", pid);
+ }
+ g_exited = 1;
+ break;
+
+ case PS_LOST:
+ notice("pid %d exec'd a set-id or unobservable program\n", pid);
+ g_exited = 1;
+ break;
+ }
+}
+
+/*ARGSUSED*/
+static int
+chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg)
+{
+ dtrace_eprobedesc_t *epd = data->dtpda_edesc;
+ dtrace_aggvarid_t aggvars[2];
+ const void *buf;
+ int i, nagv;
+
+ /*
+ * A NULL rec indicates that we've processed the last record.
+ */
+ if (rec == NULL)
+ return (DTRACE_CONSUME_NEXT);
+
+ buf = data->dtpda_data - rec->dtrd_offset;
+
+ switch (rec->dtrd_action) {
+ case DTRACEACT_DIFEXPR:
+ (void) printf("\n%s\n\n", (char *)buf + rec->dtrd_offset);
+ if (!g_opt_s) {
+ print_legend();
+ print_bar();
+ }
+ return (DTRACE_CONSUME_NEXT);
+
+ case DTRACEACT_PRINTA:
+ for (nagv = 0, i = 0; i < epd->dtepd_nrecs - 1; i++) {
+ const dtrace_recdesc_t *nrec = &rec[i];
+
+ if (nrec->dtrd_uarg != rec->dtrd_uarg)
+ break;
+
+ /*LINTED - alignment*/
+ aggvars[nagv++] = *(dtrace_aggvarid_t *)((caddr_t)buf +
+ nrec->dtrd_offset);
+ }
+
+ if (nagv == (g_opt_s ? 1 : 2)) {
+ uint_t nent = 0;
+ if (dtrace_aggregate_walk_joined(g_dtp, aggvars, nagv,
+ process_aggregate, &nent) != 0)
+ dfatal("failed to walk aggregate");
+ }
+
+ return (DTRACE_CONSUME_NEXT);
+ }
+
+ return (DTRACE_CONSUME_THIS);
+}
+
+/*ARGSUSED*/
+static void
+intr(int signo)
+{
+ g_intr = 1;
+}
+
+int
+main(int argc, char **argv)
+{
+#ifdef illumos
+ ucred_t *ucp;
+#endif
+ int err;
+ int opt_C = 0, opt_H = 0, opt_p = 0, opt_v = 0;
+ int c;
+ char *p, *end;
+ struct sigaction act;
+ int done = 0;
+
+ g_pname = basename(argv[0]);
+ argv[0] = g_pname; /* rewrite argv[0] for getopt errors */
+#ifdef illumos
+ /*
+ * Make sure we have the required dtrace_proc privilege.
+ */
+ if ((ucp = ucred_get(getpid())) != NULL) {
+ const priv_set_t *psp;
+ if ((psp = ucred_getprivset(ucp, PRIV_EFFECTIVE)) != NULL &&
+ !priv_ismember(psp, PRIV_DTRACE_PROC)) {
+ fatal("dtrace_proc privilege required\n");
+ }
+
+ ucred_free(ucp);
+ }
+#endif
+
+ while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) {
+ switch (c) {
+ case 'n':
+ errno = 0;
+ g_nent = strtoul(optarg, &end, 10);
+ if (*end != '\0' || errno != 0) {
+ (void) fprintf(stderr, "%s: invalid count "
+ "'%s'\n", g_pname, optarg);
+ usage();
+ }
+ break;
+
+ case 'p':
+ opt_p = 1;
+ break;
+
+ case 'v':
+ opt_v = 1;
+ break;
+
+ case 'A':
+ opt_C = opt_H = 1;
+ break;
+
+ case 'C':
+ opt_C = 1;
+ break;
+
+ case 'H':
+ opt_H = 1;
+ break;
+
+ case 'V':
+ g_opt_V = 1;
+ break;
+
+ default:
+ if (strchr(PLOCKSTAT_OPTSTR, c) == NULL)
+ usage();
+ }
+ }
+
+ /*
+ * We need a command or at least one pid.
+ */
+ if (argc == optind)
+ usage();
+
+ if (opt_C == 0 && opt_H == 0)
+ opt_C = 1;
+
+ if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL)
+ fatal("failed to initialize dtrace: %s\n",
+ dtrace_errmsg(NULL, err));
+
+ /*
+ * The longest string we trace is 23 bytes long -- so 32 is plenty.
+ */
+ if (dtrace_setopt(g_dtp, "strsize", "32") == -1)
+ dfatal("failed to set 'strsize'");
+
+ /*
+ * 1k should be more than enough for all trace() and printa() actions.
+ */
+ if (dtrace_setopt(g_dtp, "bufsize", "1k") == -1)
+ dfatal("failed to set 'bufsize'");
+
+ /*
+ * The table we produce has the hottest locks at the top.
+ */
+ if (dtrace_setopt(g_dtp, "aggsortrev", NULL) == -1)
+ dfatal("failed to set 'aggsortrev'");
+
+ /*
+ * These are two reasonable defaults which should suffice.
+ */
+ if (dtrace_setopt(g_dtp, "aggsize", "256k") == -1)
+ dfatal("failed to set 'aggsize'");
+ if (dtrace_setopt(g_dtp, "aggrate", "1sec") == -1)
+ dfatal("failed to set 'aggrate'");
+
+ /*
+ * Take a second pass through to look for options that set options now
+ * that we have an open dtrace handle.
+ */
+ optind = 1;
+ while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) {
+ switch (c) {
+ case 's':
+ g_opt_s = 1;
+ if (dtrace_setopt(g_dtp, "ustackframes", optarg) == -1)
+ dfatal("failed to set 'ustackframes'");
+ break;
+
+ case 'x':
+ if ((p = strchr(optarg, '=')) != NULL)
+ *p++ = '\0';
+
+ if (dtrace_setopt(g_dtp, optarg, p) != 0)
+ dfatal("failed to set -x %s", optarg);
+ break;
+
+ case 'e':
+ errno = 0;
+ (void) strtoul(optarg, &end, 10);
+ if (*optarg == '-' || *end != '\0' || errno != 0) {
+ (void) fprintf(stderr, "%s: invalid timeout "
+ "'%s'\n", g_pname, optarg);
+ usage();
+ }
+
+ /*
+ * Construct a DTrace enabling that will exit after
+ * the specified number of seconds.
+ */
+ dprog_add("BEGIN\n{\n\tend = timestamp + ");
+ dprog_add(optarg);
+ dprog_add(" * 1000000000;\n}\n");
+ dprog_add("tick-10hz\n/timestamp >= end/\n");
+ dprog_add("{\n\texit(0);\n}\n");
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (opt_H) {
+ dprog_add(g_hold_init);
+ if (!g_opt_s)
+ dprog_add(g_hold_times);
+ else
+ dprog_add(g_hold_histogram);
+ }
+
+ if (opt_C) {
+ dprog_add(g_ctnd_init);
+ if (!g_opt_s)
+ dprog_add(g_ctnd_times);
+ else
+ dprog_add(g_ctnd_histogram);
+ }
+
+ if (opt_p) {
+ ulong_t pid;
+
+ if (argc > 1) {
+ (void) fprintf(stderr, "%s: only one pid is allowed\n",
+ g_pname);
+ usage();
+ }
+
+ errno = 0;
+ pid = strtoul(argv[0], &end, 10);
+ if (*end != '\0' || errno != 0 || (pid_t)pid != pid) {
+ (void) fprintf(stderr, "%s: invalid pid '%s'\n",
+ g_pname, argv[0]);
+ usage();
+ }
+
+ if ((g_pr = dtrace_proc_grab(g_dtp, (pid_t)pid, 0)) == NULL)
+ dfatal(NULL);
+ } else {
+ if ((g_pr = dtrace_proc_create(g_dtp, argv[0], argv, NULL, NULL)) == NULL)
+ dfatal(NULL);
+ }
+
+ dprog_compile();
+
+ if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1)
+ dfatal("failed to establish proc handler");
+
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = intr;
+ (void) sigaction(SIGINT, &act, NULL);
+ (void) sigaction(SIGTERM, &act, NULL);
+
+ if (dtrace_go(g_dtp) != 0)
+ dfatal("dtrace_go()");
+
+ if (dtrace_getopt(g_dtp, "ustackframes", &g_nframes) != 0)
+ dfatal("failed to get 'ustackframes'");
+
+ dtrace_proc_continue(g_dtp, g_pr);
+
+ if (opt_v)
+ (void) printf("%s: tracing enabled for pid %d\n", g_pname,
+#ifdef illumos
+ (int)Pstatus(g_pr)->pr_pid);
+#else
+ (int)proc_getpid(g_pr));
+#endif
+
+ do {
+ if (!g_intr && !done)
+ dtrace_sleep(g_dtp);
+
+ if (done || g_intr || g_exited) {
+ done = 1;
+ if (dtrace_stop(g_dtp) == -1)
+ dfatal("couldn't stop tracing");
+ }
+
+ switch (dtrace_work(g_dtp, stdout, NULL, chewrec, NULL)) {
+ case DTRACE_WORKSTATUS_DONE:
+ done = 1;
+ break;
+ case DTRACE_WORKSTATUS_OKAY:
+ break;
+ default:
+ dfatal("processing aborted");
+ }
+
+ } while (!done);
+
+ dtrace_close(g_dtp);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/pyzfs/pyzfs.py b/cddl/contrib/opensolaris/cmd/pyzfs/pyzfs.py
new file mode 100644
index 000000000000..3867d91ccde5
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/pyzfs/pyzfs.py
@@ -0,0 +1,79 @@
+#! /usr/bin/python2.4 -S
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# Note, we want SIGINT (control-c) to exit the process quietly, to mimic
+# the standard behavior of C programs. The best we can do with pure
+# Python is to run with -S (to disable "import site"), and start our
+# program with a "try" statement. Hopefully nobody hits ^C before our
+# try statement is executed.
+
+try:
+ import site
+ import gettext
+ import zfs.util
+ import zfs.ioctl
+ import sys
+ import errno
+
+ """This is the main script for doing zfs subcommands. It doesn't know
+ what subcommands there are, it just looks for a module zfs.<subcommand>
+ that implements that subcommand."""
+
+ _ = gettext.translation("SUNW_OST_OSCMD", "/usr/lib/locale",
+ fallback=True).gettext
+
+ if len(sys.argv) < 2:
+ sys.exit(_("missing subcommand argument"))
+
+ zfs.ioctl.set_cmdstr(" ".join(["zfs"] + sys.argv[1:]))
+
+ try:
+ # import zfs.<subcommand>
+ # subfunc = zfs.<subcommand>.do_<subcommand>
+
+ subcmd = sys.argv[1]
+ __import__("zfs." + subcmd)
+ submod = getattr(zfs, subcmd)
+ subfunc = getattr(submod, "do_" + subcmd)
+ except (ImportError, AttributeError):
+ sys.exit(_("invalid subcommand"))
+
+ try:
+ subfunc()
+ except zfs.util.ZFSError, e:
+ print(e)
+ sys.exit(1)
+
+except IOError, e:
+ import errno
+ import sys
+
+ if e.errno == errno.EPIPE:
+ sys.exit(1)
+ raise
+except KeyboardInterrupt:
+ import sys
+
+ sys.exit(1)
diff --git a/cddl/contrib/opensolaris/cmd/stat/common/statcommon.h b/cddl/contrib/opensolaris/cmd/stat/common/statcommon.h
new file mode 100644
index 000000000000..f82495f22b5f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/stat/common/statcommon.h
@@ -0,0 +1,50 @@
+/*
+ * 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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Common routines for acquiring snapshots of kstats for
+ * iostat, mpstat, and vmstat.
+ */
+
+#ifndef _STATCOMMON_H
+#define _STATCOMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+
+#define NODATE 0 /* Default: No time stamp */
+#define DDATE 1 /* Standard date format */
+#define UDATE 2 /* Internal representation of Unix time */
+
+/* Print a timestamp in either Unix or standard format. */
+void print_timestamp(uint_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STATCOMMON_H */
diff --git a/cddl/contrib/opensolaris/cmd/stat/common/timestamp.c b/cddl/contrib/opensolaris/cmd/stat/common/timestamp.c
new file mode 100644
index 000000000000..be7b30c29fd0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/stat/common/timestamp.c
@@ -0,0 +1,49 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "statcommon.h"
+
+#include <langinfo.h>
+
+/*
+ * Print timestamp as decimal reprentation of time_t value (-T u was specified)
+ * or in date(1) format (-T d was specified).
+ */
+void
+print_timestamp(uint_t timestamp_fmt)
+{
+ time_t t = time(NULL);
+
+ if (timestamp_fmt == UDATE) {
+ (void) printf("%ld\n", t);
+ } else if (timestamp_fmt == DDATE) {
+ char dstr[64];
+ int len;
+
+ len = strftime(dstr, sizeof (dstr), "%+", localtime(&t));
+ if (len > 0)
+ (void) printf("%s\n", dstr);
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.8 b/cddl/contrib/opensolaris/cmd/zdb/zdb.8
new file mode 100644
index 000000000000..8561b972ac45
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.8
@@ -0,0 +1,409 @@
+.\"
+.\" This file and its contents are supplied under the terms of the
+.\" Common Development and Distribution License ("CDDL"), version 1.0.
+.\" You may only use this file in accordance with the terms of version
+.\" 1.0 of the CDDL.
+.\"
+.\" A full copy of the text of the CDDL should have accompanied this
+.\" source. A copy of the CDDL is also available via the Internet at
+.\" http://www.illumos.org/license/CDDL.
+.\"
+.\"
+.\" Copyright 2012, Richard Lowe.
+.\" Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+.\" Copyright 2017 Nexenta Systems, Inc.
+.\"
+.Dd October 06, 2017
+.Dt ZDB 8
+.Os
+.Sh NAME
+.Nm zdb
+.Nd display zpool debugging and consistency information
+.Sh SYNOPSIS
+.Nm
+.Op Fl AbcdDFGhikLMPsvX
+.Op Fl e Oo Fl V Oc Op Fl p Ar path ...
+.Op Fl I Ar inflight I/Os
+.Oo Fl o Ar var Ns = Ns Ar value Oc Ns ...
+.Op Fl t Ar txg
+.Op Fl U Ar cache
+.Op Fl x Ar dumpdir
+.Op Ar poolname Op Ar object ...
+.Nm
+.Op Fl AdiPv
+.Op Fl e Oo Fl V Oc Op Fl p Ar path ...
+.Op Fl U Ar cache
+.Ar dataset Op Ar object ...
+.Nm
+.Fl C
+.Op Fl A
+.Op Fl U Ar cache
+.Nm
+.Fl E
+.Op Fl A
+.Ar word0 Ns \&: Ns Ar word1 Ns :...: Ns Ar word15
+.Nm
+.Fl l
+.Op Fl Aqu
+.Ar device
+.Nm
+.Fl m
+.Op Fl AFLPX
+.Op Fl e Oo Fl V Oc Op Fl p Ar path ...
+.Op Fl t Ar txg
+.Op Fl U Ar cache
+.Ar poolname Op Ar vdev Op Ar metaslab ...
+.Nm
+.Fl O
+.Ar dataset path
+.Nm
+.Fl R
+.Op Fl A
+.Op Fl e Oo Fl V Oc Op Fl p Ar path ...
+.Op Fl U Ar cache
+.Ar poolname vdev Ns \&: Ns Ar offset Ns \&: Ns Ar size Ns Op : Ns Ar flags
+.Nm
+.Fl S
+.Op Fl AP
+.Op Fl e Oo Fl V Oc Op Fl p Ar path ...
+.Op Fl U Ar cache
+.Ar poolname
+.Sh DESCRIPTION
+The
+.Nm
+utility displays information about a ZFS pool useful for debugging and performs
+some amount of consistency checking.
+It is a not a general purpose tool and options
+.Pq and facilities
+may change.
+This is neither a
+.Xr fsck 8
+nor an
+.Xr fsdb 8
+utility.
+.Pp
+The output of this command in general reflects the on-disk structure of a ZFS
+pool, and is inherently unstable.
+The precise output of most invocations is not documented, a knowledge of ZFS
+internals is assumed.
+.Pp
+If the
+.Ar dataset
+argument does not contain any
+.Qq Sy /
+or
+.Qq Sy @
+characters, it is interpreted as a pool name.
+The root dataset can be specified as
+.Ar pool Ns /
+.Pq pool name followed by a slash .
+.Pp
+When operating on an imported and active pool it is possible, though unlikely,
+that zdb may interpret inconsistent pool data and behave erratically.
+.Sh OPTIONS
+Display options:
+.Bl -tag -width Ds
+.It Fl b
+Display statistics regarding the number, size
+.Pq logical, physical and allocated
+and deduplication of blocks.
+.It Fl c
+Verify the checksum of all metadata blocks while printing block statistics
+.Po see
+.Fl b
+.Pc .
+.Pp
+If specified multiple times, verify the checksums of all blocks.
+.It Fl C
+Display information about the configuration.
+If specified with no other options, instead display information about the cache
+file
+.Pq Pa /boot/zfs/zpool.cache .
+To specify the cache file to display, see
+.Fl U .
+.Pp
+If specified multiple times, and a pool name is also specified display both the
+cached configuration and the on-disk configuration.
+If specified multiple times with
+.Fl e
+also display the configuration that would be used were the pool to be imported.
+.It Fl d
+Display information about datasets.
+Specified once, displays basic dataset information: ID, create transaction,
+size, and object count.
+.Pp
+If specified multiple times provides greater and greater verbosity.
+.Pp
+If object IDs are specified, display information about those specific objects
+only.
+.It Fl D
+Display deduplication statistics, including the deduplication ratio
+.Pq Sy dedup ,
+compression ratio
+.Pq Sy compress ,
+inflation due to the zfs copies property
+.Pq Sy copies ,
+and an overall effective ratio
+.Pq Sy dedup No * Sy compress No / Sy copies .
+.It Fl DD
+Display a histogram of deduplication statistics, showing the allocated
+.Pq physically present on disk
+and referenced
+.Pq logically referenced in the pool
+block counts and sizes by reference count.
+.It Fl DDD
+Display the statistics independently for each deduplication table.
+.It Fl DDDD
+Dump the contents of the deduplication tables describing duplicate blocks.
+.It Fl DDDDD
+Also dump the contents of the deduplication tables describing unique blocks.
+.It Fl E Ar word0 Ns \&: Ns Ar word1 Ns :...: Ns Ar word15
+Decode and display block from an embedded block pointer specified by the
+.Ar word
+arguments.
+.It Fl h
+Display pool history similar to
+.Nm zpool Cm history ,
+but include internal changes, transaction, and dataset information.
+.It Fl i
+Display information about intent log
+.Pq ZIL
+entries relating to each dataset.
+If specified multiple times, display counts of each intent log transaction type.
+.It Fl k
+Examine the checkpointed state of the pool.
+Note, the on disk format of the pool is not reverted to the checkpointed state.
+.It Fl l Ar device
+Read the vdev labels from the specified device.
+.Nm Fl l
+will return 0 if valid label was found, 1 if error occurred, and 2 if no valid
+labels were found.
+.Pp
+If the
+.Fl q
+option is also specified, don't print the labels.
+.Pp
+If the
+.Fl u
+option is also specified, also display the uberblocks on this device.
+.It Fl L
+Disable leak tracing and the loading of space maps.
+By default,
+.Nm
+verifies that all non-free blocks are referenced, which can be very expensive.
+.It Fl m
+Display the offset, spacemap, and free space of each metaslab.
+.It Fl mm
+Also display information about the on-disk free space histogram associated with
+each metaslab.
+.It Fl mmm
+Display the maximum contiguous free space, the in-core free space histogram, and
+the percentage of free space in each space map.
+.It Fl mmmm
+Display every spacemap record.
+.It Fl M
+Display the offset, spacemap, and free space of each metaslab.
+.It Fl MM
+Also display information about the maximum contiguous free space and the
+percentage of free space in each space map.
+.It Fl MMM
+Display every spacemap record.
+.It Fl O Ar dataset path
+Look up the specified
+.Ar path
+inside of the
+.Ar dataset
+and display its metadata and indirect blocks.
+Specified
+.Ar path
+must be relative to the root of
+.Ar dataset .
+This option can be combined with
+.Fl v
+for increasing verbosity.
+.It Xo
+.Fl R Ar poolname vdev Ns \&: Ns Ar offset Ns \&: Ns Ar size Ns Op : Ns Ar flags
+.Xc
+Read and display a block from the specified device.
+By default the block is displayed as a hex dump, but see the description of the
+.Sy r
+flag, below.
+.Pp
+The block is specified in terms of a colon-separated tuple
+.Ar vdev
+.Pq an integer vdev identifier
+.Ar offset
+.Pq the offset within the vdev
+.Ar size
+.Pq the size of the block to read
+and, optionally,
+.Ar flags
+.Pq a set of flags, described below .
+.Pp
+.Bl -tag -compact -width "b offset"
+.It Sy b Ar offset
+Print block pointer
+.It Sy d
+Decompress the block
+.It Sy e
+Byte swap the block
+.It Sy g
+Dump gang block header
+.It Sy i
+Dump indirect block
+.It Sy r
+Dump raw uninterpreted block data
+.El
+.It Fl s
+Report statistics on
+.Nm zdb
+I/O.
+Display operation counts, bandwidth, and error counts of I/O to the pool from
+.Nm .
+.It Fl S
+Simulate the effects of deduplication, constructing a DDT and then display
+that DDT as with
+.Fl DD .
+.It Fl u
+Display the current uberblock.
+.El
+.Pp
+Other options:
+.Bl -tag -width Ds
+.It Fl A
+Do not abort should any assertion fail.
+.It Fl AA
+Enable panic recovery, certain errors which would otherwise be fatal are
+demoted to warnings.
+.It Fl AAA
+Do not abort if asserts fail and also enable panic recovery.
+.It Fl e Op Fl p Ar path ...
+Operate on an exported pool, not present in
+.Pa /boot/zfs/zpool.cache .
+The
+.Fl p
+flag specifies the path under which devices are to be searched.
+.It Fl x Ar dumpdir
+All blocks accessed will be copied to files in the specified directory.
+The blocks will be placed in sparse files whose name is the same as
+that of the file or device read.
+.Nm
+can be then run on the generated files.
+Note that the
+.Fl bbc
+flags are sufficient to access
+.Pq and thus copy
+all metadata on the pool.
+.It Fl F
+Attempt to make an unreadable pool readable by trying progressively older
+transactions.
+.It Fl G
+Dump the contents of the zfs_dbgmsg buffer before exiting
+.Nm .
+zfs_dbgmsg is a buffer used by ZFS to dump advanced debug information.
+.It Fl I Ar inflight I/Os
+Limit the number of outstanding checksum I/Os to the specified value.
+The default value is 200.
+This option affects the performance of the
+.Fl c
+option.
+.It Fl o Ar var Ns = Ns Ar value ...
+Set the given global libzpool variable to the provided value.
+The value must be an unsigned 32-bit integer.
+Currently only little-endian systems are supported to avoid accidentally setting
+the high 32 bits of 64-bit variables.
+.It Fl P
+Print numbers in an unscaled form more amenable to parsing, eg. 1000000 rather
+than 1M.
+.It Fl t Ar transaction
+Specify the highest transaction to use when searching for uberblocks.
+See also the
+.Fl u
+and
+.Fl l
+options for a means to see the available uberblocks and their associated
+transaction numbers.
+.It Fl U Ar cachefile
+Use a cache file other than
+.Pa /boot/zfs/zpool.cache .
+.It Fl v
+Enable verbosity.
+Specify multiple times for increased verbosity.
+.It Fl V
+Attempt verbatim import.
+This mimics the behavior of the kernel when loading a pool from a cachefile.
+Only usable with
+.Fl e .
+.It Fl X
+Attempt
+.Qq extreme
+transaction rewind, that is attempt the same recovery as
+.Fl F
+but read transactions otherwise deemed too old.
+.El
+.Pp
+Specifying a display option more than once enables verbosity for only that
+option, with more occurrences enabling more verbosity.
+.Pp
+If no options are specified, all information about the named pool will be
+displayed at default verbosity.
+.Sh EXAMPLES
+.Bl -tag -width Ds
+.It Xo
+.Sy Example 1
+Display the configuration of imported pool
+.Pa rpool
+.Xc
+.Bd -literal
+# zdb -C rpool
+
+MOS Configuration:
+ version: 28
+ name: 'rpool'
+ ...
+.Ed
+.It Xo
+.Sy Example 2
+Display basic dataset information about
+.Pa rpool
+.Xc
+.Bd -literal
+# zdb -d rpool
+Dataset mos [META], ID 0, cr_txg 4, 26.9M, 1051 objects
+Dataset rpool/swap [ZVOL], ID 59, cr_txg 356, 486M, 2 objects
+ ...
+.Ed
+.It Xo
+.Sy Example 3
+Display basic information about object 0 in
+.Pa rpool/export/home
+.Xc
+.Bd -literal
+# zdb -d rpool/export/home 0
+Dataset rpool/export/home [ZPL], ID 137, cr_txg 1546, 32K, 8 objects
+
+ Object lvl iblk dblk dsize lsize %full type
+ 0 7 16K 16K 15.0K 16K 25.00 DMU dnode
+.Ed
+.It Xo
+.Sy Example 4
+Display the predicted effect of enabling deduplication on
+.Pa rpool
+.Xc
+.Bd -literal
+# zdb -S rpool
+Simulated DDT histogram:
+
+bucket allocated referenced
+______ ______________________________ ______________________________
+refcnt blocks LSIZE PSIZE DSIZE blocks LSIZE PSIZE DSIZE
+------ ------ ----- ----- ----- ------ ----- ----- -----
+ 1 694K 27.1G 15.0G 15.0G 694K 27.1G 15.0G 15.0G
+ 2 35.0K 1.33G 699M 699M 74.7K 2.79G 1.45G 1.45G
+ ...
+dedup = 1.11, compress = 1.80, copies = 1.00, dedup * compress / copies = 2.00
+.Ed
+.El
+.Sh SEE ALSO
+.Xr zfs 8 ,
+.Xr zpool 8
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.c b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
new file mode 100644
index 000000000000..e3ee43a8661c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
@@ -0,0 +1,5734 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2017 Nexenta Systems, Inc.
+ * Copyright (c) 2017, 2018 Lawrence Livermore National Security, LLC.
+ * Copyright 2017 RackTop Systems.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/dmu.h>
+#include <sys/zap.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_sa.h>
+#include <sys/sa.h>
+#include <sys/sa_impl.h>
+#include <sys/vdev.h>
+#include <sys/vdev_impl.h>
+#include <sys/metaslab_impl.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_pool.h>
+#include <sys/dbuf.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/dmu_traverse.h>
+#include <sys/zio_checksum.h>
+#include <sys/zio_compress.h>
+#include <sys/zfs_fuid.h>
+#include <sys/arc.h>
+#include <sys/ddt.h>
+#include <sys/zfeature.h>
+#include <sys/abd.h>
+#include <sys/blkptr.h>
+#include <sys/dsl_scan.h>
+#include <zfs_comutil.h>
+#include <libcmdutils.h>
+#undef verify
+#include <libzfs.h>
+
+#include "zdb.h"
+
+#define ZDB_COMPRESS_NAME(idx) ((idx) < ZIO_COMPRESS_FUNCTIONS ? \
+ zio_compress_table[(idx)].ci_name : "UNKNOWN")
+#define ZDB_CHECKSUM_NAME(idx) ((idx) < ZIO_CHECKSUM_FUNCTIONS ? \
+ zio_checksum_table[(idx)].ci_name : "UNKNOWN")
+#define ZDB_OT_NAME(idx) ((idx) < DMU_OT_NUMTYPES ? \
+ dmu_ot[(idx)].ot_name : DMU_OT_IS_VALID(idx) ? \
+ dmu_ot_byteswap[DMU_OT_BYTESWAP(idx)].ob_name : "UNKNOWN")
+#define ZDB_OT_TYPE(idx) ((idx) < DMU_OT_NUMTYPES ? (idx) : \
+ (idx) == DMU_OTN_ZAP_DATA || (idx) == DMU_OTN_ZAP_METADATA ? \
+ DMU_OT_ZAP_OTHER : \
+ (idx) == DMU_OTN_UINT64_DATA || (idx) == DMU_OTN_UINT64_METADATA ? \
+ DMU_OT_UINT64_OTHER : DMU_OT_NUMTYPES)
+
+#ifndef lint
+extern int reference_tracking_enable;
+extern boolean_t zfs_recover;
+extern uint64_t zfs_arc_max, zfs_arc_meta_limit;
+extern int zfs_vdev_async_read_max_active;
+extern boolean_t spa_load_verify_dryrun;
+extern int aok;
+#else
+int reference_tracking_enable;
+boolean_t zfs_recover;
+uint64_t zfs_arc_max, zfs_arc_meta_limit;
+int zfs_vdev_async_read_max_active;
+boolean_t spa_load_verify_dryrun;
+int aok;
+#endif
+
+static const char cmdname[] = "zdb";
+uint8_t dump_opt[256];
+
+typedef void object_viewer_t(objset_t *, uint64_t, void *data, size_t size);
+
+static uint64_t *zopt_object = NULL;
+static unsigned zopt_objects = 0;
+static libzfs_handle_t *g_zfs;
+static uint64_t max_inflight = 1000;
+static int leaked_objects = 0;
+
+static void snprintf_blkptr_compact(char *, size_t, const blkptr_t *);
+static void mos_obj_refd(uint64_t);
+
+/*
+ * These libumem hooks provide a reasonable set of defaults for the allocator's
+ * debugging facilities.
+ */
+const char *
+_umem_debug_init()
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr,
+ "Usage:\t%s [-AbcdDFGhikLMPsvX] [-e [-V] [-p <path> ...]] "
+ "[-I <inflight I/Os>]\n"
+ "\t\t[-o <var>=<value>]... [-t <txg>] [-U <cache>] [-x <dumpdir>]\n"
+ "\t\t[<poolname> [<object> ...]]\n"
+ "\t%s [-AdiPv] [-e [-V] [-p <path> ...]] [-U <cache>] <dataset> "
+ "[<object> ...]\n"
+ "\t%s -C [-A] [-U <cache>]\n"
+ "\t%s -l [-Aqu] <device>\n"
+ "\t%s -m [-AFLPX] [-e [-V] [-p <path> ...]] [-t <txg>] "
+ "[-U <cache>]\n\t\t<poolname> [<vdev> [<metaslab> ...]]\n"
+ "\t%s -O <dataset> <path>\n"
+ "\t%s -R [-A] [-e [-V] [-p <path> ...]] [-U <cache>]\n"
+ "\t\t<poolname> <vdev>:<offset>:<size>[:<flags>]\n"
+ "\t%s -E [-A] word0:word1:...:word15\n"
+ "\t%s -S [-AP] [-e [-V] [-p <path> ...]] [-U <cache>] "
+ "<poolname>\n\n",
+ cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname,
+ cmdname, cmdname);
+
+ (void) fprintf(stderr, " Dataset name must include at least one "
+ "separator character '/' or '@'\n");
+ (void) fprintf(stderr, " If dataset name is specified, only that "
+ "dataset is dumped\n");
+ (void) fprintf(stderr, " If object numbers are specified, only "
+ "those objects are dumped\n\n");
+ (void) fprintf(stderr, " Options to control amount of output:\n");
+ (void) fprintf(stderr, " -b block statistics\n");
+ (void) fprintf(stderr, " -c checksum all metadata (twice for "
+ "all data) blocks\n");
+ (void) fprintf(stderr, " -C config (or cachefile if alone)\n");
+ (void) fprintf(stderr, " -d dataset(s)\n");
+ (void) fprintf(stderr, " -D dedup statistics\n");
+ (void) fprintf(stderr, " -E decode and display block from an "
+ "embedded block pointer\n");
+ (void) fprintf(stderr, " -h pool history\n");
+ (void) fprintf(stderr, " -i intent logs\n");
+ (void) fprintf(stderr, " -l read label contents\n");
+ (void) fprintf(stderr, " -k examine the checkpointed state "
+ "of the pool\n");
+ (void) fprintf(stderr, " -L disable leak tracking (do not "
+ "load spacemaps)\n");
+ (void) fprintf(stderr, " -m metaslabs\n");
+ (void) fprintf(stderr, " -M metaslab groups\n");
+ (void) fprintf(stderr, " -O perform object lookups by path\n");
+ (void) fprintf(stderr, " -R read and display block from a "
+ "device\n");
+ (void) fprintf(stderr, " -s report stats on zdb's I/O\n");
+ (void) fprintf(stderr, " -S simulate dedup to measure effect\n");
+ (void) fprintf(stderr, " -v verbose (applies to all "
+ "others)\n\n");
+ (void) fprintf(stderr, " Below options are intended for use "
+ "with other options:\n");
+ (void) fprintf(stderr, " -A ignore assertions (-A), enable "
+ "panic recovery (-AA) or both (-AAA)\n");
+ (void) fprintf(stderr, " -e pool is exported/destroyed/"
+ "has altroot/not in a cachefile\n");
+ (void) fprintf(stderr, " -F attempt automatic rewind within "
+ "safe range of transaction groups\n");
+ (void) fprintf(stderr, " -G dump zfs_dbgmsg buffer before "
+ "exiting\n");
+ (void) fprintf(stderr, " -I <number of inflight I/Os> -- "
+ "specify the maximum number of "
+ "checksumming I/Os [default is 200]\n");
+ (void) fprintf(stderr, " -o <variable>=<value> set global "
+ "variable to an unsigned 32-bit integer value\n");
+ (void) fprintf(stderr, " -p <path> -- use one or more with "
+ "-e to specify path to vdev dir\n");
+ (void) fprintf(stderr, " -P print numbers in parseable form\n");
+ (void) fprintf(stderr, " -q don't print label contents\n");
+ (void) fprintf(stderr, " -t <txg> -- highest txg to use when "
+ "searching for uberblocks\n");
+ (void) fprintf(stderr, " -u uberblock\n");
+ (void) fprintf(stderr, " -U <cachefile_path> -- use alternate "
+ "cachefile\n");
+ (void) fprintf(stderr, " -V do verbatim import\n");
+ (void) fprintf(stderr, " -x <dumpdir> -- "
+ "dump all read blocks into specified directory\n");
+ (void) fprintf(stderr, " -X attempt extreme rewind (does not "
+ "work with dataset)\n\n");
+ (void) fprintf(stderr, "Specify an option more than once (e.g. -bb) "
+ "to make only that option verbose\n");
+ (void) fprintf(stderr, "Default is to dump everything non-verbosely\n");
+ exit(1);
+}
+
+static void
+dump_debug_buffer()
+{
+ if (dump_opt['G']) {
+ (void) printf("\n");
+ zfs_dbgmsg_print("zdb");
+ }
+}
+
+/*
+ * Called for usage errors that are discovered after a call to spa_open(),
+ * dmu_bonus_hold(), or pool_match(). abort() is called for other errors.
+ */
+
+static void
+fatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void) fprintf(stderr, "%s: ", cmdname);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void) fprintf(stderr, "\n");
+
+ dump_debug_buffer();
+
+ exit(1);
+}
+
+/* ARGSUSED */
+static void
+dump_packed_nvlist(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ nvlist_t *nv;
+ size_t nvsize = *(uint64_t *)data;
+ char *packed = umem_alloc(nvsize, UMEM_NOFAIL);
+
+ VERIFY(0 == dmu_read(os, object, 0, nvsize, packed, DMU_READ_PREFETCH));
+
+ VERIFY(nvlist_unpack(packed, nvsize, &nv, 0) == 0);
+
+ umem_free(packed, nvsize);
+
+ dump_nvlist(nv, 8);
+
+ nvlist_free(nv);
+}
+
+/* ARGSUSED */
+static void
+dump_history_offsets(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ spa_history_phys_t *shp = data;
+
+ if (shp == NULL)
+ return;
+
+ (void) printf("\t\tpool_create_len = %llu\n",
+ (u_longlong_t)shp->sh_pool_create_len);
+ (void) printf("\t\tphys_max_off = %llu\n",
+ (u_longlong_t)shp->sh_phys_max_off);
+ (void) printf("\t\tbof = %llu\n",
+ (u_longlong_t)shp->sh_bof);
+ (void) printf("\t\teof = %llu\n",
+ (u_longlong_t)shp->sh_eof);
+ (void) printf("\t\trecords_lost = %llu\n",
+ (u_longlong_t)shp->sh_records_lost);
+}
+
+static void
+zdb_nicenum(uint64_t num, char *buf, size_t buflen)
+{
+ if (dump_opt['P'])
+ (void) snprintf(buf, buflen, "%llu", (longlong_t)num);
+ else
+ nicenum(num, buf, sizeof (buf));
+}
+
+static const char histo_stars[] = "****************************************";
+static const uint64_t histo_width = sizeof (histo_stars) - 1;
+
+static void
+dump_histogram(const uint64_t *histo, int size, int offset)
+{
+ int i;
+ int minidx = size - 1;
+ int maxidx = 0;
+ uint64_t max = 0;
+
+ for (i = 0; i < size; i++) {
+ if (histo[i] > max)
+ max = histo[i];
+ if (histo[i] > 0 && i > maxidx)
+ maxidx = i;
+ if (histo[i] > 0 && i < minidx)
+ minidx = i;
+ }
+
+ if (max < histo_width)
+ max = histo_width;
+
+ for (i = minidx; i <= maxidx; i++) {
+ (void) printf("\t\t\t%3u: %6llu %s\n",
+ i + offset, (u_longlong_t)histo[i],
+ &histo_stars[(max - histo[i]) * histo_width / max]);
+ }
+}
+
+static void
+dump_zap_stats(objset_t *os, uint64_t object)
+{
+ int error;
+ zap_stats_t zs;
+
+ error = zap_get_stats(os, object, &zs);
+ if (error)
+ return;
+
+ if (zs.zs_ptrtbl_len == 0) {
+ ASSERT(zs.zs_num_blocks == 1);
+ (void) printf("\tmicrozap: %llu bytes, %llu entries\n",
+ (u_longlong_t)zs.zs_blocksize,
+ (u_longlong_t)zs.zs_num_entries);
+ return;
+ }
+
+ (void) printf("\tFat ZAP stats:\n");
+
+ (void) printf("\t\tPointer table:\n");
+ (void) printf("\t\t\t%llu elements\n",
+ (u_longlong_t)zs.zs_ptrtbl_len);
+ (void) printf("\t\t\tzt_blk: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_zt_blk);
+ (void) printf("\t\t\tzt_numblks: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_zt_numblks);
+ (void) printf("\t\t\tzt_shift: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_zt_shift);
+ (void) printf("\t\t\tzt_blks_copied: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_blks_copied);
+ (void) printf("\t\t\tzt_nextblk: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_nextblk);
+
+ (void) printf("\t\tZAP entries: %llu\n",
+ (u_longlong_t)zs.zs_num_entries);
+ (void) printf("\t\tLeaf blocks: %llu\n",
+ (u_longlong_t)zs.zs_num_leafs);
+ (void) printf("\t\tTotal blocks: %llu\n",
+ (u_longlong_t)zs.zs_num_blocks);
+ (void) printf("\t\tzap_block_type: 0x%llx\n",
+ (u_longlong_t)zs.zs_block_type);
+ (void) printf("\t\tzap_magic: 0x%llx\n",
+ (u_longlong_t)zs.zs_magic);
+ (void) printf("\t\tzap_salt: 0x%llx\n",
+ (u_longlong_t)zs.zs_salt);
+
+ (void) printf("\t\tLeafs with 2^n pointers:\n");
+ dump_histogram(zs.zs_leafs_with_2n_pointers, ZAP_HISTOGRAM_SIZE, 0);
+
+ (void) printf("\t\tBlocks with n*5 entries:\n");
+ dump_histogram(zs.zs_blocks_with_n5_entries, ZAP_HISTOGRAM_SIZE, 0);
+
+ (void) printf("\t\tBlocks n/10 full:\n");
+ dump_histogram(zs.zs_blocks_n_tenths_full, ZAP_HISTOGRAM_SIZE, 0);
+
+ (void) printf("\t\tEntries with n chunks:\n");
+ dump_histogram(zs.zs_entries_using_n_chunks, ZAP_HISTOGRAM_SIZE, 0);
+
+ (void) printf("\t\tBuckets with n entries:\n");
+ dump_histogram(zs.zs_buckets_with_n_entries, ZAP_HISTOGRAM_SIZE, 0);
+}
+
+/*ARGSUSED*/
+static void
+dump_none(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_unknown(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ (void) printf("\tUNKNOWN OBJECT TYPE\n");
+}
+
+/*ARGSUSED*/
+static void
+dump_uint8(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_uint64(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_zap(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ zap_cursor_t zc;
+ zap_attribute_t attr;
+ void *prop;
+ unsigned i;
+
+ dump_zap_stats(os, object);
+ (void) printf("\n");
+
+ for (zap_cursor_init(&zc, os, object);
+ zap_cursor_retrieve(&zc, &attr) == 0;
+ zap_cursor_advance(&zc)) {
+ (void) printf("\t\t%s = ", attr.za_name);
+ if (attr.za_num_integers == 0) {
+ (void) printf("\n");
+ continue;
+ }
+ prop = umem_zalloc(attr.za_num_integers *
+ attr.za_integer_length, UMEM_NOFAIL);
+ (void) zap_lookup(os, object, attr.za_name,
+ attr.za_integer_length, attr.za_num_integers, prop);
+ if (attr.za_integer_length == 1) {
+ (void) printf("%s", (char *)prop);
+ } else {
+ for (i = 0; i < attr.za_num_integers; i++) {
+ switch (attr.za_integer_length) {
+ case 2:
+ (void) printf("%u ",
+ ((uint16_t *)prop)[i]);
+ break;
+ case 4:
+ (void) printf("%u ",
+ ((uint32_t *)prop)[i]);
+ break;
+ case 8:
+ (void) printf("%lld ",
+ (u_longlong_t)((int64_t *)prop)[i]);
+ break;
+ }
+ }
+ }
+ (void) printf("\n");
+ umem_free(prop, attr.za_num_integers * attr.za_integer_length);
+ }
+ zap_cursor_fini(&zc);
+}
+
+static void
+dump_bpobj(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ bpobj_phys_t *bpop = data;
+ char bytes[32], comp[32], uncomp[32];
+
+ /* make sure the output won't get truncated */
+ CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (uncomp) >= NN_NUMBUF_SZ);
+
+ if (bpop == NULL)
+ return;
+
+ zdb_nicenum(bpop->bpo_bytes, bytes, sizeof (bytes));
+ zdb_nicenum(bpop->bpo_comp, comp, sizeof (comp));
+ zdb_nicenum(bpop->bpo_uncomp, uncomp, sizeof (uncomp));
+
+ (void) printf("\t\tnum_blkptrs = %llu\n",
+ (u_longlong_t)bpop->bpo_num_blkptrs);
+ (void) printf("\t\tbytes = %s\n", bytes);
+ if (size >= BPOBJ_SIZE_V1) {
+ (void) printf("\t\tcomp = %s\n", comp);
+ (void) printf("\t\tuncomp = %s\n", uncomp);
+ }
+ if (size >= sizeof (*bpop)) {
+ (void) printf("\t\tsubobjs = %llu\n",
+ (u_longlong_t)bpop->bpo_subobjs);
+ (void) printf("\t\tnum_subobjs = %llu\n",
+ (u_longlong_t)bpop->bpo_num_subobjs);
+ }
+
+ if (dump_opt['d'] < 5)
+ return;
+
+ for (uint64_t i = 0; i < bpop->bpo_num_blkptrs; i++) {
+ char blkbuf[BP_SPRINTF_LEN];
+ blkptr_t bp;
+
+ int err = dmu_read(os, object,
+ i * sizeof (bp), sizeof (bp), &bp, 0);
+ if (err != 0) {
+ (void) printf("got error %u from dmu_read\n", err);
+ break;
+ }
+ snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), &bp);
+ (void) printf("\t%s\n", blkbuf);
+ }
+}
+
+/* ARGSUSED */
+static void
+dump_bpobj_subobjs(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ dmu_object_info_t doi;
+
+ VERIFY0(dmu_object_info(os, object, &doi));
+ uint64_t *subobjs = kmem_alloc(doi.doi_max_offset, KM_SLEEP);
+
+ int err = dmu_read(os, object, 0, doi.doi_max_offset, subobjs, 0);
+ if (err != 0) {
+ (void) printf("got error %u from dmu_read\n", err);
+ kmem_free(subobjs, doi.doi_max_offset);
+ return;
+ }
+
+ int64_t last_nonzero = -1;
+ for (uint64_t i = 0; i < doi.doi_max_offset / 8; i++) {
+ if (subobjs[i] != 0)
+ last_nonzero = i;
+ }
+
+ for (int64_t i = 0; i <= last_nonzero; i++) {
+ (void) printf("\t%llu\n", (longlong_t)subobjs[i]);
+ }
+ kmem_free(subobjs, doi.doi_max_offset);
+}
+
+/*ARGSUSED*/
+static void
+dump_ddt_zap(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ dump_zap_stats(os, object);
+ /* contents are printed elsewhere, properly decoded */
+}
+
+/*ARGSUSED*/
+static void
+dump_sa_attrs(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ zap_cursor_t zc;
+ zap_attribute_t attr;
+
+ dump_zap_stats(os, object);
+ (void) printf("\n");
+
+ for (zap_cursor_init(&zc, os, object);
+ zap_cursor_retrieve(&zc, &attr) == 0;
+ zap_cursor_advance(&zc)) {
+ (void) printf("\t\t%s = ", attr.za_name);
+ if (attr.za_num_integers == 0) {
+ (void) printf("\n");
+ continue;
+ }
+ (void) printf(" %llx : [%d:%d:%d]\n",
+ (u_longlong_t)attr.za_first_integer,
+ (int)ATTR_LENGTH(attr.za_first_integer),
+ (int)ATTR_BSWAP(attr.za_first_integer),
+ (int)ATTR_NUM(attr.za_first_integer));
+ }
+ zap_cursor_fini(&zc);
+}
+
+/*ARGSUSED*/
+static void
+dump_sa_layouts(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ zap_cursor_t zc;
+ zap_attribute_t attr;
+ uint16_t *layout_attrs;
+ unsigned i;
+
+ dump_zap_stats(os, object);
+ (void) printf("\n");
+
+ for (zap_cursor_init(&zc, os, object);
+ zap_cursor_retrieve(&zc, &attr) == 0;
+ zap_cursor_advance(&zc)) {
+ (void) printf("\t\t%s = [", attr.za_name);
+ if (attr.za_num_integers == 0) {
+ (void) printf("\n");
+ continue;
+ }
+
+ VERIFY(attr.za_integer_length == 2);
+ layout_attrs = umem_zalloc(attr.za_num_integers *
+ attr.za_integer_length, UMEM_NOFAIL);
+
+ VERIFY(zap_lookup(os, object, attr.za_name,
+ attr.za_integer_length,
+ attr.za_num_integers, layout_attrs) == 0);
+
+ for (i = 0; i != attr.za_num_integers; i++)
+ (void) printf(" %d ", (int)layout_attrs[i]);
+ (void) printf("]\n");
+ umem_free(layout_attrs,
+ attr.za_num_integers * attr.za_integer_length);
+ }
+ zap_cursor_fini(&zc);
+}
+
+/*ARGSUSED*/
+static void
+dump_zpldir(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ zap_cursor_t zc;
+ zap_attribute_t attr;
+ const char *typenames[] = {
+ /* 0 */ "not specified",
+ /* 1 */ "FIFO",
+ /* 2 */ "Character Device",
+ /* 3 */ "3 (invalid)",
+ /* 4 */ "Directory",
+ /* 5 */ "5 (invalid)",
+ /* 6 */ "Block Device",
+ /* 7 */ "7 (invalid)",
+ /* 8 */ "Regular File",
+ /* 9 */ "9 (invalid)",
+ /* 10 */ "Symbolic Link",
+ /* 11 */ "11 (invalid)",
+ /* 12 */ "Socket",
+ /* 13 */ "Door",
+ /* 14 */ "Event Port",
+ /* 15 */ "15 (invalid)",
+ };
+
+ dump_zap_stats(os, object);
+ (void) printf("\n");
+
+ for (zap_cursor_init(&zc, os, object);
+ zap_cursor_retrieve(&zc, &attr) == 0;
+ zap_cursor_advance(&zc)) {
+ (void) printf("\t\t%s = %lld (type: %s)\n",
+ attr.za_name, ZFS_DIRENT_OBJ(attr.za_first_integer),
+ typenames[ZFS_DIRENT_TYPE(attr.za_first_integer)]);
+ }
+ zap_cursor_fini(&zc);
+}
+
+static int
+get_dtl_refcount(vdev_t *vd)
+{
+ int refcount = 0;
+
+ if (vd->vdev_ops->vdev_op_leaf) {
+ space_map_t *sm = vd->vdev_dtl_sm;
+
+ if (sm != NULL &&
+ sm->sm_dbuf->db_size == sizeof (space_map_phys_t))
+ return (1);
+ return (0);
+ }
+
+ for (unsigned c = 0; c < vd->vdev_children; c++)
+ refcount += get_dtl_refcount(vd->vdev_child[c]);
+ return (refcount);
+}
+
+static int
+get_metaslab_refcount(vdev_t *vd)
+{
+ int refcount = 0;
+
+ if (vd->vdev_top == vd) {
+ for (uint64_t m = 0; m < vd->vdev_ms_count; m++) {
+ space_map_t *sm = vd->vdev_ms[m]->ms_sm;
+
+ if (sm != NULL &&
+ sm->sm_dbuf->db_size == sizeof (space_map_phys_t))
+ refcount++;
+ }
+ }
+ for (unsigned c = 0; c < vd->vdev_children; c++)
+ refcount += get_metaslab_refcount(vd->vdev_child[c]);
+
+ return (refcount);
+}
+
+static int
+get_obsolete_refcount(vdev_t *vd)
+{
+ int refcount = 0;
+
+ uint64_t obsolete_sm_obj = vdev_obsolete_sm_object(vd);
+ if (vd->vdev_top == vd && obsolete_sm_obj != 0) {
+ dmu_object_info_t doi;
+ VERIFY0(dmu_object_info(vd->vdev_spa->spa_meta_objset,
+ obsolete_sm_obj, &doi));
+ if (doi.doi_bonus_size == sizeof (space_map_phys_t)) {
+ refcount++;
+ }
+ } else {
+ ASSERT3P(vd->vdev_obsolete_sm, ==, NULL);
+ ASSERT3U(obsolete_sm_obj, ==, 0);
+ }
+ for (unsigned c = 0; c < vd->vdev_children; c++) {
+ refcount += get_obsolete_refcount(vd->vdev_child[c]);
+ }
+
+ return (refcount);
+}
+
+static int
+get_prev_obsolete_spacemap_refcount(spa_t *spa)
+{
+ uint64_t prev_obj =
+ spa->spa_condensing_indirect_phys.scip_prev_obsolete_sm_object;
+ if (prev_obj != 0) {
+ dmu_object_info_t doi;
+ VERIFY0(dmu_object_info(spa->spa_meta_objset, prev_obj, &doi));
+ if (doi.doi_bonus_size == sizeof (space_map_phys_t)) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static int
+get_checkpoint_refcount(vdev_t *vd)
+{
+ int refcount = 0;
+
+ if (vd->vdev_top == vd && vd->vdev_top_zap != 0 &&
+ zap_contains(spa_meta_objset(vd->vdev_spa),
+ vd->vdev_top_zap, VDEV_TOP_ZAP_POOL_CHECKPOINT_SM) == 0)
+ refcount++;
+
+ for (uint64_t c = 0; c < vd->vdev_children; c++)
+ refcount += get_checkpoint_refcount(vd->vdev_child[c]);
+
+ return (refcount);
+}
+
+static int
+verify_spacemap_refcounts(spa_t *spa)
+{
+ uint64_t expected_refcount = 0;
+ uint64_t actual_refcount;
+
+ (void) feature_get_refcount(spa,
+ &spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM],
+ &expected_refcount);
+ actual_refcount = get_dtl_refcount(spa->spa_root_vdev);
+ actual_refcount += get_metaslab_refcount(spa->spa_root_vdev);
+ actual_refcount += get_obsolete_refcount(spa->spa_root_vdev);
+ actual_refcount += get_prev_obsolete_spacemap_refcount(spa);
+ actual_refcount += get_checkpoint_refcount(spa->spa_root_vdev);
+
+ if (expected_refcount != actual_refcount) {
+ (void) printf("space map refcount mismatch: expected %lld != "
+ "actual %lld\n",
+ (longlong_t)expected_refcount,
+ (longlong_t)actual_refcount);
+ return (2);
+ }
+ return (0);
+}
+
+static void
+dump_spacemap(objset_t *os, space_map_t *sm)
+{
+ char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID",
+ "INVALID", "INVALID", "INVALID", "INVALID" };
+
+ if (sm == NULL)
+ return;
+
+ (void) printf("space map object %llu:\n",
+ (longlong_t)sm->sm_phys->smp_object);
+ (void) printf(" smp_objsize = 0x%llx\n",
+ (longlong_t)sm->sm_phys->smp_objsize);
+ (void) printf(" smp_alloc = 0x%llx\n",
+ (longlong_t)sm->sm_phys->smp_alloc);
+
+ /*
+ * Print out the freelist entries in both encoded and decoded form.
+ */
+ uint8_t mapshift = sm->sm_shift;
+ int64_t alloc = 0;
+ uint64_t word;
+ for (uint64_t offset = 0; offset < space_map_length(sm);
+ offset += sizeof (word)) {
+
+ VERIFY0(dmu_read(os, space_map_object(sm), offset,
+ sizeof (word), &word, DMU_READ_PREFETCH));
+
+ if (sm_entry_is_debug(word)) {
+ (void) printf("\t [%6llu] %s: txg %llu, pass %llu\n",
+ (u_longlong_t)(offset / sizeof (word)),
+ ddata[SM_DEBUG_ACTION_DECODE(word)],
+ (u_longlong_t)SM_DEBUG_TXG_DECODE(word),
+ (u_longlong_t)SM_DEBUG_SYNCPASS_DECODE(word));
+ continue;
+ }
+
+ uint8_t words;
+ char entry_type;
+ uint64_t entry_off, entry_run, entry_vdev = SM_NO_VDEVID;
+
+ if (sm_entry_is_single_word(word)) {
+ entry_type = (SM_TYPE_DECODE(word) == SM_ALLOC) ?
+ 'A' : 'F';
+ entry_off = (SM_OFFSET_DECODE(word) << mapshift) +
+ sm->sm_start;
+ entry_run = SM_RUN_DECODE(word) << mapshift;
+ words = 1;
+ } else {
+ /* it is a two-word entry so we read another word */
+ ASSERT(sm_entry_is_double_word(word));
+
+ uint64_t extra_word;
+ offset += sizeof (extra_word);
+ VERIFY0(dmu_read(os, space_map_object(sm), offset,
+ sizeof (extra_word), &extra_word,
+ DMU_READ_PREFETCH));
+
+ ASSERT3U(offset, <=, space_map_length(sm));
+
+ entry_run = SM2_RUN_DECODE(word) << mapshift;
+ entry_vdev = SM2_VDEV_DECODE(word);
+ entry_type = (SM2_TYPE_DECODE(extra_word) == SM_ALLOC) ?
+ 'A' : 'F';
+ entry_off = (SM2_OFFSET_DECODE(extra_word) <<
+ mapshift) + sm->sm_start;
+ words = 2;
+ }
+
+ (void) printf("\t [%6llu] %c range:"
+ " %010llx-%010llx size: %06llx vdev: %06llu words: %u\n",
+ (u_longlong_t)(offset / sizeof (word)),
+ entry_type, (u_longlong_t)entry_off,
+ (u_longlong_t)(entry_off + entry_run),
+ (u_longlong_t)entry_run,
+ (u_longlong_t)entry_vdev, words);
+
+ if (entry_type == 'A')
+ alloc += entry_run;
+ else
+ alloc -= entry_run;
+ }
+ if ((uint64_t)alloc != space_map_allocated(sm)) {
+ (void) printf("space_map_object alloc (%lld) INCONSISTENT "
+ "with space map summary (%lld)\n",
+ (longlong_t)space_map_allocated(sm), (longlong_t)alloc);
+ }
+}
+
+static void
+dump_metaslab_stats(metaslab_t *msp)
+{
+ char maxbuf[32];
+ range_tree_t *rt = msp->ms_allocatable;
+ avl_tree_t *t = &msp->ms_allocatable_by_size;
+ int free_pct = range_tree_space(rt) * 100 / msp->ms_size;
+
+ /* max sure nicenum has enough space */
+ CTASSERT(sizeof (maxbuf) >= NN_NUMBUF_SZ);
+
+ zdb_nicenum(metaslab_block_maxsize(msp), maxbuf, sizeof (maxbuf));
+
+ (void) printf("\t %25s %10lu %7s %6s %4s %4d%%\n",
+ "segments", avl_numnodes(t), "maxsize", maxbuf,
+ "freepct", free_pct);
+ (void) printf("\tIn-memory histogram:\n");
+ dump_histogram(rt->rt_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0);
+}
+
+static void
+dump_metaslab(metaslab_t *msp)
+{
+ vdev_t *vd = msp->ms_group->mg_vd;
+ spa_t *spa = vd->vdev_spa;
+ space_map_t *sm = msp->ms_sm;
+ char freebuf[32];
+
+ zdb_nicenum(msp->ms_size - space_map_allocated(sm), freebuf,
+ sizeof (freebuf));
+
+ (void) printf(
+ "\tmetaslab %6llu offset %12llx spacemap %6llu free %5s\n",
+ (u_longlong_t)msp->ms_id, (u_longlong_t)msp->ms_start,
+ (u_longlong_t)space_map_object(sm), freebuf);
+
+ if (dump_opt['m'] > 2 && !dump_opt['L']) {
+ mutex_enter(&msp->ms_lock);
+ VERIFY0(metaslab_load(msp));
+ range_tree_stat_verify(msp->ms_allocatable);
+ dump_metaslab_stats(msp);
+ metaslab_unload(msp);
+ mutex_exit(&msp->ms_lock);
+ }
+
+ if (dump_opt['m'] > 1 && sm != NULL &&
+ spa_feature_is_active(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
+ /*
+ * The space map histogram represents free space in chunks
+ * of sm_shift (i.e. bucket 0 refers to 2^sm_shift).
+ */
+ (void) printf("\tOn-disk histogram:\t\tfragmentation %llu\n",
+ (u_longlong_t)msp->ms_fragmentation);
+ dump_histogram(sm->sm_phys->smp_histogram,
+ SPACE_MAP_HISTOGRAM_SIZE, sm->sm_shift);
+ }
+
+ if (dump_opt['d'] > 5 || dump_opt['m'] > 3) {
+ ASSERT(msp->ms_size == (1ULL << vd->vdev_ms_shift));
+
+ dump_spacemap(spa->spa_meta_objset, msp->ms_sm);
+ }
+}
+
+static void
+print_vdev_metaslab_header(vdev_t *vd)
+{
+ vdev_alloc_bias_t alloc_bias = vd->vdev_alloc_bias;
+ const char *bias_str;
+
+ bias_str = (alloc_bias == VDEV_BIAS_LOG || vd->vdev_islog) ?
+ VDEV_ALLOC_BIAS_LOG :
+ (alloc_bias == VDEV_BIAS_SPECIAL) ? VDEV_ALLOC_BIAS_SPECIAL :
+ (alloc_bias == VDEV_BIAS_DEDUP) ? VDEV_ALLOC_BIAS_DEDUP :
+ vd->vdev_islog ? "log" : "";
+
+ (void) printf("\tvdev %10llu %s\n"
+ "\t%-10s%5llu %-19s %-15s %-12s\n",
+ (u_longlong_t)vd->vdev_id, bias_str,
+ "metaslabs", (u_longlong_t)vd->vdev_ms_count,
+ "offset", "spacemap", "free");
+ (void) printf("\t%15s %19s %15s %12s\n",
+ "---------------", "-------------------",
+ "---------------", "------------");
+}
+
+static void
+dump_metaslab_groups(spa_t *spa)
+{
+ vdev_t *rvd = spa->spa_root_vdev;
+ metaslab_class_t *mc = spa_normal_class(spa);
+ uint64_t fragmentation;
+
+ metaslab_class_histogram_verify(mc);
+
+ for (unsigned c = 0; c < rvd->vdev_children; c++) {
+ vdev_t *tvd = rvd->vdev_child[c];
+ metaslab_group_t *mg = tvd->vdev_mg;
+
+ if (mg == NULL || mg->mg_class != mc)
+ continue;
+
+ metaslab_group_histogram_verify(mg);
+ mg->mg_fragmentation = metaslab_group_fragmentation(mg);
+
+ (void) printf("\tvdev %10llu\t\tmetaslabs%5llu\t\t"
+ "fragmentation",
+ (u_longlong_t)tvd->vdev_id,
+ (u_longlong_t)tvd->vdev_ms_count);
+ if (mg->mg_fragmentation == ZFS_FRAG_INVALID) {
+ (void) printf("%3s\n", "-");
+ } else {
+ (void) printf("%3llu%%\n",
+ (u_longlong_t)mg->mg_fragmentation);
+ }
+ dump_histogram(mg->mg_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0);
+ }
+
+ (void) printf("\tpool %s\tfragmentation", spa_name(spa));
+ fragmentation = metaslab_class_fragmentation(mc);
+ if (fragmentation == ZFS_FRAG_INVALID)
+ (void) printf("\t%3s\n", "-");
+ else
+ (void) printf("\t%3llu%%\n", (u_longlong_t)fragmentation);
+ dump_histogram(mc->mc_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0);
+}
+
+static void
+print_vdev_indirect(vdev_t *vd)
+{
+ vdev_indirect_config_t *vic = &vd->vdev_indirect_config;
+ vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping;
+ vdev_indirect_births_t *vib = vd->vdev_indirect_births;
+
+ if (vim == NULL) {
+ ASSERT3P(vib, ==, NULL);
+ return;
+ }
+
+ ASSERT3U(vdev_indirect_mapping_object(vim), ==,
+ vic->vic_mapping_object);
+ ASSERT3U(vdev_indirect_births_object(vib), ==,
+ vic->vic_births_object);
+
+ (void) printf("indirect births obj %llu:\n",
+ (longlong_t)vic->vic_births_object);
+ (void) printf(" vib_count = %llu\n",
+ (longlong_t)vdev_indirect_births_count(vib));
+ for (uint64_t i = 0; i < vdev_indirect_births_count(vib); i++) {
+ vdev_indirect_birth_entry_phys_t *cur_vibe =
+ &vib->vib_entries[i];
+ (void) printf("\toffset %llx -> txg %llu\n",
+ (longlong_t)cur_vibe->vibe_offset,
+ (longlong_t)cur_vibe->vibe_phys_birth_txg);
+ }
+ (void) printf("\n");
+
+ (void) printf("indirect mapping obj %llu:\n",
+ (longlong_t)vic->vic_mapping_object);
+ (void) printf(" vim_max_offset = 0x%llx\n",
+ (longlong_t)vdev_indirect_mapping_max_offset(vim));
+ (void) printf(" vim_bytes_mapped = 0x%llx\n",
+ (longlong_t)vdev_indirect_mapping_bytes_mapped(vim));
+ (void) printf(" vim_count = %llu\n",
+ (longlong_t)vdev_indirect_mapping_num_entries(vim));
+
+ if (dump_opt['d'] <= 5 && dump_opt['m'] <= 3)
+ return;
+
+ uint32_t *counts = vdev_indirect_mapping_load_obsolete_counts(vim);
+
+ for (uint64_t i = 0; i < vdev_indirect_mapping_num_entries(vim); i++) {
+ vdev_indirect_mapping_entry_phys_t *vimep =
+ &vim->vim_entries[i];
+ (void) printf("\t<%llx:%llx:%llx> -> "
+ "<%llx:%llx:%llx> (%x obsolete)\n",
+ (longlong_t)vd->vdev_id,
+ (longlong_t)DVA_MAPPING_GET_SRC_OFFSET(vimep),
+ (longlong_t)DVA_GET_ASIZE(&vimep->vimep_dst),
+ (longlong_t)DVA_GET_VDEV(&vimep->vimep_dst),
+ (longlong_t)DVA_GET_OFFSET(&vimep->vimep_dst),
+ (longlong_t)DVA_GET_ASIZE(&vimep->vimep_dst),
+ counts[i]);
+ }
+ (void) printf("\n");
+
+ uint64_t obsolete_sm_object = vdev_obsolete_sm_object(vd);
+ if (obsolete_sm_object != 0) {
+ objset_t *mos = vd->vdev_spa->spa_meta_objset;
+ (void) printf("obsolete space map object %llu:\n",
+ (u_longlong_t)obsolete_sm_object);
+ ASSERT(vd->vdev_obsolete_sm != NULL);
+ ASSERT3U(space_map_object(vd->vdev_obsolete_sm), ==,
+ obsolete_sm_object);
+ dump_spacemap(mos, vd->vdev_obsolete_sm);
+ (void) printf("\n");
+ }
+}
+
+static void
+dump_metaslabs(spa_t *spa)
+{
+ vdev_t *vd, *rvd = spa->spa_root_vdev;
+ uint64_t m, c = 0, children = rvd->vdev_children;
+
+ (void) printf("\nMetaslabs:\n");
+
+ if (!dump_opt['d'] && zopt_objects > 0) {
+ c = zopt_object[0];
+
+ if (c >= children)
+ (void) fatal("bad vdev id: %llu", (u_longlong_t)c);
+
+ if (zopt_objects > 1) {
+ vd = rvd->vdev_child[c];
+ print_vdev_metaslab_header(vd);
+
+ for (m = 1; m < zopt_objects; m++) {
+ if (zopt_object[m] < vd->vdev_ms_count)
+ dump_metaslab(
+ vd->vdev_ms[zopt_object[m]]);
+ else
+ (void) fprintf(stderr, "bad metaslab "
+ "number %llu\n",
+ (u_longlong_t)zopt_object[m]);
+ }
+ (void) printf("\n");
+ return;
+ }
+ children = c + 1;
+ }
+ for (; c < children; c++) {
+ vd = rvd->vdev_child[c];
+ print_vdev_metaslab_header(vd);
+
+ print_vdev_indirect(vd);
+
+ for (m = 0; m < vd->vdev_ms_count; m++)
+ dump_metaslab(vd->vdev_ms[m]);
+ (void) printf("\n");
+ }
+}
+
+static void
+dump_dde(const ddt_t *ddt, const ddt_entry_t *dde, uint64_t index)
+{
+ const ddt_phys_t *ddp = dde->dde_phys;
+ const ddt_key_t *ddk = &dde->dde_key;
+ const char *types[4] = { "ditto", "single", "double", "triple" };
+ char blkbuf[BP_SPRINTF_LEN];
+ blkptr_t blk;
+
+ for (int p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+ if (ddp->ddp_phys_birth == 0)
+ continue;
+ ddt_bp_create(ddt->ddt_checksum, ddk, ddp, &blk);
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), &blk);
+ (void) printf("index %llx refcnt %llu %s %s\n",
+ (u_longlong_t)index, (u_longlong_t)ddp->ddp_refcnt,
+ types[p], blkbuf);
+ }
+}
+
+static void
+dump_dedup_ratio(const ddt_stat_t *dds)
+{
+ double rL, rP, rD, D, dedup, compress, copies;
+
+ if (dds->dds_blocks == 0)
+ return;
+
+ rL = (double)dds->dds_ref_lsize;
+ rP = (double)dds->dds_ref_psize;
+ rD = (double)dds->dds_ref_dsize;
+ D = (double)dds->dds_dsize;
+
+ dedup = rD / D;
+ compress = rL / rP;
+ copies = rD / rP;
+
+ (void) printf("dedup = %.2f, compress = %.2f, copies = %.2f, "
+ "dedup * compress / copies = %.2f\n\n",
+ dedup, compress, copies, dedup * compress / copies);
+}
+
+static void
+dump_ddt(ddt_t *ddt, enum ddt_type type, enum ddt_class class)
+{
+ char name[DDT_NAMELEN];
+ ddt_entry_t dde;
+ uint64_t walk = 0;
+ dmu_object_info_t doi;
+ uint64_t count, dspace, mspace;
+ int error;
+
+ error = ddt_object_info(ddt, type, class, &doi);
+
+ if (error == ENOENT)
+ return;
+ ASSERT(error == 0);
+
+ error = ddt_object_count(ddt, type, class, &count);
+ ASSERT(error == 0);
+ if (count == 0)
+ return;
+
+ dspace = doi.doi_physical_blocks_512 << 9;
+ mspace = doi.doi_fill_count * doi.doi_data_block_size;
+
+ ddt_object_name(ddt, type, class, name);
+
+ (void) printf("%s: %llu entries, size %llu on disk, %llu in core\n",
+ name,
+ (u_longlong_t)count,
+ (u_longlong_t)(dspace / count),
+ (u_longlong_t)(mspace / count));
+
+ if (dump_opt['D'] < 3)
+ return;
+
+ zpool_dump_ddt(NULL, &ddt->ddt_histogram[type][class]);
+
+ if (dump_opt['D'] < 4)
+ return;
+
+ if (dump_opt['D'] < 5 && class == DDT_CLASS_UNIQUE)
+ return;
+
+ (void) printf("%s contents:\n\n", name);
+
+ while ((error = ddt_object_walk(ddt, type, class, &walk, &dde)) == 0)
+ dump_dde(ddt, &dde, walk);
+
+ ASSERT3U(error, ==, ENOENT);
+
+ (void) printf("\n");
+}
+
+static void
+dump_all_ddts(spa_t *spa)
+{
+ ddt_histogram_t ddh_total;
+ ddt_stat_t dds_total;
+
+ bzero(&ddh_total, sizeof (ddh_total));
+ bzero(&dds_total, sizeof (dds_total));
+
+ for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
+ ddt_t *ddt = spa->spa_ddt[c];
+ for (enum ddt_type type = 0; type < DDT_TYPES; type++) {
+ for (enum ddt_class class = 0; class < DDT_CLASSES;
+ class++) {
+ dump_ddt(ddt, type, class);
+ }
+ }
+ }
+
+ ddt_get_dedup_stats(spa, &dds_total);
+
+ if (dds_total.dds_blocks == 0) {
+ (void) printf("All DDTs are empty\n");
+ return;
+ }
+
+ (void) printf("\n");
+
+ if (dump_opt['D'] > 1) {
+ (void) printf("DDT histogram (aggregated over all DDTs):\n");
+ ddt_get_dedup_histogram(spa, &ddh_total);
+ zpool_dump_ddt(&dds_total, &ddh_total);
+ }
+
+ dump_dedup_ratio(&dds_total);
+}
+
+static void
+dump_dtl_seg(void *arg, uint64_t start, uint64_t size)
+{
+ char *prefix = arg;
+
+ (void) printf("%s [%llu,%llu) length %llu\n",
+ prefix,
+ (u_longlong_t)start,
+ (u_longlong_t)(start + size),
+ (u_longlong_t)(size));
+}
+
+static void
+dump_dtl(vdev_t *vd, int indent)
+{
+ spa_t *spa = vd->vdev_spa;
+ boolean_t required;
+ const char *name[DTL_TYPES] = { "missing", "partial", "scrub",
+ "outage" };
+ char prefix[256];
+
+ spa_vdev_state_enter(spa, SCL_NONE);
+ required = vdev_dtl_required(vd);
+ (void) spa_vdev_state_exit(spa, NULL, 0);
+
+ if (indent == 0)
+ (void) printf("\nDirty time logs:\n\n");
+
+ (void) printf("\t%*s%s [%s]\n", indent, "",
+ vd->vdev_path ? vd->vdev_path :
+ vd->vdev_parent ? vd->vdev_ops->vdev_op_type : spa_name(spa),
+ required ? "DTL-required" : "DTL-expendable");
+
+ for (int t = 0; t < DTL_TYPES; t++) {
+ range_tree_t *rt = vd->vdev_dtl[t];
+ if (range_tree_space(rt) == 0)
+ continue;
+ (void) snprintf(prefix, sizeof (prefix), "\t%*s%s",
+ indent + 2, "", name[t]);
+ range_tree_walk(rt, dump_dtl_seg, prefix);
+ if (dump_opt['d'] > 5 && vd->vdev_children == 0)
+ dump_spacemap(spa->spa_meta_objset, vd->vdev_dtl_sm);
+ }
+
+ for (unsigned c = 0; c < vd->vdev_children; c++)
+ dump_dtl(vd->vdev_child[c], indent + 4);
+}
+
+/* from spa_history.c: spa_history_create_obj() */
+#define HIS_BUF_LEN_DEF (128 << 10)
+#define HIS_BUF_LEN_MAX (1 << 30)
+
+static void
+dump_history(spa_t *spa)
+{
+ nvlist_t **events = NULL;
+ char *buf = NULL;
+ uint64_t bufsize = HIS_BUF_LEN_DEF;
+ uint64_t resid, len, off = 0;
+ uint_t num = 0;
+ int error;
+ time_t tsec;
+ struct tm t;
+ char tbuf[30];
+ char internalstr[MAXPATHLEN];
+
+ if ((buf = malloc(bufsize)) == NULL)
+ (void) fprintf(stderr, "Unable to read history: "
+ "out of memory\n");
+ do {
+ len = bufsize;
+
+ if ((error = spa_history_get(spa, &off, &len, buf)) != 0) {
+ (void) fprintf(stderr, "Unable to read history: "
+ "error %d\n", error);
+ return;
+ }
+
+ if (zpool_history_unpack(buf, len, &resid, &events, &num) != 0)
+ break;
+ off -= resid;
+
+ /*
+ * If the history block is too big, double the buffer
+ * size and try again.
+ */
+ if (resid == len) {
+ free(buf);
+ buf = NULL;
+
+ bufsize <<= 1;
+ if ((bufsize >= HIS_BUF_LEN_MAX) ||
+ ((buf = malloc(bufsize)) == NULL)) {
+ (void) fprintf(stderr, "Unable to read history: "
+ "out of memory\n");
+ return;
+ }
+ }
+ } while (len != 0);
+ free(buf);
+
+ (void) printf("\nHistory:\n");
+ for (unsigned i = 0; i < num; i++) {
+ uint64_t time, txg, ievent;
+ char *cmd, *intstr;
+ boolean_t printed = B_FALSE;
+
+ if (nvlist_lookup_uint64(events[i], ZPOOL_HIST_TIME,
+ &time) != 0)
+ goto next;
+ if (nvlist_lookup_string(events[i], ZPOOL_HIST_CMD,
+ &cmd) != 0) {
+ if (nvlist_lookup_uint64(events[i],
+ ZPOOL_HIST_INT_EVENT, &ievent) != 0)
+ goto next;
+ verify(nvlist_lookup_uint64(events[i],
+ ZPOOL_HIST_TXG, &txg) == 0);
+ verify(nvlist_lookup_string(events[i],
+ ZPOOL_HIST_INT_STR, &intstr) == 0);
+ if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS)
+ goto next;
+
+ (void) snprintf(internalstr,
+ sizeof (internalstr),
+ "[internal %s txg:%ju] %s",
+ zfs_history_event_names[ievent], (uintmax_t)txg,
+ intstr);
+ cmd = internalstr;
+ }
+ tsec = time;
+ (void) localtime_r(&tsec, &t);
+ (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
+ (void) printf("%s %s\n", tbuf, cmd);
+ printed = B_TRUE;
+
+next:
+ if (dump_opt['h'] > 1) {
+ if (!printed)
+ (void) printf("unrecognized record:\n");
+ dump_nvlist(events[i], 2);
+ }
+ }
+}
+
+/*ARGSUSED*/
+static void
+dump_dnode(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+static uint64_t
+blkid2offset(const dnode_phys_t *dnp, const blkptr_t *bp,
+ const zbookmark_phys_t *zb)
+{
+ if (dnp == NULL) {
+ ASSERT(zb->zb_level < 0);
+ if (zb->zb_object == 0)
+ return (zb->zb_blkid);
+ return (zb->zb_blkid * BP_GET_LSIZE(bp));
+ }
+
+ ASSERT(zb->zb_level >= 0);
+
+ return ((zb->zb_blkid <<
+ (zb->zb_level * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) *
+ dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT);
+}
+
+static void
+snprintf_blkptr_compact(char *blkbuf, size_t buflen, const blkptr_t *bp)
+{
+ const dva_t *dva = bp->blk_dva;
+ int ndvas = dump_opt['d'] > 5 ? BP_GET_NDVAS(bp) : 1;
+
+ if (dump_opt['b'] >= 6) {
+ snprintf_blkptr(blkbuf, buflen, bp);
+ return;
+ }
+
+ if (BP_IS_EMBEDDED(bp)) {
+ (void) sprintf(blkbuf,
+ "EMBEDDED et=%u %llxL/%llxP B=%llu",
+ (int)BPE_GET_ETYPE(bp),
+ (u_longlong_t)BPE_GET_LSIZE(bp),
+ (u_longlong_t)BPE_GET_PSIZE(bp),
+ (u_longlong_t)bp->blk_birth);
+ return;
+ }
+
+ blkbuf[0] = '\0';
+ for (int i = 0; i < ndvas; i++)
+ (void) snprintf(blkbuf + strlen(blkbuf),
+ buflen - strlen(blkbuf), "%llu:%llx:%llx ",
+ (u_longlong_t)DVA_GET_VDEV(&dva[i]),
+ (u_longlong_t)DVA_GET_OFFSET(&dva[i]),
+ (u_longlong_t)DVA_GET_ASIZE(&dva[i]));
+
+ if (BP_IS_HOLE(bp)) {
+ (void) snprintf(blkbuf + strlen(blkbuf),
+ buflen - strlen(blkbuf),
+ "%llxL B=%llu",
+ (u_longlong_t)BP_GET_LSIZE(bp),
+ (u_longlong_t)bp->blk_birth);
+ } else {
+ (void) snprintf(blkbuf + strlen(blkbuf),
+ buflen - strlen(blkbuf),
+ "%llxL/%llxP F=%llu B=%llu/%llu",
+ (u_longlong_t)BP_GET_LSIZE(bp),
+ (u_longlong_t)BP_GET_PSIZE(bp),
+ (u_longlong_t)BP_GET_FILL(bp),
+ (u_longlong_t)bp->blk_birth,
+ (u_longlong_t)BP_PHYSICAL_BIRTH(bp));
+ }
+}
+
+static void
+print_indirect(blkptr_t *bp, const zbookmark_phys_t *zb,
+ const dnode_phys_t *dnp)
+{
+ char blkbuf[BP_SPRINTF_LEN];
+ int l;
+
+ if (!BP_IS_EMBEDDED(bp)) {
+ ASSERT3U(BP_GET_TYPE(bp), ==, dnp->dn_type);
+ ASSERT3U(BP_GET_LEVEL(bp), ==, zb->zb_level);
+ }
+
+ (void) printf("%16llx ", (u_longlong_t)blkid2offset(dnp, bp, zb));
+
+ ASSERT(zb->zb_level >= 0);
+
+ for (l = dnp->dn_nlevels - 1; l >= -1; l--) {
+ if (l == zb->zb_level) {
+ (void) printf("L%llx", (u_longlong_t)zb->zb_level);
+ } else {
+ (void) printf(" ");
+ }
+ }
+
+ snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp);
+ (void) printf("%s\n", blkbuf);
+}
+
+static int
+visit_indirect(spa_t *spa, const dnode_phys_t *dnp,
+ blkptr_t *bp, const zbookmark_phys_t *zb)
+{
+ int err = 0;
+
+ if (bp->blk_birth == 0)
+ return (0);
+
+ print_indirect(bp, zb, dnp);
+
+ if (BP_GET_LEVEL(bp) > 0 && !BP_IS_HOLE(bp)) {
+ arc_flags_t flags = ARC_FLAG_WAIT;
+ int i;
+ blkptr_t *cbp;
+ int epb = BP_GET_LSIZE(bp) >> SPA_BLKPTRSHIFT;
+ arc_buf_t *buf;
+ uint64_t fill = 0;
+
+ err = arc_read(NULL, spa, bp, arc_getbuf_func, &buf,
+ ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
+ if (err)
+ return (err);
+ ASSERT(buf->b_data);
+
+ /* recursively visit blocks below this */
+ cbp = buf->b_data;
+ for (i = 0; i < epb; i++, cbp++) {
+ zbookmark_phys_t czb;
+
+ SET_BOOKMARK(&czb, zb->zb_objset, zb->zb_object,
+ zb->zb_level - 1,
+ zb->zb_blkid * epb + i);
+ err = visit_indirect(spa, dnp, cbp, &czb);
+ if (err)
+ break;
+ fill += BP_GET_FILL(cbp);
+ }
+ if (!err)
+ ASSERT3U(fill, ==, BP_GET_FILL(bp));
+ arc_buf_destroy(buf, &buf);
+ }
+
+ return (err);
+}
+
+/*ARGSUSED*/
+static void
+dump_indirect(dnode_t *dn)
+{
+ dnode_phys_t *dnp = dn->dn_phys;
+ int j;
+ zbookmark_phys_t czb;
+
+ (void) printf("Indirect blocks:\n");
+
+ SET_BOOKMARK(&czb, dmu_objset_id(dn->dn_objset),
+ dn->dn_object, dnp->dn_nlevels - 1, 0);
+ for (j = 0; j < dnp->dn_nblkptr; j++) {
+ czb.zb_blkid = j;
+ (void) visit_indirect(dmu_objset_spa(dn->dn_objset), dnp,
+ &dnp->dn_blkptr[j], &czb);
+ }
+
+ (void) printf("\n");
+}
+
+/*ARGSUSED*/
+static void
+dump_dsl_dir(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ dsl_dir_phys_t *dd = data;
+ time_t crtime;
+ char nice[32];
+
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (nice) >= NN_NUMBUF_SZ);
+
+ if (dd == NULL)
+ return;
+
+ ASSERT3U(size, >=, sizeof (dsl_dir_phys_t));
+
+ crtime = dd->dd_creation_time;
+ (void) printf("\t\tcreation_time = %s", ctime(&crtime));
+ (void) printf("\t\thead_dataset_obj = %llu\n",
+ (u_longlong_t)dd->dd_head_dataset_obj);
+ (void) printf("\t\tparent_dir_obj = %llu\n",
+ (u_longlong_t)dd->dd_parent_obj);
+ (void) printf("\t\torigin_obj = %llu\n",
+ (u_longlong_t)dd->dd_origin_obj);
+ (void) printf("\t\tchild_dir_zapobj = %llu\n",
+ (u_longlong_t)dd->dd_child_dir_zapobj);
+ zdb_nicenum(dd->dd_used_bytes, nice, sizeof (nice));
+ (void) printf("\t\tused_bytes = %s\n", nice);
+ zdb_nicenum(dd->dd_compressed_bytes, nice, sizeof (nice));
+ (void) printf("\t\tcompressed_bytes = %s\n", nice);
+ zdb_nicenum(dd->dd_uncompressed_bytes, nice, sizeof (nice));
+ (void) printf("\t\tuncompressed_bytes = %s\n", nice);
+ zdb_nicenum(dd->dd_quota, nice, sizeof (nice));
+ (void) printf("\t\tquota = %s\n", nice);
+ zdb_nicenum(dd->dd_reserved, nice, sizeof (nice));
+ (void) printf("\t\treserved = %s\n", nice);
+ (void) printf("\t\tprops_zapobj = %llu\n",
+ (u_longlong_t)dd->dd_props_zapobj);
+ (void) printf("\t\tdeleg_zapobj = %llu\n",
+ (u_longlong_t)dd->dd_deleg_zapobj);
+ (void) printf("\t\tflags = %llx\n",
+ (u_longlong_t)dd->dd_flags);
+
+#define DO(which) \
+ zdb_nicenum(dd->dd_used_breakdown[DD_USED_ ## which], nice, \
+ sizeof (nice)); \
+ (void) printf("\t\tused_breakdown[" #which "] = %s\n", nice)
+ DO(HEAD);
+ DO(SNAP);
+ DO(CHILD);
+ DO(CHILD_RSRV);
+ DO(REFRSRV);
+#undef DO
+ (void) printf("\t\tclones = %llu\n",
+ (u_longlong_t)dd->dd_clones);
+}
+
+/*ARGSUSED*/
+static void
+dump_dsl_dataset(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ dsl_dataset_phys_t *ds = data;
+ time_t crtime;
+ char used[32], compressed[32], uncompressed[32], unique[32];
+ char blkbuf[BP_SPRINTF_LEN];
+
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (used) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (compressed) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (uncompressed) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (unique) >= NN_NUMBUF_SZ);
+
+ if (ds == NULL)
+ return;
+
+ ASSERT(size == sizeof (*ds));
+ crtime = ds->ds_creation_time;
+ zdb_nicenum(ds->ds_referenced_bytes, used, sizeof (used));
+ zdb_nicenum(ds->ds_compressed_bytes, compressed, sizeof (compressed));
+ zdb_nicenum(ds->ds_uncompressed_bytes, uncompressed,
+ sizeof (uncompressed));
+ zdb_nicenum(ds->ds_unique_bytes, unique, sizeof (unique));
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), &ds->ds_bp);
+
+ (void) printf("\t\tdir_obj = %llu\n",
+ (u_longlong_t)ds->ds_dir_obj);
+ (void) printf("\t\tprev_snap_obj = %llu\n",
+ (u_longlong_t)ds->ds_prev_snap_obj);
+ (void) printf("\t\tprev_snap_txg = %llu\n",
+ (u_longlong_t)ds->ds_prev_snap_txg);
+ (void) printf("\t\tnext_snap_obj = %llu\n",
+ (u_longlong_t)ds->ds_next_snap_obj);
+ (void) printf("\t\tsnapnames_zapobj = %llu\n",
+ (u_longlong_t)ds->ds_snapnames_zapobj);
+ (void) printf("\t\tnum_children = %llu\n",
+ (u_longlong_t)ds->ds_num_children);
+ (void) printf("\t\tuserrefs_obj = %llu\n",
+ (u_longlong_t)ds->ds_userrefs_obj);
+ (void) printf("\t\tcreation_time = %s", ctime(&crtime));
+ (void) printf("\t\tcreation_txg = %llu\n",
+ (u_longlong_t)ds->ds_creation_txg);
+ (void) printf("\t\tdeadlist_obj = %llu\n",
+ (u_longlong_t)ds->ds_deadlist_obj);
+ (void) printf("\t\tused_bytes = %s\n", used);
+ (void) printf("\t\tcompressed_bytes = %s\n", compressed);
+ (void) printf("\t\tuncompressed_bytes = %s\n", uncompressed);
+ (void) printf("\t\tunique = %s\n", unique);
+ (void) printf("\t\tfsid_guid = %llu\n",
+ (u_longlong_t)ds->ds_fsid_guid);
+ (void) printf("\t\tguid = %llu\n",
+ (u_longlong_t)ds->ds_guid);
+ (void) printf("\t\tflags = %llx\n",
+ (u_longlong_t)ds->ds_flags);
+ (void) printf("\t\tnext_clones_obj = %llu\n",
+ (u_longlong_t)ds->ds_next_clones_obj);
+ (void) printf("\t\tprops_obj = %llu\n",
+ (u_longlong_t)ds->ds_props_obj);
+ (void) printf("\t\tbp = %s\n", blkbuf);
+}
+
+/* ARGSUSED */
+static int
+dump_bptree_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+ char blkbuf[BP_SPRINTF_LEN];
+
+ if (bp->blk_birth != 0) {
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+ (void) printf("\t%s\n", blkbuf);
+ }
+ return (0);
+}
+
+static void
+dump_bptree(objset_t *os, uint64_t obj, const char *name)
+{
+ char bytes[32];
+ bptree_phys_t *bt;
+ dmu_buf_t *db;
+
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
+
+ if (dump_opt['d'] < 3)
+ return;
+
+ VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db));
+ bt = db->db_data;
+ zdb_nicenum(bt->bt_bytes, bytes, sizeof (bytes));
+ (void) printf("\n %s: %llu datasets, %s\n",
+ name, (unsigned long long)(bt->bt_end - bt->bt_begin), bytes);
+ dmu_buf_rele(db, FTAG);
+
+ if (dump_opt['d'] < 5)
+ return;
+
+ (void) printf("\n");
+
+ (void) bptree_iterate(os, obj, B_FALSE, dump_bptree_cb, NULL, NULL);
+}
+
+/* ARGSUSED */
+static int
+dump_bpobj_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+ char blkbuf[BP_SPRINTF_LEN];
+
+ ASSERT(bp->blk_birth != 0);
+ snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp);
+ (void) printf("\t%s\n", blkbuf);
+ return (0);
+}
+
+static void
+dump_full_bpobj(bpobj_t *bpo, const char *name, int indent)
+{
+ char bytes[32];
+ char comp[32];
+ char uncomp[32];
+
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (uncomp) >= NN_NUMBUF_SZ);
+
+ if (dump_opt['d'] < 3)
+ return;
+
+ zdb_nicenum(bpo->bpo_phys->bpo_bytes, bytes, sizeof (bytes));
+ if (bpo->bpo_havesubobj && bpo->bpo_phys->bpo_subobjs != 0) {
+ zdb_nicenum(bpo->bpo_phys->bpo_comp, comp, sizeof (comp));
+ zdb_nicenum(bpo->bpo_phys->bpo_uncomp, uncomp, sizeof (uncomp));
+ (void) printf(" %*s: object %llu, %llu local blkptrs, "
+ "%llu subobjs in object %llu, %s (%s/%s comp)\n",
+ indent * 8, name,
+ (u_longlong_t)bpo->bpo_object,
+ (u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
+ (u_longlong_t)bpo->bpo_phys->bpo_num_subobjs,
+ (u_longlong_t)bpo->bpo_phys->bpo_subobjs,
+ bytes, comp, uncomp);
+
+ for (uint64_t i = 0; i < bpo->bpo_phys->bpo_num_subobjs; i++) {
+ uint64_t subobj;
+ bpobj_t subbpo;
+ int error;
+ VERIFY0(dmu_read(bpo->bpo_os,
+ bpo->bpo_phys->bpo_subobjs,
+ i * sizeof (subobj), sizeof (subobj), &subobj, 0));
+ error = bpobj_open(&subbpo, bpo->bpo_os, subobj);
+ if (error != 0) {
+ (void) printf("ERROR %u while trying to open "
+ "subobj id %llu\n",
+ error, (u_longlong_t)subobj);
+ continue;
+ }
+ dump_full_bpobj(&subbpo, "subobj", indent + 1);
+ bpobj_close(&subbpo);
+ }
+ } else {
+ (void) printf(" %*s: object %llu, %llu blkptrs, %s\n",
+ indent * 8, name,
+ (u_longlong_t)bpo->bpo_object,
+ (u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
+ bytes);
+ }
+
+ if (dump_opt['d'] < 5)
+ return;
+
+
+ if (indent == 0) {
+ (void) bpobj_iterate_nofree(bpo, dump_bpobj_cb, NULL, NULL);
+ (void) printf("\n");
+ }
+}
+
+static void
+bpobj_count_refd(bpobj_t *bpo)
+{
+ mos_obj_refd(bpo->bpo_object);
+
+ if (bpo->bpo_havesubobj && bpo->bpo_phys->bpo_subobjs != 0) {
+ mos_obj_refd(bpo->bpo_phys->bpo_subobjs);
+ for (uint64_t i = 0; i < bpo->bpo_phys->bpo_num_subobjs; i++) {
+ uint64_t subobj;
+ bpobj_t subbpo;
+ int error;
+ VERIFY0(dmu_read(bpo->bpo_os,
+ bpo->bpo_phys->bpo_subobjs,
+ i * sizeof (subobj), sizeof (subobj), &subobj, 0));
+ error = bpobj_open(&subbpo, bpo->bpo_os, subobj);
+ if (error != 0) {
+ (void) printf("ERROR %u while trying to open "
+ "subobj id %llu\n",
+ error, (u_longlong_t)subobj);
+ continue;
+ }
+ bpobj_count_refd(&subbpo);
+ bpobj_close(&subbpo);
+ }
+ }
+}
+
+static void
+dump_deadlist(dsl_deadlist_t *dl)
+{
+ dsl_deadlist_entry_t *dle;
+ uint64_t unused;
+ char bytes[32];
+ char comp[32];
+ char uncomp[32];
+ uint64_t empty_bpobj =
+ dmu_objset_spa(dl->dl_os)->spa_dsl_pool->dp_empty_bpobj;
+
+ /* force the tree to be loaded */
+ dsl_deadlist_space_range(dl, 0, UINT64_MAX, &unused, &unused, &unused);
+
+ if (dl->dl_oldfmt) {
+ if (dl->dl_bpobj.bpo_object != empty_bpobj)
+ bpobj_count_refd(&dl->dl_bpobj);
+ } else {
+ mos_obj_refd(dl->dl_object);
+ for (dle = avl_first(&dl->dl_tree); dle;
+ dle = AVL_NEXT(&dl->dl_tree, dle)) {
+ if (dle->dle_bpobj.bpo_object != empty_bpobj)
+ bpobj_count_refd(&dle->dle_bpobj);
+ }
+ }
+
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (uncomp) >= NN_NUMBUF_SZ);
+
+ if (dump_opt['d'] < 3)
+ return;
+
+ if (dl->dl_oldfmt) {
+ dump_full_bpobj(&dl->dl_bpobj, "old-format deadlist", 0);
+ return;
+ }
+
+ zdb_nicenum(dl->dl_phys->dl_used, bytes, sizeof (bytes));
+ zdb_nicenum(dl->dl_phys->dl_comp, comp, sizeof (comp));
+ zdb_nicenum(dl->dl_phys->dl_uncomp, uncomp, sizeof (uncomp));
+ (void) printf("\n Deadlist: %s (%s/%s comp)\n",
+ bytes, comp, uncomp);
+
+ if (dump_opt['d'] < 4)
+ return;
+
+ (void) printf("\n");
+
+ for (dle = avl_first(&dl->dl_tree); dle;
+ dle = AVL_NEXT(&dl->dl_tree, dle)) {
+ if (dump_opt['d'] >= 5) {
+ char buf[128];
+ (void) snprintf(buf, sizeof (buf),
+ "mintxg %llu -> obj %llu",
+ (longlong_t)dle->dle_mintxg,
+ (longlong_t)dle->dle_bpobj.bpo_object);
+ dump_full_bpobj(&dle->dle_bpobj, buf, 0);
+ } else {
+ (void) printf("mintxg %llu -> obj %llu\n",
+ (longlong_t)dle->dle_mintxg,
+ (longlong_t)dle->dle_bpobj.bpo_object);
+ }
+ }
+}
+
+static avl_tree_t idx_tree;
+static avl_tree_t domain_tree;
+static boolean_t fuid_table_loaded;
+static objset_t *sa_os = NULL;
+static sa_attr_type_t *sa_attr_table = NULL;
+
+static int
+open_objset(const char *path, dmu_objset_type_t type, void *tag, objset_t **osp)
+{
+ int err;
+ uint64_t sa_attrs = 0;
+ uint64_t version = 0;
+
+ VERIFY3P(sa_os, ==, NULL);
+ err = dmu_objset_own(path, type, B_TRUE, tag, osp);
+ if (err != 0) {
+ (void) fprintf(stderr, "failed to own dataset '%s': %s\n", path,
+ strerror(err));
+ return (err);
+ }
+
+ if (dmu_objset_type(*osp) == DMU_OST_ZFS) {
+ (void) zap_lookup(*osp, MASTER_NODE_OBJ, ZPL_VERSION_STR,
+ 8, 1, &version);
+ if (version >= ZPL_VERSION_SA) {
+ (void) zap_lookup(*osp, MASTER_NODE_OBJ, ZFS_SA_ATTRS,
+ 8, 1, &sa_attrs);
+ }
+ err = sa_setup(*osp, sa_attrs, zfs_attr_table, ZPL_END,
+ &sa_attr_table);
+ if (err != 0) {
+ (void) fprintf(stderr, "sa_setup failed: %s\n",
+ strerror(err));
+ dmu_objset_disown(*osp, tag);
+ *osp = NULL;
+ }
+ }
+ sa_os = *osp;
+
+ return (0);
+}
+
+static void
+close_objset(objset_t *os, void *tag)
+{
+ VERIFY3P(os, ==, sa_os);
+ if (os->os_sa != NULL)
+ sa_tear_down(os);
+ dmu_objset_disown(os, tag);
+ sa_attr_table = NULL;
+ sa_os = NULL;
+}
+
+static void
+fuid_table_destroy()
+{
+ if (fuid_table_loaded) {
+ zfs_fuid_table_destroy(&idx_tree, &domain_tree);
+ fuid_table_loaded = B_FALSE;
+ }
+}
+
+/*
+ * print uid or gid information.
+ * For normal POSIX id just the id is printed in decimal format.
+ * For CIFS files with FUID the fuid is printed in hex followed by
+ * the domain-rid string.
+ */
+static void
+print_idstr(uint64_t id, const char *id_type)
+{
+ if (FUID_INDEX(id)) {
+ char *domain;
+
+ domain = zfs_fuid_idx_domain(&idx_tree, FUID_INDEX(id));
+ (void) printf("\t%s %llx [%s-%d]\n", id_type,
+ (u_longlong_t)id, domain, (int)FUID_RID(id));
+ } else {
+ (void) printf("\t%s %llu\n", id_type, (u_longlong_t)id);
+ }
+
+}
+
+static void
+dump_uidgid(objset_t *os, uint64_t uid, uint64_t gid)
+{
+ uint32_t uid_idx, gid_idx;
+
+ uid_idx = FUID_INDEX(uid);
+ gid_idx = FUID_INDEX(gid);
+
+ /* Load domain table, if not already loaded */
+ if (!fuid_table_loaded && (uid_idx || gid_idx)) {
+ uint64_t fuid_obj;
+
+ /* first find the fuid object. It lives in the master node */
+ VERIFY(zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES,
+ 8, 1, &fuid_obj) == 0);
+ zfs_fuid_avl_tree_create(&idx_tree, &domain_tree);
+ (void) zfs_fuid_table_load(os, fuid_obj,
+ &idx_tree, &domain_tree);
+ fuid_table_loaded = B_TRUE;
+ }
+
+ print_idstr(uid, "uid");
+ print_idstr(gid, "gid");
+}
+
+/*ARGSUSED*/
+static void
+dump_znode(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ char path[MAXPATHLEN * 2]; /* allow for xattr and failure prefix */
+ sa_handle_t *hdl;
+ uint64_t xattr, rdev, gen;
+ uint64_t uid, gid, mode, fsize, parent, links;
+ uint64_t pflags;
+ uint64_t acctm[2], modtm[2], chgtm[2], crtm[2];
+ time_t z_crtime, z_atime, z_mtime, z_ctime;
+ sa_bulk_attr_t bulk[12];
+ int idx = 0;
+ int error;
+
+ VERIFY3P(os, ==, sa_os);
+ if (sa_handle_get(os, object, NULL, SA_HDL_PRIVATE, &hdl)) {
+ (void) printf("Failed to get handle for SA znode\n");
+ return;
+ }
+
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_UID], NULL, &uid, 8);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_GID], NULL, &gid, 8);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_LINKS], NULL,
+ &links, 8);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_GEN], NULL, &gen, 8);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_MODE], NULL,
+ &mode, 8);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_PARENT],
+ NULL, &parent, 8);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_SIZE], NULL,
+ &fsize, 8);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_ATIME], NULL,
+ acctm, 16);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_MTIME], NULL,
+ modtm, 16);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_CRTIME], NULL,
+ crtm, 16);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_CTIME], NULL,
+ chgtm, 16);
+ SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_FLAGS], NULL,
+ &pflags, 8);
+
+ if (sa_bulk_lookup(hdl, bulk, idx)) {
+ (void) sa_handle_destroy(hdl);
+ return;
+ }
+
+ z_crtime = (time_t)crtm[0];
+ z_atime = (time_t)acctm[0];
+ z_mtime = (time_t)modtm[0];
+ z_ctime = (time_t)chgtm[0];
+
+ if (dump_opt['d'] > 4) {
+ error = zfs_obj_to_path(os, object, path, sizeof (path));
+ if (error == ESTALE) {
+ (void) snprintf(path, sizeof (path), "on delete queue");
+ } else if (error != 0) {
+ leaked_objects++;
+ (void) snprintf(path, sizeof (path),
+ "path not found, possibly leaked");
+ }
+ (void) printf("\tpath %s\n", path);
+ }
+ dump_uidgid(os, uid, gid);
+ (void) printf("\tatime %s", ctime(&z_atime));
+ (void) printf("\tmtime %s", ctime(&z_mtime));
+ (void) printf("\tctime %s", ctime(&z_ctime));
+ (void) printf("\tcrtime %s", ctime(&z_crtime));
+ (void) printf("\tgen %llu\n", (u_longlong_t)gen);
+ (void) printf("\tmode %llo\n", (u_longlong_t)mode);
+ (void) printf("\tsize %llu\n", (u_longlong_t)fsize);
+ (void) printf("\tparent %llu\n", (u_longlong_t)parent);
+ (void) printf("\tlinks %llu\n", (u_longlong_t)links);
+ (void) printf("\tpflags %llx\n", (u_longlong_t)pflags);
+ if (sa_lookup(hdl, sa_attr_table[ZPL_XATTR], &xattr,
+ sizeof (uint64_t)) == 0)
+ (void) printf("\txattr %llu\n", (u_longlong_t)xattr);
+ if (sa_lookup(hdl, sa_attr_table[ZPL_RDEV], &rdev,
+ sizeof (uint64_t)) == 0)
+ (void) printf("\trdev 0x%016llx\n", (u_longlong_t)rdev);
+ sa_handle_destroy(hdl);
+}
+
+/*ARGSUSED*/
+static void
+dump_acl(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_dmu_objset(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+static object_viewer_t *object_viewer[DMU_OT_NUMTYPES + 1] = {
+ dump_none, /* unallocated */
+ dump_zap, /* object directory */
+ dump_uint64, /* object array */
+ dump_none, /* packed nvlist */
+ dump_packed_nvlist, /* packed nvlist size */
+ dump_none, /* bpobj */
+ dump_bpobj, /* bpobj header */
+ dump_none, /* SPA space map header */
+ dump_none, /* SPA space map */
+ dump_none, /* ZIL intent log */
+ dump_dnode, /* DMU dnode */
+ dump_dmu_objset, /* DMU objset */
+ dump_dsl_dir, /* DSL directory */
+ dump_zap, /* DSL directory child map */
+ dump_zap, /* DSL dataset snap map */
+ dump_zap, /* DSL props */
+ dump_dsl_dataset, /* DSL dataset */
+ dump_znode, /* ZFS znode */
+ dump_acl, /* ZFS V0 ACL */
+ dump_uint8, /* ZFS plain file */
+ dump_zpldir, /* ZFS directory */
+ dump_zap, /* ZFS master node */
+ dump_zap, /* ZFS delete queue */
+ dump_uint8, /* zvol object */
+ dump_zap, /* zvol prop */
+ dump_uint8, /* other uint8[] */
+ dump_uint64, /* other uint64[] */
+ dump_zap, /* other ZAP */
+ dump_zap, /* persistent error log */
+ dump_uint8, /* SPA history */
+ dump_history_offsets, /* SPA history offsets */
+ dump_zap, /* Pool properties */
+ dump_zap, /* DSL permissions */
+ dump_acl, /* ZFS ACL */
+ dump_uint8, /* ZFS SYSACL */
+ dump_none, /* FUID nvlist */
+ dump_packed_nvlist, /* FUID nvlist size */
+ dump_zap, /* DSL dataset next clones */
+ dump_zap, /* DSL scrub queue */
+ dump_zap, /* ZFS user/group used */
+ dump_zap, /* ZFS user/group quota */
+ dump_zap, /* snapshot refcount tags */
+ dump_ddt_zap, /* DDT ZAP object */
+ dump_zap, /* DDT statistics */
+ dump_znode, /* SA object */
+ dump_zap, /* SA Master Node */
+ dump_sa_attrs, /* SA attribute registration */
+ dump_sa_layouts, /* SA attribute layouts */
+ dump_zap, /* DSL scrub translations */
+ dump_none, /* fake dedup BP */
+ dump_zap, /* deadlist */
+ dump_none, /* deadlist hdr */
+ dump_zap, /* dsl clones */
+ dump_bpobj_subobjs, /* bpobj subobjs */
+ dump_unknown, /* Unknown type, must be last */
+};
+
+static void
+dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header,
+ uint64_t *dnode_slots_used)
+{
+ dmu_buf_t *db = NULL;
+ dmu_object_info_t doi;
+ dnode_t *dn;
+ void *bonus = NULL;
+ size_t bsize = 0;
+ char iblk[32], dblk[32], lsize[32], asize[32], fill[32], dnsize[32];
+ char bonus_size[32];
+ char aux[50];
+ int error;
+
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (iblk) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (dblk) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (lsize) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (asize) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (bonus_size) >= NN_NUMBUF_SZ);
+
+ if (*print_header) {
+ (void) printf("\n%10s %3s %5s %5s %5s %6s %5s %6s %s\n",
+ "Object", "lvl", "iblk", "dblk", "dsize", "dnsize",
+ "lsize", "%full", "type");
+ *print_header = 0;
+ }
+
+ if (object == 0) {
+ dn = DMU_META_DNODE(os);
+ } else {
+ error = dmu_bonus_hold(os, object, FTAG, &db);
+ if (error)
+ fatal("dmu_bonus_hold(%llu) failed, errno %u",
+ object, error);
+ bonus = db->db_data;
+ bsize = db->db_size;
+ dn = DB_DNODE((dmu_buf_impl_t *)db);
+ }
+ dmu_object_info_from_dnode(dn, &doi);
+
+ if (dnode_slots_used != NULL)
+ *dnode_slots_used = doi.doi_dnodesize / DNODE_MIN_SIZE;
+
+ zdb_nicenum(doi.doi_metadata_block_size, iblk, sizeof (iblk));
+ zdb_nicenum(doi.doi_data_block_size, dblk, sizeof (dblk));
+ zdb_nicenum(doi.doi_max_offset, lsize, sizeof (lsize));
+ zdb_nicenum(doi.doi_physical_blocks_512 << 9, asize, sizeof (asize));
+ zdb_nicenum(doi.doi_bonus_size, bonus_size, sizeof (bonus_size));
+ zdb_nicenum(doi.doi_dnodesize, dnsize, sizeof (dnsize));
+ (void) sprintf(fill, "%6.2f", 100.0 * doi.doi_fill_count *
+ doi.doi_data_block_size / (object == 0 ? DNODES_PER_BLOCK : 1) /
+ doi.doi_max_offset);
+
+ aux[0] = '\0';
+
+ if (doi.doi_checksum != ZIO_CHECKSUM_INHERIT || verbosity >= 6) {
+ (void) snprintf(aux + strlen(aux), sizeof (aux), " (K=%s)",
+ ZDB_CHECKSUM_NAME(doi.doi_checksum));
+ }
+
+ if (doi.doi_compress != ZIO_COMPRESS_INHERIT || verbosity >= 6) {
+ (void) snprintf(aux + strlen(aux), sizeof (aux), " (Z=%s)",
+ ZDB_COMPRESS_NAME(doi.doi_compress));
+ }
+
+ (void) printf("%10" PRIu64
+ " %3u %5s %5s %5s %5s %5s %6s %s%s\n",
+ object, doi.doi_indirection, iblk, dblk,
+ asize, dnsize, lsize, fill, ZDB_OT_NAME(doi.doi_type), aux);
+
+ if (doi.doi_bonus_type != DMU_OT_NONE && verbosity > 3) {
+ (void) printf("%10s %3s %5s %5s %5s %5s %5s %6s %s\n",
+ "", "", "", "", "", "", bonus_size, "bonus",
+ ZDB_OT_NAME(doi.doi_bonus_type));
+ }
+
+ if (verbosity >= 4) {
+ (void) printf("\tdnode flags: %s%s%s\n",
+ (dn->dn_phys->dn_flags & DNODE_FLAG_USED_BYTES) ?
+ "USED_BYTES " : "",
+ (dn->dn_phys->dn_flags & DNODE_FLAG_USERUSED_ACCOUNTED) ?
+ "USERUSED_ACCOUNTED " : "",
+ (dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR) ?
+ "SPILL_BLKPTR" : "");
+ (void) printf("\tdnode maxblkid: %llu\n",
+ (longlong_t)dn->dn_phys->dn_maxblkid);
+
+ object_viewer[ZDB_OT_TYPE(doi.doi_bonus_type)](os, object,
+ bonus, bsize);
+ object_viewer[ZDB_OT_TYPE(doi.doi_type)](os, object, NULL, 0);
+ *print_header = 1;
+ }
+
+ if (verbosity >= 5)
+ dump_indirect(dn);
+
+ if (verbosity >= 5) {
+ /*
+ * Report the list of segments that comprise the object.
+ */
+ uint64_t start = 0;
+ uint64_t end;
+ uint64_t blkfill = 1;
+ int minlvl = 1;
+
+ if (dn->dn_type == DMU_OT_DNODE) {
+ minlvl = 0;
+ blkfill = DNODES_PER_BLOCK;
+ }
+
+ for (;;) {
+ char segsize[32];
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (segsize) >= NN_NUMBUF_SZ);
+ error = dnode_next_offset(dn,
+ 0, &start, minlvl, blkfill, 0);
+ if (error)
+ break;
+ end = start;
+ error = dnode_next_offset(dn,
+ DNODE_FIND_HOLE, &end, minlvl, blkfill, 0);
+ zdb_nicenum(end - start, segsize, sizeof (segsize));
+ (void) printf("\t\tsegment [%016llx, %016llx)"
+ " size %5s\n", (u_longlong_t)start,
+ (u_longlong_t)end, segsize);
+ if (error)
+ break;
+ start = end;
+ }
+ }
+
+ if (db != NULL)
+ dmu_buf_rele(db, FTAG);
+}
+
+static void
+count_dir_mos_objects(dsl_dir_t *dd)
+{
+ mos_obj_refd(dd->dd_object);
+ mos_obj_refd(dsl_dir_phys(dd)->dd_child_dir_zapobj);
+ mos_obj_refd(dsl_dir_phys(dd)->dd_deleg_zapobj);
+ mos_obj_refd(dsl_dir_phys(dd)->dd_props_zapobj);
+ mos_obj_refd(dsl_dir_phys(dd)->dd_clones);
+}
+
+static void
+count_ds_mos_objects(dsl_dataset_t *ds)
+{
+ mos_obj_refd(ds->ds_object);
+ mos_obj_refd(dsl_dataset_phys(ds)->ds_next_clones_obj);
+ mos_obj_refd(dsl_dataset_phys(ds)->ds_props_obj);
+ mos_obj_refd(dsl_dataset_phys(ds)->ds_userrefs_obj);
+ mos_obj_refd(dsl_dataset_phys(ds)->ds_snapnames_zapobj);
+
+ if (!dsl_dataset_is_snapshot(ds)) {
+ count_dir_mos_objects(ds->ds_dir);
+ }
+}
+
+static const char *objset_types[DMU_OST_NUMTYPES] = {
+ "NONE", "META", "ZPL", "ZVOL", "OTHER", "ANY" };
+
+static void
+dump_dir(objset_t *os)
+{
+ dmu_objset_stats_t dds;
+ uint64_t object, object_count;
+ uint64_t refdbytes, usedobjs, scratch;
+ char numbuf[32];
+ char blkbuf[BP_SPRINTF_LEN + 20];
+ char osname[ZFS_MAX_DATASET_NAME_LEN];
+ const char *type = "UNKNOWN";
+ int verbosity = dump_opt['d'];
+ int print_header = 1;
+ unsigned i;
+ int error;
+ uint64_t total_slots_used = 0;
+ uint64_t max_slot_used = 0;
+ uint64_t dnode_slots;
+
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (numbuf) >= NN_NUMBUF_SZ);
+
+ dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
+ dmu_objset_fast_stat(os, &dds);
+ dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
+
+ if (dds.dds_type < DMU_OST_NUMTYPES)
+ type = objset_types[dds.dds_type];
+
+ if (dds.dds_type == DMU_OST_META) {
+ dds.dds_creation_txg = TXG_INITIAL;
+ usedobjs = BP_GET_FILL(os->os_rootbp);
+ refdbytes = dsl_dir_phys(os->os_spa->spa_dsl_pool->dp_mos_dir)->
+ dd_used_bytes;
+ } else {
+ dmu_objset_space(os, &refdbytes, &scratch, &usedobjs, &scratch);
+ }
+
+ ASSERT3U(usedobjs, ==, BP_GET_FILL(os->os_rootbp));
+
+ zdb_nicenum(refdbytes, numbuf, sizeof (numbuf));
+
+ if (verbosity >= 4) {
+ (void) snprintf(blkbuf, sizeof (blkbuf), ", rootbp ");
+ (void) snprintf_blkptr(blkbuf + strlen(blkbuf),
+ sizeof (blkbuf) - strlen(blkbuf), os->os_rootbp);
+ } else {
+ blkbuf[0] = '\0';
+ }
+
+ dmu_objset_name(os, osname);
+
+ (void) printf("Dataset %s [%s], ID %llu, cr_txg %llu, "
+ "%s, %llu objects%s%s\n",
+ osname, type, (u_longlong_t)dmu_objset_id(os),
+ (u_longlong_t)dds.dds_creation_txg,
+ numbuf, (u_longlong_t)usedobjs, blkbuf,
+ (dds.dds_inconsistent) ? " (inconsistent)" : "");
+
+ if (zopt_objects != 0) {
+ for (i = 0; i < zopt_objects; i++)
+ dump_object(os, zopt_object[i], verbosity,
+ &print_header, NULL);
+ (void) printf("\n");
+ return;
+ }
+
+ if (dump_opt['i'] != 0 || verbosity >= 2)
+ dump_intent_log(dmu_objset_zil(os));
+
+ if (dmu_objset_ds(os) != NULL) {
+ dsl_dataset_t *ds = dmu_objset_ds(os);
+ dump_deadlist(&ds->ds_deadlist);
+
+ if (dsl_dataset_remap_deadlist_exists(ds)) {
+ (void) printf("ds_remap_deadlist:\n");
+ dump_deadlist(&ds->ds_remap_deadlist);
+ }
+ count_ds_mos_objects(ds);
+ }
+
+ if (verbosity < 2)
+ return;
+
+ if (BP_IS_HOLE(os->os_rootbp))
+ return;
+
+ dump_object(os, 0, verbosity, &print_header, NULL);
+ object_count = 0;
+ if (DMU_USERUSED_DNODE(os) != NULL &&
+ DMU_USERUSED_DNODE(os)->dn_type != 0) {
+ dump_object(os, DMU_USERUSED_OBJECT, verbosity, &print_header,
+ NULL);
+ dump_object(os, DMU_GROUPUSED_OBJECT, verbosity, &print_header,
+ NULL);
+ }
+
+ object = 0;
+ while ((error = dmu_object_next(os, &object, B_FALSE, 0)) == 0) {
+ dump_object(os, object, verbosity, &print_header, &dnode_slots);
+ object_count++;
+ total_slots_used += dnode_slots;
+ max_slot_used = object + dnode_slots - 1;
+ }
+
+ (void) printf("\n");
+
+ (void) printf(" Dnode slots:\n");
+ (void) printf("\tTotal used: %10llu\n",
+ (u_longlong_t)total_slots_used);
+ (void) printf("\tMax used: %10llu\n",
+ (u_longlong_t)max_slot_used);
+ (void) printf("\tPercent empty: %10lf\n",
+ (double)(max_slot_used - total_slots_used)*100 /
+ (double)max_slot_used);
+
+ (void) printf("\n");
+
+ if (error != ESRCH) {
+ (void) fprintf(stderr, "dmu_object_next() = %d\n", error);
+ abort();
+ }
+
+ ASSERT3U(object_count, ==, usedobjs);
+
+ if (leaked_objects != 0) {
+ (void) printf("%d potentially leaked objects detected\n",
+ leaked_objects);
+ leaked_objects = 0;
+ }
+}
+
+static void
+dump_uberblock(uberblock_t *ub, const char *header, const char *footer)
+{
+ time_t timestamp = ub->ub_timestamp;
+
+ (void) printf("%s", header ? header : "");
+ (void) printf("\tmagic = %016llx\n", (u_longlong_t)ub->ub_magic);
+ (void) printf("\tversion = %llu\n", (u_longlong_t)ub->ub_version);
+ (void) printf("\ttxg = %llu\n", (u_longlong_t)ub->ub_txg);
+ (void) printf("\tguid_sum = %llu\n", (u_longlong_t)ub->ub_guid_sum);
+ (void) printf("\ttimestamp = %llu UTC = %s",
+ (u_longlong_t)ub->ub_timestamp, asctime(localtime(&timestamp)));
+
+ (void) printf("\tmmp_magic = %016llx\n",
+ (u_longlong_t)ub->ub_mmp_magic);
+ if (MMP_VALID(ub)) {
+ (void) printf("\tmmp_delay = %0llu\n",
+ (u_longlong_t)ub->ub_mmp_delay);
+ if (MMP_SEQ_VALID(ub))
+ (void) printf("\tmmp_seq = %u\n",
+ (unsigned int) MMP_SEQ(ub));
+ if (MMP_FAIL_INT_VALID(ub))
+ (void) printf("\tmmp_fail = %u\n",
+ (unsigned int) MMP_FAIL_INT(ub));
+ if (MMP_INTERVAL_VALID(ub))
+ (void) printf("\tmmp_write = %u\n",
+ (unsigned int) MMP_INTERVAL(ub));
+ /* After MMP_* to make summarize_uberblock_mmp cleaner */
+ (void) printf("\tmmp_valid = %x\n",
+ (unsigned int) ub->ub_mmp_config & 0xFF);
+ }
+
+ if (dump_opt['u'] >= 3) {
+ char blkbuf[BP_SPRINTF_LEN];
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), &ub->ub_rootbp);
+ (void) printf("\trootbp = %s\n", blkbuf);
+ }
+ (void) printf("\tcheckpoint_txg = %llu\n",
+ (u_longlong_t)ub->ub_checkpoint_txg);
+ (void) printf("%s", footer ? footer : "");
+}
+
+static void
+dump_config(spa_t *spa)
+{
+ dmu_buf_t *db;
+ size_t nvsize = 0;
+ int error = 0;
+
+
+ error = dmu_bonus_hold(spa->spa_meta_objset,
+ spa->spa_config_object, FTAG, &db);
+
+ if (error == 0) {
+ nvsize = *(uint64_t *)db->db_data;
+ dmu_buf_rele(db, FTAG);
+
+ (void) printf("\nMOS Configuration:\n");
+ dump_packed_nvlist(spa->spa_meta_objset,
+ spa->spa_config_object, (void *)&nvsize, 1);
+ } else {
+ (void) fprintf(stderr, "dmu_bonus_hold(%llu) failed, errno %d",
+ (u_longlong_t)spa->spa_config_object, error);
+ }
+}
+
+static void
+dump_cachefile(const char *cachefile)
+{
+ int fd;
+ struct stat64 statbuf;
+ char *buf;
+ nvlist_t *config;
+
+ if ((fd = open64(cachefile, O_RDONLY)) < 0) {
+ (void) fprintf(stderr, "cannot open '%s': %s\n", cachefile,
+ strerror(errno));
+ exit(1);
+ }
+
+ if (fstat64(fd, &statbuf) != 0) {
+ (void) fprintf(stderr, "failed to stat '%s': %s\n", cachefile,
+ strerror(errno));
+ exit(1);
+ }
+
+ if ((buf = malloc(statbuf.st_size)) == NULL) {
+ (void) fprintf(stderr, "failed to allocate %llu bytes\n",
+ (u_longlong_t)statbuf.st_size);
+ exit(1);
+ }
+
+ if (read(fd, buf, statbuf.st_size) != statbuf.st_size) {
+ (void) fprintf(stderr, "failed to read %llu bytes\n",
+ (u_longlong_t)statbuf.st_size);
+ exit(1);
+ }
+
+ (void) close(fd);
+
+ if (nvlist_unpack(buf, statbuf.st_size, &config, 0) != 0) {
+ (void) fprintf(stderr, "failed to unpack nvlist\n");
+ exit(1);
+ }
+
+ free(buf);
+
+ dump_nvlist(config, 0);
+
+ nvlist_free(config);
+}
+
+#define ZDB_MAX_UB_HEADER_SIZE 32
+
+static void
+dump_label_uberblocks(vdev_label_t *lbl, uint64_t ashift)
+{
+ vdev_t vd;
+ vdev_t *vdp = &vd;
+ char header[ZDB_MAX_UB_HEADER_SIZE];
+
+ vd.vdev_ashift = ashift;
+ vdp->vdev_top = vdp;
+
+ for (int i = 0; i < VDEV_UBERBLOCK_COUNT(vdp); i++) {
+ uint64_t uoff = VDEV_UBERBLOCK_OFFSET(vdp, i);
+ uberblock_t *ub = (void *)((char *)lbl + uoff);
+
+ if (uberblock_verify(ub))
+ continue;
+
+ if ((dump_opt['u'] < 4) &&
+ (ub->ub_mmp_magic == MMP_MAGIC) && ub->ub_mmp_delay &&
+ (i >= VDEV_UBERBLOCK_COUNT(&vd) - MMP_BLOCKS_PER_LABEL))
+ continue;
+
+ (void) snprintf(header, ZDB_MAX_UB_HEADER_SIZE,
+ "Uberblock[%d]\n", i);
+ dump_uberblock(ub, header, "");
+ }
+}
+
+static char curpath[PATH_MAX];
+
+/*
+ * Iterate through the path components, recursively passing
+ * current one's obj and remaining path until we find the obj
+ * for the last one.
+ */
+static int
+dump_path_impl(objset_t *os, uint64_t obj, char *name)
+{
+ int err;
+ int header = 1;
+ uint64_t child_obj;
+ char *s;
+ dmu_buf_t *db;
+ dmu_object_info_t doi;
+
+ if ((s = strchr(name, '/')) != NULL)
+ *s = '\0';
+ err = zap_lookup(os, obj, name, 8, 1, &child_obj);
+
+ (void) strlcat(curpath, name, sizeof (curpath));
+
+ if (err != 0) {
+ (void) fprintf(stderr, "failed to lookup %s: %s\n",
+ curpath, strerror(err));
+ return (err);
+ }
+
+ child_obj = ZFS_DIRENT_OBJ(child_obj);
+ err = sa_buf_hold(os, child_obj, FTAG, &db);
+ if (err != 0) {
+ (void) fprintf(stderr,
+ "failed to get SA dbuf for obj %llu: %s\n",
+ (u_longlong_t)child_obj, strerror(err));
+ return (EINVAL);
+ }
+ dmu_object_info_from_db(db, &doi);
+ sa_buf_rele(db, FTAG);
+
+ if (doi.doi_bonus_type != DMU_OT_SA &&
+ doi.doi_bonus_type != DMU_OT_ZNODE) {
+ (void) fprintf(stderr, "invalid bonus type %d for obj %llu\n",
+ doi.doi_bonus_type, (u_longlong_t)child_obj);
+ return (EINVAL);
+ }
+
+ if (dump_opt['v'] > 6) {
+ (void) printf("obj=%llu %s type=%d bonustype=%d\n",
+ (u_longlong_t)child_obj, curpath, doi.doi_type,
+ doi.doi_bonus_type);
+ }
+
+ (void) strlcat(curpath, "/", sizeof (curpath));
+
+ switch (doi.doi_type) {
+ case DMU_OT_DIRECTORY_CONTENTS:
+ if (s != NULL && *(s + 1) != '\0')
+ return (dump_path_impl(os, child_obj, s + 1));
+ /*FALLTHROUGH*/
+ case DMU_OT_PLAIN_FILE_CONTENTS:
+ dump_object(os, child_obj, dump_opt['v'], &header, NULL);
+ return (0);
+ default:
+ (void) fprintf(stderr, "object %llu has non-file/directory "
+ "type %d\n", (u_longlong_t)obj, doi.doi_type);
+ break;
+ }
+
+ return (EINVAL);
+}
+
+/*
+ * Dump the blocks for the object specified by path inside the dataset.
+ */
+static int
+dump_path(char *ds, char *path)
+{
+ int err;
+ objset_t *os;
+ uint64_t root_obj;
+
+ err = open_objset(ds, DMU_OST_ZFS, FTAG, &os);
+ if (err != 0)
+ return (err);
+
+ err = zap_lookup(os, MASTER_NODE_OBJ, ZFS_ROOT_OBJ, 8, 1, &root_obj);
+ if (err != 0) {
+ (void) fprintf(stderr, "can't lookup root znode: %s\n",
+ strerror(err));
+ dmu_objset_disown(os, FTAG);
+ return (EINVAL);
+ }
+
+ (void) snprintf(curpath, sizeof (curpath), "dataset=%s path=/", ds);
+
+ err = dump_path_impl(os, root_obj, path);
+
+ close_objset(os, FTAG);
+ return (err);
+}
+
+static int
+dump_label(const char *dev)
+{
+ int fd;
+ vdev_label_t label;
+ char path[MAXPATHLEN];
+ char *buf = label.vl_vdev_phys.vp_nvlist;
+ size_t buflen = sizeof (label.vl_vdev_phys.vp_nvlist);
+ struct stat64 statbuf;
+ uint64_t psize, ashift;
+ boolean_t label_found = B_FALSE;
+
+ (void) strlcpy(path, dev, sizeof (path));
+ if (dev[0] == '/') {
+ if (strncmp(dev, ZFS_DISK_ROOTD,
+ strlen(ZFS_DISK_ROOTD)) == 0) {
+ (void) snprintf(path, sizeof (path), "%s%s",
+ ZFS_RDISK_ROOTD, dev + strlen(ZFS_DISK_ROOTD));
+ }
+ } else if (stat64(path, &statbuf) != 0) {
+ char *s;
+
+ (void) snprintf(path, sizeof (path), "%s%s", ZFS_RDISK_ROOTD,
+ dev);
+ if (((s = strrchr(dev, 's')) == NULL &&
+ (s = strchr(dev, 'p')) == NULL) ||
+ !isdigit(*(s + 1)))
+ (void) strlcat(path, "s0", sizeof (path));
+ }
+
+ if ((fd = open64(path, O_RDONLY)) < 0) {
+ (void) fprintf(stderr, "cannot open '%s': %s\n", path,
+ strerror(errno));
+ exit(1);
+ }
+
+ if (fstat64(fd, &statbuf) != 0) {
+ (void) fprintf(stderr, "failed to stat '%s': %s\n", path,
+ strerror(errno));
+ (void) close(fd);
+ exit(1);
+ }
+
+ if (S_ISBLK(statbuf.st_mode)) {
+ (void) fprintf(stderr,
+ "cannot use '%s': character device required\n", path);
+ (void) close(fd);
+ exit(1);
+ }
+
+ psize = statbuf.st_size;
+ psize = P2ALIGN(psize, (uint64_t)sizeof (vdev_label_t));
+
+ for (int l = 0; l < VDEV_LABELS; l++) {
+ nvlist_t *config = NULL;
+
+ if (!dump_opt['q']) {
+ (void) printf("------------------------------------\n");
+ (void) printf("LABEL %d\n", l);
+ (void) printf("------------------------------------\n");
+ }
+
+ if (pread64(fd, &label, sizeof (label),
+ vdev_label_offset(psize, l, 0)) != sizeof (label)) {
+ if (!dump_opt['q'])
+ (void) printf("failed to read label %d\n", l);
+ continue;
+ }
+
+ if (nvlist_unpack(buf, buflen, &config, 0) != 0) {
+ if (!dump_opt['q'])
+ (void) printf("failed to unpack label %d\n", l);
+ ashift = SPA_MINBLOCKSHIFT;
+ } else {
+ nvlist_t *vdev_tree = NULL;
+
+ if (!dump_opt['q'])
+ dump_nvlist(config, 4);
+ if ((nvlist_lookup_nvlist(config,
+ ZPOOL_CONFIG_VDEV_TREE, &vdev_tree) != 0) ||
+ (nvlist_lookup_uint64(vdev_tree,
+ ZPOOL_CONFIG_ASHIFT, &ashift) != 0))
+ ashift = SPA_MINBLOCKSHIFT;
+ nvlist_free(config);
+ label_found = B_TRUE;
+ }
+ if (dump_opt['u'])
+ dump_label_uberblocks(&label, ashift);
+ }
+
+ (void) close(fd);
+
+ return (label_found ? 0 : 2);
+}
+
+static uint64_t dataset_feature_count[SPA_FEATURES];
+static uint64_t remap_deadlist_count = 0;
+
+/*ARGSUSED*/
+static int
+dump_one_dir(const char *dsname, void *arg)
+{
+ int error;
+ objset_t *os;
+
+ error = open_objset(dsname, DMU_OST_ANY, FTAG, &os);
+ if (error != 0)
+ return (0);
+
+ for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
+ if (!dmu_objset_ds(os)->ds_feature_inuse[f])
+ continue;
+ ASSERT(spa_feature_table[f].fi_flags &
+ ZFEATURE_FLAG_PER_DATASET);
+ dataset_feature_count[f]++;
+ }
+
+ if (dsl_dataset_remap_deadlist_exists(dmu_objset_ds(os))) {
+ remap_deadlist_count++;
+ }
+
+ dump_dir(os);
+ close_objset(os, FTAG);
+ fuid_table_destroy();
+ return (0);
+}
+
+/*
+ * Block statistics.
+ */
+#define PSIZE_HISTO_SIZE (SPA_OLD_MAXBLOCKSIZE / SPA_MINBLOCKSIZE + 2)
+typedef struct zdb_blkstats {
+ uint64_t zb_asize;
+ uint64_t zb_lsize;
+ uint64_t zb_psize;
+ uint64_t zb_count;
+ uint64_t zb_gangs;
+ uint64_t zb_ditto_samevdev;
+ uint64_t zb_ditto_same_ms;
+ uint64_t zb_psize_histogram[PSIZE_HISTO_SIZE];
+} zdb_blkstats_t;
+
+/*
+ * Extended object types to report deferred frees and dedup auto-ditto blocks.
+ */
+#define ZDB_OT_DEFERRED (DMU_OT_NUMTYPES + 0)
+#define ZDB_OT_DITTO (DMU_OT_NUMTYPES + 1)
+#define ZDB_OT_OTHER (DMU_OT_NUMTYPES + 2)
+#define ZDB_OT_TOTAL (DMU_OT_NUMTYPES + 3)
+
+static const char *zdb_ot_extname[] = {
+ "deferred free",
+ "dedup ditto",
+ "other",
+ "Total",
+};
+
+#define ZB_TOTAL DN_MAX_LEVELS
+
+typedef struct zdb_cb {
+ zdb_blkstats_t zcb_type[ZB_TOTAL + 1][ZDB_OT_TOTAL + 1];
+ uint64_t zcb_removing_size;
+ uint64_t zcb_checkpoint_size;
+ uint64_t zcb_dedup_asize;
+ uint64_t zcb_dedup_blocks;
+ uint64_t zcb_embedded_blocks[NUM_BP_EMBEDDED_TYPES];
+ uint64_t zcb_embedded_histogram[NUM_BP_EMBEDDED_TYPES]
+ [BPE_PAYLOAD_SIZE];
+ uint64_t zcb_start;
+ hrtime_t zcb_lastprint;
+ uint64_t zcb_totalasize;
+ uint64_t zcb_errors[256];
+ int zcb_readfails;
+ int zcb_haderrors;
+ spa_t *zcb_spa;
+ uint32_t **zcb_vd_obsolete_counts;
+} zdb_cb_t;
+
+/* test if two DVA offsets from same vdev are within the same metaslab */
+static boolean_t
+same_metaslab(spa_t *spa, uint64_t vdev, uint64_t off1, uint64_t off2)
+{
+ vdev_t *vd = vdev_lookup_top(spa, vdev);
+ uint64_t ms_shift = vd->vdev_ms_shift;
+
+ return ((off1 >> ms_shift) == (off2 >> ms_shift));
+}
+
+static void
+zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
+ dmu_object_type_t type)
+{
+ uint64_t refcnt = 0;
+
+ ASSERT(type < ZDB_OT_TOTAL);
+
+ if (zilog && zil_bp_tree_add(zilog, bp) != 0)
+ return;
+
+ spa_config_enter(zcb->zcb_spa, SCL_CONFIG, FTAG, RW_READER);
+
+ for (int i = 0; i < 4; i++) {
+ int l = (i < 2) ? BP_GET_LEVEL(bp) : ZB_TOTAL;
+ int t = (i & 1) ? type : ZDB_OT_TOTAL;
+ int equal;
+ zdb_blkstats_t *zb = &zcb->zcb_type[l][t];
+
+ zb->zb_asize += BP_GET_ASIZE(bp);
+ zb->zb_lsize += BP_GET_LSIZE(bp);
+ zb->zb_psize += BP_GET_PSIZE(bp);
+ zb->zb_count++;
+
+ /*
+ * The histogram is only big enough to record blocks up to
+ * SPA_OLD_MAXBLOCKSIZE; larger blocks go into the last,
+ * "other", bucket.
+ */
+ unsigned idx = BP_GET_PSIZE(bp) >> SPA_MINBLOCKSHIFT;
+ idx = MIN(idx, SPA_OLD_MAXBLOCKSIZE / SPA_MINBLOCKSIZE + 1);
+ zb->zb_psize_histogram[idx]++;
+
+ zb->zb_gangs += BP_COUNT_GANG(bp);
+
+ switch (BP_GET_NDVAS(bp)) {
+ case 2:
+ if (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+ DVA_GET_VDEV(&bp->blk_dva[1])) {
+ zb->zb_ditto_samevdev++;
+
+ if (same_metaslab(zcb->zcb_spa,
+ DVA_GET_VDEV(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[1])))
+ zb->zb_ditto_same_ms++;
+ }
+ break;
+ case 3:
+ equal = (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+ DVA_GET_VDEV(&bp->blk_dva[1])) +
+ (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+ DVA_GET_VDEV(&bp->blk_dva[2])) +
+ (DVA_GET_VDEV(&bp->blk_dva[1]) ==
+ DVA_GET_VDEV(&bp->blk_dva[2]));
+ if (equal != 0) {
+ zb->zb_ditto_samevdev++;
+
+ if (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+ DVA_GET_VDEV(&bp->blk_dva[1]) &&
+ same_metaslab(zcb->zcb_spa,
+ DVA_GET_VDEV(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[1])))
+ zb->zb_ditto_same_ms++;
+ else if (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+ DVA_GET_VDEV(&bp->blk_dva[2]) &&
+ same_metaslab(zcb->zcb_spa,
+ DVA_GET_VDEV(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[2])))
+ zb->zb_ditto_same_ms++;
+ else if (DVA_GET_VDEV(&bp->blk_dva[1]) ==
+ DVA_GET_VDEV(&bp->blk_dva[2]) &&
+ same_metaslab(zcb->zcb_spa,
+ DVA_GET_VDEV(&bp->blk_dva[1]),
+ DVA_GET_OFFSET(&bp->blk_dva[1]),
+ DVA_GET_OFFSET(&bp->blk_dva[2])))
+ zb->zb_ditto_same_ms++;
+ }
+ break;
+ }
+ }
+
+ spa_config_exit(zcb->zcb_spa, SCL_CONFIG, FTAG);
+
+ if (BP_IS_EMBEDDED(bp)) {
+ zcb->zcb_embedded_blocks[BPE_GET_ETYPE(bp)]++;
+ zcb->zcb_embedded_histogram[BPE_GET_ETYPE(bp)]
+ [BPE_GET_PSIZE(bp)]++;
+ return;
+ }
+
+ if (dump_opt['L'])
+ return;
+
+ if (BP_GET_DEDUP(bp)) {
+ ddt_t *ddt;
+ ddt_entry_t *dde;
+
+ ddt = ddt_select(zcb->zcb_spa, bp);
+ ddt_enter(ddt);
+ dde = ddt_lookup(ddt, bp, B_FALSE);
+
+ if (dde == NULL) {
+ refcnt = 0;
+ } else {
+ ddt_phys_t *ddp = ddt_phys_select(dde, bp);
+ ddt_phys_decref(ddp);
+ refcnt = ddp->ddp_refcnt;
+ if (ddt_phys_total_refcnt(dde) == 0)
+ ddt_remove(ddt, dde);
+ }
+ ddt_exit(ddt);
+ }
+
+ VERIFY3U(zio_wait(zio_claim(NULL, zcb->zcb_spa,
+ refcnt ? 0 : spa_min_claim_txg(zcb->zcb_spa),
+ bp, NULL, NULL, ZIO_FLAG_CANFAIL)), ==, 0);
+}
+
+/* ARGSUSED */
+static void
+zdb_blkptr_done(zio_t *zio)
+{
+ spa_t *spa = zio->io_spa;
+ blkptr_t *bp = zio->io_bp;
+ int ioerr = zio->io_error;
+ zdb_cb_t *zcb = zio->io_private;
+ zbookmark_phys_t *zb = &zio->io_bookmark;
+
+ abd_free(zio->io_abd);
+
+ mutex_enter(&spa->spa_scrub_lock);
+ spa->spa_scrub_inflight--;
+ spa->spa_load_verify_ios--;
+ cv_broadcast(&spa->spa_scrub_io_cv);
+
+ if (ioerr && !(zio->io_flags & ZIO_FLAG_SPECULATIVE)) {
+ char blkbuf[BP_SPRINTF_LEN];
+
+ zcb->zcb_haderrors = 1;
+ zcb->zcb_errors[ioerr]++;
+
+ if (dump_opt['b'] >= 2)
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+ else
+ blkbuf[0] = '\0';
+
+ (void) printf("zdb_blkptr_cb: "
+ "Got error %d reading "
+ "<%llu, %llu, %lld, %llx> %s -- skipping\n",
+ ioerr,
+ (u_longlong_t)zb->zb_objset,
+ (u_longlong_t)zb->zb_object,
+ (u_longlong_t)zb->zb_level,
+ (u_longlong_t)zb->zb_blkid,
+ blkbuf);
+ }
+ mutex_exit(&spa->spa_scrub_lock);
+}
+
+/* ARGSUSED */
+static int
+zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+ const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+ zdb_cb_t *zcb = arg;
+ dmu_object_type_t type;
+ boolean_t is_metadata;
+
+ if (bp == NULL)
+ return (0);
+
+ if (dump_opt['b'] >= 5 && bp->blk_birth > 0) {
+ char blkbuf[BP_SPRINTF_LEN];
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+ (void) printf("objset %llu object %llu "
+ "level %lld offset 0x%llx %s\n",
+ (u_longlong_t)zb->zb_objset,
+ (u_longlong_t)zb->zb_object,
+ (longlong_t)zb->zb_level,
+ (u_longlong_t)blkid2offset(dnp, bp, zb),
+ blkbuf);
+ }
+
+ if (BP_IS_HOLE(bp))
+ return (0);
+
+ type = BP_GET_TYPE(bp);
+
+ zdb_count_block(zcb, zilog, bp,
+ (type & DMU_OT_NEWTYPE) ? ZDB_OT_OTHER : type);
+
+ is_metadata = (BP_GET_LEVEL(bp) != 0 || DMU_OT_IS_METADATA(type));
+
+ if (!BP_IS_EMBEDDED(bp) &&
+ (dump_opt['c'] > 1 || (dump_opt['c'] && is_metadata))) {
+ size_t size = BP_GET_PSIZE(bp);
+ abd_t *abd = abd_alloc(size, B_FALSE);
+ int flags = ZIO_FLAG_CANFAIL | ZIO_FLAG_SCRUB | ZIO_FLAG_RAW;
+
+ /* If it's an intent log block, failure is expected. */
+ if (zb->zb_level == ZB_ZIL_LEVEL)
+ flags |= ZIO_FLAG_SPECULATIVE;
+
+ mutex_enter(&spa->spa_scrub_lock);
+ while (spa->spa_load_verify_ios > max_inflight)
+ cv_wait(&spa->spa_scrub_io_cv, &spa->spa_scrub_lock);
+ spa->spa_scrub_inflight++;
+ spa->spa_load_verify_ios++;
+ mutex_exit(&spa->spa_scrub_lock);
+
+ zio_nowait(zio_read(NULL, spa, bp, abd, size,
+ zdb_blkptr_done, zcb, ZIO_PRIORITY_ASYNC_READ, flags, zb));
+ }
+
+ zcb->zcb_readfails = 0;
+
+ /* only call gethrtime() every 100 blocks */
+ static int iters;
+ if (++iters > 100)
+ iters = 0;
+ else
+ return (0);
+
+ if (dump_opt['b'] < 5 && gethrtime() > zcb->zcb_lastprint + NANOSEC) {
+ uint64_t now = gethrtime();
+ char buf[10];
+ uint64_t bytes = zcb->zcb_type[ZB_TOTAL][ZDB_OT_TOTAL].zb_asize;
+ int kb_per_sec =
+ 1 + bytes / (1 + ((now - zcb->zcb_start) / 1000 / 1000));
+ int sec_remaining =
+ (zcb->zcb_totalasize - bytes) / 1024 / kb_per_sec;
+
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (buf) >= NN_NUMBUF_SZ);
+
+ zfs_nicenum(bytes, buf, sizeof (buf));
+ (void) fprintf(stderr,
+ "\r%5s completed (%4dMB/s) "
+ "estimated time remaining: %uhr %02umin %02usec ",
+ buf, kb_per_sec / 1024,
+ sec_remaining / 60 / 60,
+ sec_remaining / 60 % 60,
+ sec_remaining % 60);
+
+ zcb->zcb_lastprint = now;
+ }
+
+ return (0);
+}
+
+static void
+zdb_leak(void *arg, uint64_t start, uint64_t size)
+{
+ vdev_t *vd = arg;
+
+ (void) printf("leaked space: vdev %llu, offset 0x%llx, size %llu\n",
+ (u_longlong_t)vd->vdev_id, (u_longlong_t)start, (u_longlong_t)size);
+}
+
+static metaslab_ops_t zdb_metaslab_ops = {
+ NULL /* alloc */
+};
+
+static void
+zdb_ddt_leak_init(spa_t *spa, zdb_cb_t *zcb)
+{
+ ddt_bookmark_t ddb;
+ ddt_entry_t dde;
+ int error;
+
+ bzero(&ddb, sizeof (ddb));
+ while ((error = ddt_walk(spa, &ddb, &dde)) == 0) {
+ blkptr_t blk;
+ ddt_phys_t *ddp = dde.dde_phys;
+
+ if (ddb.ddb_class == DDT_CLASS_UNIQUE)
+ return;
+
+ ASSERT(ddt_phys_total_refcnt(&dde) > 1);
+
+ for (int p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+ if (ddp->ddp_phys_birth == 0)
+ continue;
+ ddt_bp_create(ddb.ddb_checksum,
+ &dde.dde_key, ddp, &blk);
+ if (p == DDT_PHYS_DITTO) {
+ zdb_count_block(zcb, NULL, &blk, ZDB_OT_DITTO);
+ } else {
+ zcb->zcb_dedup_asize +=
+ BP_GET_ASIZE(&blk) * (ddp->ddp_refcnt - 1);
+ zcb->zcb_dedup_blocks++;
+ }
+ }
+ if (!dump_opt['L']) {
+ ddt_t *ddt = spa->spa_ddt[ddb.ddb_checksum];
+ ddt_enter(ddt);
+ VERIFY(ddt_lookup(ddt, &blk, B_TRUE) != NULL);
+ ddt_exit(ddt);
+ }
+ }
+
+ ASSERT(error == ENOENT);
+}
+
+/* ARGSUSED */
+static void
+claim_segment_impl_cb(uint64_t inner_offset, vdev_t *vd, uint64_t offset,
+ uint64_t size, void *arg)
+{
+ /*
+ * This callback was called through a remap from
+ * a device being removed. Therefore, the vdev that
+ * this callback is applied to is a concrete
+ * vdev.
+ */
+ ASSERT(vdev_is_concrete(vd));
+
+ VERIFY0(metaslab_claim_impl(vd, offset, size,
+ spa_min_claim_txg(vd->vdev_spa)));
+}
+
+static void
+claim_segment_cb(void *arg, uint64_t offset, uint64_t size)
+{
+ vdev_t *vd = arg;
+
+ vdev_indirect_ops.vdev_op_remap(vd, offset, size,
+ claim_segment_impl_cb, NULL);
+}
+
+/*
+ * After accounting for all allocated blocks that are directly referenced,
+ * we might have missed a reference to a block from a partially complete
+ * (and thus unused) indirect mapping object. We perform a secondary pass
+ * through the metaslabs we have already mapped and claim the destination
+ * blocks.
+ */
+static void
+zdb_claim_removing(spa_t *spa, zdb_cb_t *zcb)
+{
+ if (spa->spa_vdev_removal == NULL)
+ return;
+
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+
+ spa_vdev_removal_t *svr = spa->spa_vdev_removal;
+ vdev_t *vd = vdev_lookup_top(spa, svr->svr_vdev_id);
+ vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping;
+
+ for (uint64_t msi = 0; msi < vd->vdev_ms_count; msi++) {
+ metaslab_t *msp = vd->vdev_ms[msi];
+
+ if (msp->ms_start >= vdev_indirect_mapping_max_offset(vim))
+ break;
+
+ ASSERT0(range_tree_space(svr->svr_allocd_segs));
+
+ if (msp->ms_sm != NULL) {
+ VERIFY0(space_map_load(msp->ms_sm,
+ svr->svr_allocd_segs, SM_ALLOC));
+
+ /*
+ * Clear everything past what has been synced unless
+ * it's past the spacemap, because we have not allocated
+ * mappings for it yet.
+ */
+ uint64_t vim_max_offset =
+ vdev_indirect_mapping_max_offset(vim);
+ uint64_t sm_end = msp->ms_sm->sm_start +
+ msp->ms_sm->sm_size;
+ if (sm_end > vim_max_offset)
+ range_tree_clear(svr->svr_allocd_segs,
+ vim_max_offset, sm_end - vim_max_offset);
+ }
+
+ zcb->zcb_removing_size +=
+ range_tree_space(svr->svr_allocd_segs);
+ range_tree_vacate(svr->svr_allocd_segs, claim_segment_cb, vd);
+ }
+
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
+}
+
+/* ARGSUSED */
+static int
+increment_indirect_mapping_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+ zdb_cb_t *zcb = arg;
+ spa_t *spa = zcb->zcb_spa;
+ vdev_t *vd;
+ const dva_t *dva = &bp->blk_dva[0];
+
+ ASSERT(!dump_opt['L']);
+ ASSERT3U(BP_GET_NDVAS(bp), ==, 1);
+
+ spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+ vd = vdev_lookup_top(zcb->zcb_spa, DVA_GET_VDEV(dva));
+ ASSERT3P(vd, !=, NULL);
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+
+ ASSERT(vd->vdev_indirect_config.vic_mapping_object != 0);
+ ASSERT3P(zcb->zcb_vd_obsolete_counts[vd->vdev_id], !=, NULL);
+
+ vdev_indirect_mapping_increment_obsolete_count(
+ vd->vdev_indirect_mapping,
+ DVA_GET_OFFSET(dva), DVA_GET_ASIZE(dva),
+ zcb->zcb_vd_obsolete_counts[vd->vdev_id]);
+
+ return (0);
+}
+
+static uint32_t *
+zdb_load_obsolete_counts(vdev_t *vd)
+{
+ vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping;
+ spa_t *spa = vd->vdev_spa;
+ spa_condensing_indirect_phys_t *scip =
+ &spa->spa_condensing_indirect_phys;
+ uint32_t *counts;
+
+ EQUIV(vdev_obsolete_sm_object(vd) != 0, vd->vdev_obsolete_sm != NULL);
+ counts = vdev_indirect_mapping_load_obsolete_counts(vim);
+ if (vd->vdev_obsolete_sm != NULL) {
+ vdev_indirect_mapping_load_obsolete_spacemap(vim, counts,
+ vd->vdev_obsolete_sm);
+ }
+ if (scip->scip_vdev == vd->vdev_id &&
+ scip->scip_prev_obsolete_sm_object != 0) {
+ space_map_t *prev_obsolete_sm = NULL;
+ VERIFY0(space_map_open(&prev_obsolete_sm, spa->spa_meta_objset,
+ scip->scip_prev_obsolete_sm_object, 0, vd->vdev_asize, 0));
+ space_map_update(prev_obsolete_sm);
+ vdev_indirect_mapping_load_obsolete_spacemap(vim, counts,
+ prev_obsolete_sm);
+ space_map_close(prev_obsolete_sm);
+ }
+ return (counts);
+}
+
+typedef struct checkpoint_sm_exclude_entry_arg {
+ vdev_t *cseea_vd;
+ uint64_t cseea_checkpoint_size;
+} checkpoint_sm_exclude_entry_arg_t;
+
+static int
+checkpoint_sm_exclude_entry_cb(space_map_entry_t *sme, void *arg)
+{
+ checkpoint_sm_exclude_entry_arg_t *cseea = arg;
+ vdev_t *vd = cseea->cseea_vd;
+ metaslab_t *ms = vd->vdev_ms[sme->sme_offset >> vd->vdev_ms_shift];
+ uint64_t end = sme->sme_offset + sme->sme_run;
+
+ ASSERT(sme->sme_type == SM_FREE);
+
+ /*
+ * Since the vdev_checkpoint_sm exists in the vdev level
+ * and the ms_sm space maps exist in the metaslab level,
+ * an entry in the checkpoint space map could theoretically
+ * cross the boundaries of the metaslab that it belongs.
+ *
+ * In reality, because of the way that we populate and
+ * manipulate the checkpoint's space maps currently,
+ * there shouldn't be any entries that cross metaslabs.
+ * Hence the assertion below.
+ *
+ * That said, there is no fundamental requirement that
+ * the checkpoint's space map entries should not cross
+ * metaslab boundaries. So if needed we could add code
+ * that handles metaslab-crossing segments in the future.
+ */
+ VERIFY3U(sme->sme_offset, >=, ms->ms_start);
+ VERIFY3U(end, <=, ms->ms_start + ms->ms_size);
+
+ /*
+ * By removing the entry from the allocated segments we
+ * also verify that the entry is there to begin with.
+ */
+ mutex_enter(&ms->ms_lock);
+ range_tree_remove(ms->ms_allocatable, sme->sme_offset, sme->sme_run);
+ mutex_exit(&ms->ms_lock);
+
+ cseea->cseea_checkpoint_size += sme->sme_run;
+ return (0);
+}
+
+static void
+zdb_leak_init_vdev_exclude_checkpoint(vdev_t *vd, zdb_cb_t *zcb)
+{
+ spa_t *spa = vd->vdev_spa;
+ space_map_t *checkpoint_sm = NULL;
+ uint64_t checkpoint_sm_obj;
+
+ /*
+ * If there is no vdev_top_zap, we are in a pool whose
+ * version predates the pool checkpoint feature.
+ */
+ if (vd->vdev_top_zap == 0)
+ return;
+
+ /*
+ * If there is no reference of the vdev_checkpoint_sm in
+ * the vdev_top_zap, then one of the following scenarios
+ * is true:
+ *
+ * 1] There is no checkpoint
+ * 2] There is a checkpoint, but no checkpointed blocks
+ * have been freed yet
+ * 3] The current vdev is indirect
+ *
+ * In these cases we return immediately.
+ */
+ if (zap_contains(spa_meta_objset(spa), vd->vdev_top_zap,
+ VDEV_TOP_ZAP_POOL_CHECKPOINT_SM) != 0)
+ return;
+
+ VERIFY0(zap_lookup(spa_meta_objset(spa), vd->vdev_top_zap,
+ VDEV_TOP_ZAP_POOL_CHECKPOINT_SM, sizeof (uint64_t), 1,
+ &checkpoint_sm_obj));
+
+ checkpoint_sm_exclude_entry_arg_t cseea;
+ cseea.cseea_vd = vd;
+ cseea.cseea_checkpoint_size = 0;
+
+ VERIFY0(space_map_open(&checkpoint_sm, spa_meta_objset(spa),
+ checkpoint_sm_obj, 0, vd->vdev_asize, vd->vdev_ashift));
+ space_map_update(checkpoint_sm);
+
+ VERIFY0(space_map_iterate(checkpoint_sm,
+ checkpoint_sm_exclude_entry_cb, &cseea));
+ space_map_close(checkpoint_sm);
+
+ zcb->zcb_checkpoint_size += cseea.cseea_checkpoint_size;
+}
+
+static void
+zdb_leak_init_exclude_checkpoint(spa_t *spa, zdb_cb_t *zcb)
+{
+ vdev_t *rvd = spa->spa_root_vdev;
+ for (uint64_t c = 0; c < rvd->vdev_children; c++) {
+ ASSERT3U(c, ==, rvd->vdev_child[c]->vdev_id);
+ zdb_leak_init_vdev_exclude_checkpoint(rvd->vdev_child[c], zcb);
+ }
+}
+
+static void
+load_concrete_ms_allocatable_trees(spa_t *spa, maptype_t maptype)
+{
+ vdev_t *rvd = spa->spa_root_vdev;
+ for (uint64_t i = 0; i < rvd->vdev_children; i++) {
+ vdev_t *vd = rvd->vdev_child[i];
+
+ ASSERT3U(i, ==, vd->vdev_id);
+
+ if (vd->vdev_ops == &vdev_indirect_ops)
+ continue;
+
+ for (uint64_t m = 0; m < vd->vdev_ms_count; m++) {
+ metaslab_t *msp = vd->vdev_ms[m];
+
+ (void) fprintf(stderr,
+ "\rloading concrete vdev %llu, "
+ "metaslab %llu of %llu ...",
+ (longlong_t)vd->vdev_id,
+ (longlong_t)msp->ms_id,
+ (longlong_t)vd->vdev_ms_count);
+
+ mutex_enter(&msp->ms_lock);
+ metaslab_unload(msp);
+
+ /*
+ * We don't want to spend the CPU manipulating the
+ * size-ordered tree, so clear the range_tree ops.
+ */
+ msp->ms_allocatable->rt_ops = NULL;
+
+ if (msp->ms_sm != NULL) {
+ VERIFY0(space_map_load(msp->ms_sm,
+ msp->ms_allocatable, maptype));
+ }
+ if (!msp->ms_loaded)
+ msp->ms_loaded = B_TRUE;
+ mutex_exit(&msp->ms_lock);
+ }
+ }
+}
+
+/*
+ * vm_idxp is an in-out parameter which (for indirect vdevs) is the
+ * index in vim_entries that has the first entry in this metaslab.
+ * On return, it will be set to the first entry after this metaslab.
+ */
+static void
+load_indirect_ms_allocatable_tree(vdev_t *vd, metaslab_t *msp,
+ uint64_t *vim_idxp)
+{
+ vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping;
+
+ mutex_enter(&msp->ms_lock);
+ metaslab_unload(msp);
+
+ /*
+ * We don't want to spend the CPU manipulating the
+ * size-ordered tree, so clear the range_tree ops.
+ */
+ msp->ms_allocatable->rt_ops = NULL;
+
+ for (; *vim_idxp < vdev_indirect_mapping_num_entries(vim);
+ (*vim_idxp)++) {
+ vdev_indirect_mapping_entry_phys_t *vimep =
+ &vim->vim_entries[*vim_idxp];
+ uint64_t ent_offset = DVA_MAPPING_GET_SRC_OFFSET(vimep);
+ uint64_t ent_len = DVA_GET_ASIZE(&vimep->vimep_dst);
+ ASSERT3U(ent_offset, >=, msp->ms_start);
+ if (ent_offset >= msp->ms_start + msp->ms_size)
+ break;
+
+ /*
+ * Mappings do not cross metaslab boundaries,
+ * because we create them by walking the metaslabs.
+ */
+ ASSERT3U(ent_offset + ent_len, <=,
+ msp->ms_start + msp->ms_size);
+ range_tree_add(msp->ms_allocatable, ent_offset, ent_len);
+ }
+
+ if (!msp->ms_loaded)
+ msp->ms_loaded = B_TRUE;
+ mutex_exit(&msp->ms_lock);
+}
+
+static void
+zdb_leak_init_prepare_indirect_vdevs(spa_t *spa, zdb_cb_t *zcb)
+{
+ vdev_t *rvd = spa->spa_root_vdev;
+ for (uint64_t c = 0; c < rvd->vdev_children; c++) {
+ vdev_t *vd = rvd->vdev_child[c];
+
+ ASSERT3U(c, ==, vd->vdev_id);
+
+ if (vd->vdev_ops != &vdev_indirect_ops)
+ continue;
+
+ /*
+ * Note: we don't check for mapping leaks on
+ * removing vdevs because their ms_allocatable's
+ * are used to look for leaks in allocated space.
+ */
+ zcb->zcb_vd_obsolete_counts[c] = zdb_load_obsolete_counts(vd);
+
+ /*
+ * Normally, indirect vdevs don't have any
+ * metaslabs. We want to set them up for
+ * zio_claim().
+ */
+ VERIFY0(vdev_metaslab_init(vd, 0));
+
+ vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping;
+ uint64_t vim_idx = 0;
+ for (uint64_t m = 0; m < vd->vdev_ms_count; m++) {
+
+ (void) fprintf(stderr,
+ "\rloading indirect vdev %llu, "
+ "metaslab %llu of %llu ...",
+ (longlong_t)vd->vdev_id,
+ (longlong_t)vd->vdev_ms[m]->ms_id,
+ (longlong_t)vd->vdev_ms_count);
+
+ load_indirect_ms_allocatable_tree(vd, vd->vdev_ms[m],
+ &vim_idx);
+ }
+ ASSERT3U(vim_idx, ==, vdev_indirect_mapping_num_entries(vim));
+ }
+}
+
+static void
+zdb_leak_init(spa_t *spa, zdb_cb_t *zcb)
+{
+ zcb->zcb_spa = spa;
+
+ if (!dump_opt['L']) {
+ dsl_pool_t *dp = spa->spa_dsl_pool;
+ vdev_t *rvd = spa->spa_root_vdev;
+
+ /*
+ * We are going to be changing the meaning of the metaslab's
+ * ms_allocatable. Ensure that the allocator doesn't try to
+ * use the tree.
+ */
+ spa->spa_normal_class->mc_ops = &zdb_metaslab_ops;
+ spa->spa_log_class->mc_ops = &zdb_metaslab_ops;
+
+ zcb->zcb_vd_obsolete_counts =
+ umem_zalloc(rvd->vdev_children * sizeof (uint32_t *),
+ UMEM_NOFAIL);
+
+ /*
+ * For leak detection, we overload the ms_allocatable trees
+ * to contain allocated segments instead of free segments.
+ * As a result, we can't use the normal metaslab_load/unload
+ * interfaces.
+ */
+ zdb_leak_init_prepare_indirect_vdevs(spa, zcb);
+ load_concrete_ms_allocatable_trees(spa, SM_ALLOC);
+
+ /*
+ * On load_concrete_ms_allocatable_trees() we loaded all the
+ * allocated entries from the ms_sm to the ms_allocatable for
+ * each metaslab. If the pool has a checkpoint or is in the
+ * middle of discarding a checkpoint, some of these blocks
+ * may have been freed but their ms_sm may not have been
+ * updated because they are referenced by the checkpoint. In
+ * order to avoid false-positives during leak-detection, we
+ * go through the vdev's checkpoint space map and exclude all
+ * its entries from their relevant ms_allocatable.
+ *
+ * We also aggregate the space held by the checkpoint and add
+ * it to zcb_checkpoint_size.
+ *
+ * Note that at this point we are also verifying that all the
+ * entries on the checkpoint_sm are marked as allocated in
+ * the ms_sm of their relevant metaslab.
+ * [see comment in checkpoint_sm_exclude_entry_cb()]
+ */
+ zdb_leak_init_exclude_checkpoint(spa, zcb);
+
+ /* for cleaner progress output */
+ (void) fprintf(stderr, "\n");
+
+ if (bpobj_is_open(&dp->dp_obsolete_bpobj)) {
+ ASSERT(spa_feature_is_enabled(spa,
+ SPA_FEATURE_DEVICE_REMOVAL));
+ (void) bpobj_iterate_nofree(&dp->dp_obsolete_bpobj,
+ increment_indirect_mapping_cb, zcb, NULL);
+ }
+ } else {
+ /*
+ * If leak tracing is disabled, we still need to consider
+ * any checkpointed space in our space verification.
+ */
+ zcb->zcb_checkpoint_size += spa_get_checkpoint_space(spa);
+ }
+
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+ zdb_ddt_leak_init(spa, zcb);
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
+}
+
+static boolean_t
+zdb_check_for_obsolete_leaks(vdev_t *vd, zdb_cb_t *zcb)
+{
+ boolean_t leaks = B_FALSE;
+ vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping;
+ uint64_t total_leaked = 0;
+
+ ASSERT(vim != NULL);
+
+ for (uint64_t i = 0; i < vdev_indirect_mapping_num_entries(vim); i++) {
+ vdev_indirect_mapping_entry_phys_t *vimep =
+ &vim->vim_entries[i];
+ uint64_t obsolete_bytes = 0;
+ uint64_t offset = DVA_MAPPING_GET_SRC_OFFSET(vimep);
+ metaslab_t *msp = vd->vdev_ms[offset >> vd->vdev_ms_shift];
+
+ /*
+ * This is not very efficient but it's easy to
+ * verify correctness.
+ */
+ for (uint64_t inner_offset = 0;
+ inner_offset < DVA_GET_ASIZE(&vimep->vimep_dst);
+ inner_offset += 1 << vd->vdev_ashift) {
+ if (range_tree_contains(msp->ms_allocatable,
+ offset + inner_offset, 1 << vd->vdev_ashift)) {
+ obsolete_bytes += 1 << vd->vdev_ashift;
+ }
+ }
+
+ int64_t bytes_leaked = obsolete_bytes -
+ zcb->zcb_vd_obsolete_counts[vd->vdev_id][i];
+ ASSERT3U(DVA_GET_ASIZE(&vimep->vimep_dst), >=,
+ zcb->zcb_vd_obsolete_counts[vd->vdev_id][i]);
+ if (bytes_leaked != 0 &&
+ (vdev_obsolete_counts_are_precise(vd) ||
+ dump_opt['d'] >= 5)) {
+ (void) printf("obsolete indirect mapping count "
+ "mismatch on %llu:%llx:%llx : %llx bytes leaked\n",
+ (u_longlong_t)vd->vdev_id,
+ (u_longlong_t)DVA_MAPPING_GET_SRC_OFFSET(vimep),
+ (u_longlong_t)DVA_GET_ASIZE(&vimep->vimep_dst),
+ (u_longlong_t)bytes_leaked);
+ }
+ total_leaked += ABS(bytes_leaked);
+ }
+
+ if (!vdev_obsolete_counts_are_precise(vd) && total_leaked > 0) {
+ int pct_leaked = total_leaked * 100 /
+ vdev_indirect_mapping_bytes_mapped(vim);
+ (void) printf("cannot verify obsolete indirect mapping "
+ "counts of vdev %llu because precise feature was not "
+ "enabled when it was removed: %d%% (%llx bytes) of mapping"
+ "unreferenced\n",
+ (u_longlong_t)vd->vdev_id, pct_leaked,
+ (u_longlong_t)total_leaked);
+ } else if (total_leaked > 0) {
+ (void) printf("obsolete indirect mapping count mismatch "
+ "for vdev %llu -- %llx total bytes mismatched\n",
+ (u_longlong_t)vd->vdev_id,
+ (u_longlong_t)total_leaked);
+ leaks |= B_TRUE;
+ }
+
+ vdev_indirect_mapping_free_obsolete_counts(vim,
+ zcb->zcb_vd_obsolete_counts[vd->vdev_id]);
+ zcb->zcb_vd_obsolete_counts[vd->vdev_id] = NULL;
+
+ return (leaks);
+}
+
+static boolean_t
+zdb_leak_fini(spa_t *spa, zdb_cb_t *zcb)
+{
+ boolean_t leaks = B_FALSE;
+ if (!dump_opt['L']) {
+ vdev_t *rvd = spa->spa_root_vdev;
+ for (unsigned c = 0; c < rvd->vdev_children; c++) {
+ vdev_t *vd = rvd->vdev_child[c];
+ metaslab_group_t *mg = vd->vdev_mg;
+
+ if (zcb->zcb_vd_obsolete_counts[c] != NULL) {
+ leaks |= zdb_check_for_obsolete_leaks(vd, zcb);
+ }
+
+ for (uint64_t m = 0; m < vd->vdev_ms_count; m++) {
+ metaslab_t *msp = vd->vdev_ms[m];
+ ASSERT3P(mg, ==, msp->ms_group);
+
+ /*
+ * ms_allocatable has been overloaded
+ * to contain allocated segments. Now that
+ * we finished traversing all blocks, any
+ * block that remains in the ms_allocatable
+ * represents an allocated block that we
+ * did not claim during the traversal.
+ * Claimed blocks would have been removed
+ * from the ms_allocatable. For indirect
+ * vdevs, space remaining in the tree
+ * represents parts of the mapping that are
+ * not referenced, which is not a bug.
+ */
+ if (vd->vdev_ops == &vdev_indirect_ops) {
+ range_tree_vacate(msp->ms_allocatable,
+ NULL, NULL);
+ } else {
+ range_tree_vacate(msp->ms_allocatable,
+ zdb_leak, vd);
+ }
+
+ if (msp->ms_loaded) {
+ msp->ms_loaded = B_FALSE;
+ }
+ }
+ }
+
+ umem_free(zcb->zcb_vd_obsolete_counts,
+ rvd->vdev_children * sizeof (uint32_t *));
+ zcb->zcb_vd_obsolete_counts = NULL;
+ }
+ return (leaks);
+}
+
+/* ARGSUSED */
+static int
+count_block_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+ zdb_cb_t *zcb = arg;
+
+ if (dump_opt['b'] >= 5) {
+ char blkbuf[BP_SPRINTF_LEN];
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+ (void) printf("[%s] %s\n",
+ "deferred free", blkbuf);
+ }
+ zdb_count_block(zcb, NULL, bp, ZDB_OT_DEFERRED);
+ return (0);
+}
+
+static int
+dump_block_stats(spa_t *spa)
+{
+ zdb_cb_t zcb;
+ zdb_blkstats_t *zb, *tzb;
+ uint64_t norm_alloc, norm_space, total_alloc, total_found;
+ int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA | TRAVERSE_HARD;
+ boolean_t leaks = B_FALSE;
+ int err;
+
+ bzero(&zcb, sizeof (zcb));
+ (void) printf("\nTraversing all blocks %s%s%s%s%s...\n\n",
+ (dump_opt['c'] || !dump_opt['L']) ? "to verify " : "",
+ (dump_opt['c'] == 1) ? "metadata " : "",
+ dump_opt['c'] ? "checksums " : "",
+ (dump_opt['c'] && !dump_opt['L']) ? "and verify " : "",
+ !dump_opt['L'] ? "nothing leaked " : "");
+
+ /*
+ * Load all space maps as SM_ALLOC maps, then traverse the pool
+ * claiming each block we discover. If the pool is perfectly
+ * consistent, the space maps will be empty when we're done.
+ * Anything left over is a leak; any block we can't claim (because
+ * it's not part of any space map) is a double allocation,
+ * reference to a freed block, or an unclaimed log block.
+ */
+ zdb_leak_init(spa, &zcb);
+
+ /*
+ * If there's a deferred-free bplist, process that first.
+ */
+ (void) bpobj_iterate_nofree(&spa->spa_deferred_bpobj,
+ count_block_cb, &zcb, NULL);
+
+ if (spa_version(spa) >= SPA_VERSION_DEADLISTS) {
+ (void) bpobj_iterate_nofree(&spa->spa_dsl_pool->dp_free_bpobj,
+ count_block_cb, &zcb, NULL);
+ }
+
+ zdb_claim_removing(spa, &zcb);
+
+ if (spa_feature_is_active(spa, SPA_FEATURE_ASYNC_DESTROY)) {
+ VERIFY3U(0, ==, bptree_iterate(spa->spa_meta_objset,
+ spa->spa_dsl_pool->dp_bptree_obj, B_FALSE, count_block_cb,
+ &zcb, NULL));
+ }
+
+ if (dump_opt['c'] > 1)
+ flags |= TRAVERSE_PREFETCH_DATA;
+
+ zcb.zcb_totalasize = metaslab_class_get_alloc(spa_normal_class(spa));
+ zcb.zcb_totalasize += metaslab_class_get_alloc(spa_special_class(spa));
+ zcb.zcb_totalasize += metaslab_class_get_alloc(spa_dedup_class(spa));
+ zcb.zcb_start = zcb.zcb_lastprint = gethrtime();
+ err = traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
+
+ /*
+ * If we've traversed the data blocks then we need to wait for those
+ * I/Os to complete. We leverage "The Godfather" zio to wait on
+ * all async I/Os to complete.
+ */
+ if (dump_opt['c']) {
+ for (int i = 0; i < max_ncpus; i++) {
+ (void) zio_wait(spa->spa_async_zio_root[i]);
+ spa->spa_async_zio_root[i] = zio_root(spa, NULL, NULL,
+ ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE |
+ ZIO_FLAG_GODFATHER);
+ }
+ }
+
+ /*
+ * Done after zio_wait() since zcb_haderrors is modified in
+ * zdb_blkptr_done()
+ */
+ zcb.zcb_haderrors |= err;
+
+ if (zcb.zcb_haderrors) {
+ (void) printf("\nError counts:\n\n");
+ (void) printf("\t%5s %s\n", "errno", "count");
+ for (int e = 0; e < 256; e++) {
+ if (zcb.zcb_errors[e] != 0) {
+ (void) printf("\t%5d %llu\n",
+ e, (u_longlong_t)zcb.zcb_errors[e]);
+ }
+ }
+ }
+
+ /*
+ * Report any leaked segments.
+ */
+ leaks |= zdb_leak_fini(spa, &zcb);
+
+ tzb = &zcb.zcb_type[ZB_TOTAL][ZDB_OT_TOTAL];
+
+ norm_alloc = metaslab_class_get_alloc(spa_normal_class(spa));
+ norm_space = metaslab_class_get_space(spa_normal_class(spa));
+
+ total_alloc = norm_alloc +
+ metaslab_class_get_alloc(spa_log_class(spa)) +
+ metaslab_class_get_alloc(spa_special_class(spa)) +
+ metaslab_class_get_alloc(spa_dedup_class(spa));
+ total_found = tzb->zb_asize - zcb.zcb_dedup_asize +
+ zcb.zcb_removing_size + zcb.zcb_checkpoint_size;
+
+ if (total_found == total_alloc) {
+ if (!dump_opt['L'])
+ (void) printf("\n\tNo leaks (block sum matches space"
+ " maps exactly)\n");
+ } else {
+ (void) printf("block traversal size %llu != alloc %llu "
+ "(%s %lld)\n",
+ (u_longlong_t)total_found,
+ (u_longlong_t)total_alloc,
+ (dump_opt['L']) ? "unreachable" : "leaked",
+ (longlong_t)(total_alloc - total_found));
+ leaks = B_TRUE;
+ }
+
+ if (tzb->zb_count == 0)
+ return (2);
+
+ (void) printf("\n");
+ (void) printf("\t%-16s %14llu\n", "bp count:",
+ (u_longlong_t)tzb->zb_count);
+ (void) printf("\t%-16s %14llu\n", "ganged count:",
+ (longlong_t)tzb->zb_gangs);
+ (void) printf("\t%-16s %14llu avg: %6llu\n", "bp logical:",
+ (u_longlong_t)tzb->zb_lsize,
+ (u_longlong_t)(tzb->zb_lsize / tzb->zb_count));
+ (void) printf("\t%-16s %14llu avg: %6llu compression: %6.2f\n",
+ "bp physical:", (u_longlong_t)tzb->zb_psize,
+ (u_longlong_t)(tzb->zb_psize / tzb->zb_count),
+ (double)tzb->zb_lsize / tzb->zb_psize);
+ (void) printf("\t%-16s %14llu avg: %6llu compression: %6.2f\n",
+ "bp allocated:", (u_longlong_t)tzb->zb_asize,
+ (u_longlong_t)(tzb->zb_asize / tzb->zb_count),
+ (double)tzb->zb_lsize / tzb->zb_asize);
+ (void) printf("\t%-16s %14llu ref>1: %6llu deduplication: %6.2f\n",
+ "bp deduped:", (u_longlong_t)zcb.zcb_dedup_asize,
+ (u_longlong_t)zcb.zcb_dedup_blocks,
+ (double)zcb.zcb_dedup_asize / tzb->zb_asize + 1.0);
+ (void) printf("\t%-16s %14llu used: %5.2f%%\n", "Normal class:",
+ (u_longlong_t)norm_alloc, 100.0 * norm_alloc / norm_space);
+
+ if (spa_special_class(spa)->mc_rotor != NULL) {
+ uint64_t alloc = metaslab_class_get_alloc(
+ spa_special_class(spa));
+ uint64_t space = metaslab_class_get_space(
+ spa_special_class(spa));
+
+ (void) printf("\t%-16s %14llu used: %5.2f%%\n",
+ "Special class", (u_longlong_t)alloc,
+ 100.0 * alloc / space);
+ }
+
+ if (spa_dedup_class(spa)->mc_rotor != NULL) {
+ uint64_t alloc = metaslab_class_get_alloc(
+ spa_dedup_class(spa));
+ uint64_t space = metaslab_class_get_space(
+ spa_dedup_class(spa));
+
+ (void) printf("\t%-16s %14llu used: %5.2f%%\n",
+ "Dedup class", (u_longlong_t)alloc,
+ 100.0 * alloc / space);
+ }
+
+ for (bp_embedded_type_t i = 0; i < NUM_BP_EMBEDDED_TYPES; i++) {
+ if (zcb.zcb_embedded_blocks[i] == 0)
+ continue;
+ (void) printf("\n");
+ (void) printf("\tadditional, non-pointer bps of type %u: "
+ "%10llu\n",
+ i, (u_longlong_t)zcb.zcb_embedded_blocks[i]);
+
+ if (dump_opt['b'] >= 3) {
+ (void) printf("\t number of (compressed) bytes: "
+ "number of bps\n");
+ dump_histogram(zcb.zcb_embedded_histogram[i],
+ sizeof (zcb.zcb_embedded_histogram[i]) /
+ sizeof (zcb.zcb_embedded_histogram[i][0]), 0);
+ }
+ }
+
+ if (tzb->zb_ditto_samevdev != 0) {
+ (void) printf("\tDittoed blocks on same vdev: %llu\n",
+ (longlong_t)tzb->zb_ditto_samevdev);
+ }
+ if (tzb->zb_ditto_same_ms != 0) {
+ (void) printf("\tDittoed blocks in same metaslab: %llu\n",
+ (longlong_t)tzb->zb_ditto_same_ms);
+ }
+
+ for (uint64_t v = 0; v < spa->spa_root_vdev->vdev_children; v++) {
+ vdev_t *vd = spa->spa_root_vdev->vdev_child[v];
+ vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping;
+
+ if (vim == NULL) {
+ continue;
+ }
+
+ char mem[32];
+ zdb_nicenum(vdev_indirect_mapping_num_entries(vim),
+ mem, vdev_indirect_mapping_size(vim));
+
+ (void) printf("\tindirect vdev id %llu has %llu segments "
+ "(%s in memory)\n",
+ (longlong_t)vd->vdev_id,
+ (longlong_t)vdev_indirect_mapping_num_entries(vim), mem);
+ }
+
+ if (dump_opt['b'] >= 2) {
+ int l, t, level;
+ (void) printf("\nBlocks\tLSIZE\tPSIZE\tASIZE"
+ "\t avg\t comp\t%%Total\tType\n");
+
+ for (t = 0; t <= ZDB_OT_TOTAL; t++) {
+ char csize[32], lsize[32], psize[32], asize[32];
+ char avg[32], gang[32];
+ const char *typename;
+
+ /* make sure nicenum has enough space */
+ CTASSERT(sizeof (csize) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (lsize) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (psize) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (asize) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (avg) >= NN_NUMBUF_SZ);
+ CTASSERT(sizeof (gang) >= NN_NUMBUF_SZ);
+
+ if (t < DMU_OT_NUMTYPES)
+ typename = dmu_ot[t].ot_name;
+ else
+ typename = zdb_ot_extname[t - DMU_OT_NUMTYPES];
+
+ if (zcb.zcb_type[ZB_TOTAL][t].zb_asize == 0) {
+ (void) printf("%6s\t%5s\t%5s\t%5s"
+ "\t%5s\t%5s\t%6s\t%s\n",
+ "-",
+ "-",
+ "-",
+ "-",
+ "-",
+ "-",
+ "-",
+ typename);
+ continue;
+ }
+
+ for (l = ZB_TOTAL - 1; l >= -1; l--) {
+ level = (l == -1 ? ZB_TOTAL : l);
+ zb = &zcb.zcb_type[level][t];
+
+ if (zb->zb_asize == 0)
+ continue;
+
+ if (dump_opt['b'] < 3 && level != ZB_TOTAL)
+ continue;
+
+ if (level == 0 && zb->zb_asize ==
+ zcb.zcb_type[ZB_TOTAL][t].zb_asize)
+ continue;
+
+ zdb_nicenum(zb->zb_count, csize,
+ sizeof (csize));
+ zdb_nicenum(zb->zb_lsize, lsize,
+ sizeof (lsize));
+ zdb_nicenum(zb->zb_psize, psize,
+ sizeof (psize));
+ zdb_nicenum(zb->zb_asize, asize,
+ sizeof (asize));
+ zdb_nicenum(zb->zb_asize / zb->zb_count, avg,
+ sizeof (avg));
+ zdb_nicenum(zb->zb_gangs, gang, sizeof (gang));
+
+ (void) printf("%6s\t%5s\t%5s\t%5s\t%5s"
+ "\t%5.2f\t%6.2f\t",
+ csize, lsize, psize, asize, avg,
+ (double)zb->zb_lsize / zb->zb_psize,
+ 100.0 * zb->zb_asize / tzb->zb_asize);
+
+ if (level == ZB_TOTAL)
+ (void) printf("%s\n", typename);
+ else
+ (void) printf(" L%d %s\n",
+ level, typename);
+
+ if (dump_opt['b'] >= 3 && zb->zb_gangs > 0) {
+ (void) printf("\t number of ganged "
+ "blocks: %s\n", gang);
+ }
+
+ if (dump_opt['b'] >= 4) {
+ (void) printf("psize "
+ "(in 512-byte sectors): "
+ "number of blocks\n");
+ dump_histogram(zb->zb_psize_histogram,
+ PSIZE_HISTO_SIZE, 0);
+ }
+ }
+ }
+ }
+
+ (void) printf("\n");
+
+ if (leaks)
+ return (2);
+
+ if (zcb.zcb_haderrors)
+ return (3);
+
+ return (0);
+}
+
+typedef struct zdb_ddt_entry {
+ ddt_key_t zdde_key;
+ uint64_t zdde_ref_blocks;
+ uint64_t zdde_ref_lsize;
+ uint64_t zdde_ref_psize;
+ uint64_t zdde_ref_dsize;
+ avl_node_t zdde_node;
+} zdb_ddt_entry_t;
+
+/* ARGSUSED */
+static int
+zdb_ddt_add_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+ const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+ avl_tree_t *t = arg;
+ avl_index_t where;
+ zdb_ddt_entry_t *zdde, zdde_search;
+
+ if (bp == NULL || BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
+ return (0);
+
+ if (dump_opt['S'] > 1 && zb->zb_level == ZB_ROOT_LEVEL) {
+ (void) printf("traversing objset %llu, %llu objects, "
+ "%lu blocks so far\n",
+ (u_longlong_t)zb->zb_objset,
+ (u_longlong_t)BP_GET_FILL(bp),
+ avl_numnodes(t));
+ }
+
+ if (BP_IS_HOLE(bp) || BP_GET_CHECKSUM(bp) == ZIO_CHECKSUM_OFF ||
+ BP_GET_LEVEL(bp) > 0 || DMU_OT_IS_METADATA(BP_GET_TYPE(bp)))
+ return (0);
+
+ ddt_key_fill(&zdde_search.zdde_key, bp);
+
+ zdde = avl_find(t, &zdde_search, &where);
+
+ if (zdde == NULL) {
+ zdde = umem_zalloc(sizeof (*zdde), UMEM_NOFAIL);
+ zdde->zdde_key = zdde_search.zdde_key;
+ avl_insert(t, zdde, where);
+ }
+
+ zdde->zdde_ref_blocks += 1;
+ zdde->zdde_ref_lsize += BP_GET_LSIZE(bp);
+ zdde->zdde_ref_psize += BP_GET_PSIZE(bp);
+ zdde->zdde_ref_dsize += bp_get_dsize_sync(spa, bp);
+
+ return (0);
+}
+
+static void
+dump_simulated_ddt(spa_t *spa)
+{
+ avl_tree_t t;
+ void *cookie = NULL;
+ zdb_ddt_entry_t *zdde;
+ ddt_histogram_t ddh_total;
+ ddt_stat_t dds_total;
+
+ bzero(&ddh_total, sizeof (ddh_total));
+ bzero(&dds_total, sizeof (dds_total));
+ avl_create(&t, ddt_entry_compare,
+ sizeof (zdb_ddt_entry_t), offsetof(zdb_ddt_entry_t, zdde_node));
+
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+
+ (void) traverse_pool(spa, 0, TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA,
+ zdb_ddt_add_cb, &t);
+
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
+
+ while ((zdde = avl_destroy_nodes(&t, &cookie)) != NULL) {
+ ddt_stat_t dds;
+ uint64_t refcnt = zdde->zdde_ref_blocks;
+ ASSERT(refcnt != 0);
+
+ dds.dds_blocks = zdde->zdde_ref_blocks / refcnt;
+ dds.dds_lsize = zdde->zdde_ref_lsize / refcnt;
+ dds.dds_psize = zdde->zdde_ref_psize / refcnt;
+ dds.dds_dsize = zdde->zdde_ref_dsize / refcnt;
+
+ dds.dds_ref_blocks = zdde->zdde_ref_blocks;
+ dds.dds_ref_lsize = zdde->zdde_ref_lsize;
+ dds.dds_ref_psize = zdde->zdde_ref_psize;
+ dds.dds_ref_dsize = zdde->zdde_ref_dsize;
+
+ ddt_stat_add(&ddh_total.ddh_stat[highbit64(refcnt) - 1],
+ &dds, 0);
+
+ umem_free(zdde, sizeof (*zdde));
+ }
+
+ avl_destroy(&t);
+
+ ddt_histogram_stat(&dds_total, &ddh_total);
+
+ (void) printf("Simulated DDT histogram:\n");
+
+ zpool_dump_ddt(&dds_total, &ddh_total);
+
+ dump_dedup_ratio(&dds_total);
+}
+
+static int
+verify_device_removal_feature_counts(spa_t *spa)
+{
+ uint64_t dr_feature_refcount = 0;
+ uint64_t oc_feature_refcount = 0;
+ uint64_t indirect_vdev_count = 0;
+ uint64_t precise_vdev_count = 0;
+ uint64_t obsolete_counts_object_count = 0;
+ uint64_t obsolete_sm_count = 0;
+ uint64_t obsolete_counts_count = 0;
+ uint64_t scip_count = 0;
+ uint64_t obsolete_bpobj_count = 0;
+ int ret = 0;
+
+ spa_condensing_indirect_phys_t *scip =
+ &spa->spa_condensing_indirect_phys;
+ if (scip->scip_next_mapping_object != 0) {
+ vdev_t *vd = spa->spa_root_vdev->vdev_child[scip->scip_vdev];
+ ASSERT(scip->scip_prev_obsolete_sm_object != 0);
+ ASSERT3P(vd->vdev_ops, ==, &vdev_indirect_ops);
+
+ (void) printf("Condensing indirect vdev %llu: new mapping "
+ "object %llu, prev obsolete sm %llu\n",
+ (u_longlong_t)scip->scip_vdev,
+ (u_longlong_t)scip->scip_next_mapping_object,
+ (u_longlong_t)scip->scip_prev_obsolete_sm_object);
+ if (scip->scip_prev_obsolete_sm_object != 0) {
+ space_map_t *prev_obsolete_sm = NULL;
+ VERIFY0(space_map_open(&prev_obsolete_sm,
+ spa->spa_meta_objset,
+ scip->scip_prev_obsolete_sm_object,
+ 0, vd->vdev_asize, 0));
+ space_map_update(prev_obsolete_sm);
+ dump_spacemap(spa->spa_meta_objset, prev_obsolete_sm);
+ (void) printf("\n");
+ space_map_close(prev_obsolete_sm);
+ }
+
+ scip_count += 2;
+ }
+
+ for (uint64_t i = 0; i < spa->spa_root_vdev->vdev_children; i++) {
+ vdev_t *vd = spa->spa_root_vdev->vdev_child[i];
+ vdev_indirect_config_t *vic = &vd->vdev_indirect_config;
+
+ if (vic->vic_mapping_object != 0) {
+ ASSERT(vd->vdev_ops == &vdev_indirect_ops ||
+ vd->vdev_removing);
+ indirect_vdev_count++;
+
+ if (vd->vdev_indirect_mapping->vim_havecounts) {
+ obsolete_counts_count++;
+ }
+ }
+ if (vdev_obsolete_counts_are_precise(vd)) {
+ ASSERT(vic->vic_mapping_object != 0);
+ precise_vdev_count++;
+ }
+ if (vdev_obsolete_sm_object(vd) != 0) {
+ ASSERT(vic->vic_mapping_object != 0);
+ obsolete_sm_count++;
+ }
+ }
+
+ (void) feature_get_refcount(spa,
+ &spa_feature_table[SPA_FEATURE_DEVICE_REMOVAL],
+ &dr_feature_refcount);
+ (void) feature_get_refcount(spa,
+ &spa_feature_table[SPA_FEATURE_OBSOLETE_COUNTS],
+ &oc_feature_refcount);
+
+ if (dr_feature_refcount != indirect_vdev_count) {
+ ret = 1;
+ (void) printf("Number of indirect vdevs (%llu) " \
+ "does not match feature count (%llu)\n",
+ (u_longlong_t)indirect_vdev_count,
+ (u_longlong_t)dr_feature_refcount);
+ } else {
+ (void) printf("Verified device_removal feature refcount " \
+ "of %llu is correct\n",
+ (u_longlong_t)dr_feature_refcount);
+ }
+
+ if (zap_contains(spa_meta_objset(spa), DMU_POOL_DIRECTORY_OBJECT,
+ DMU_POOL_OBSOLETE_BPOBJ) == 0) {
+ obsolete_bpobj_count++;
+ }
+
+
+ obsolete_counts_object_count = precise_vdev_count;
+ obsolete_counts_object_count += obsolete_sm_count;
+ obsolete_counts_object_count += obsolete_counts_count;
+ obsolete_counts_object_count += scip_count;
+ obsolete_counts_object_count += obsolete_bpobj_count;
+ obsolete_counts_object_count += remap_deadlist_count;
+
+ if (oc_feature_refcount != obsolete_counts_object_count) {
+ ret = 1;
+ (void) printf("Number of obsolete counts objects (%llu) " \
+ "does not match feature count (%llu)\n",
+ (u_longlong_t)obsolete_counts_object_count,
+ (u_longlong_t)oc_feature_refcount);
+ (void) printf("pv:%llu os:%llu oc:%llu sc:%llu "
+ "ob:%llu rd:%llu\n",
+ (u_longlong_t)precise_vdev_count,
+ (u_longlong_t)obsolete_sm_count,
+ (u_longlong_t)obsolete_counts_count,
+ (u_longlong_t)scip_count,
+ (u_longlong_t)obsolete_bpobj_count,
+ (u_longlong_t)remap_deadlist_count);
+ } else {
+ (void) printf("Verified indirect_refcount feature refcount " \
+ "of %llu is correct\n",
+ (u_longlong_t)oc_feature_refcount);
+ }
+ return (ret);
+}
+
+static void
+zdb_set_skip_mmp(char *target)
+{
+ spa_t *spa;
+
+ /*
+ * Disable the activity check to allow examination of
+ * active pools.
+ */
+ mutex_enter(&spa_namespace_lock);
+ if ((spa = spa_lookup(target)) != NULL) {
+ spa->spa_import_flags |= ZFS_IMPORT_SKIP_MMP;
+ }
+ mutex_exit(&spa_namespace_lock);
+}
+
+#define BOGUS_SUFFIX "_CHECKPOINTED_UNIVERSE"
+/*
+ * Import the checkpointed state of the pool specified by the target
+ * parameter as readonly. The function also accepts a pool config
+ * as an optional parameter, else it attempts to infer the config by
+ * the name of the target pool.
+ *
+ * Note that the checkpointed state's pool name will be the name of
+ * the original pool with the above suffix appened to it. In addition,
+ * if the target is not a pool name (e.g. a path to a dataset) then
+ * the new_path parameter is populated with the updated path to
+ * reflect the fact that we are looking into the checkpointed state.
+ *
+ * The function returns a newly-allocated copy of the name of the
+ * pool containing the checkpointed state. When this copy is no
+ * longer needed it should be freed with free(3C). Same thing
+ * applies to the new_path parameter if allocated.
+ */
+static char *
+import_checkpointed_state(char *target, nvlist_t *cfg, char **new_path)
+{
+ int error = 0;
+ char *poolname, *bogus_name;
+
+ /* If the target is not a pool, the extract the pool name */
+ char *path_start = strchr(target, '/');
+ if (path_start != NULL) {
+ size_t poolname_len = path_start - target;
+ poolname = strndup(target, poolname_len);
+ } else {
+ poolname = target;
+ }
+
+ if (cfg == NULL) {
+ zdb_set_skip_mmp(poolname);
+ error = spa_get_stats(poolname, &cfg, NULL, 0);
+ if (error != 0) {
+ fatal("Tried to read config of pool \"%s\" but "
+ "spa_get_stats() failed with error %d\n",
+ poolname, error);
+ }
+ }
+
+ (void) asprintf(&bogus_name, "%s%s", poolname, BOGUS_SUFFIX);
+ fnvlist_add_string(cfg, ZPOOL_CONFIG_POOL_NAME, bogus_name);
+
+ error = spa_import(bogus_name, cfg, NULL,
+ ZFS_IMPORT_MISSING_LOG | ZFS_IMPORT_CHECKPOINT |
+ ZFS_IMPORT_SKIP_MMP);
+ if (error != 0) {
+ fatal("Tried to import pool \"%s\" but spa_import() failed "
+ "with error %d\n", bogus_name, error);
+ }
+
+ if (new_path != NULL && path_start != NULL)
+ (void) asprintf(new_path, "%s%s", bogus_name, path_start);
+
+ if (target != poolname)
+ free(poolname);
+
+ return (bogus_name);
+}
+
+typedef struct verify_checkpoint_sm_entry_cb_arg {
+ vdev_t *vcsec_vd;
+
+ /* the following fields are only used for printing progress */
+ uint64_t vcsec_entryid;
+ uint64_t vcsec_num_entries;
+} verify_checkpoint_sm_entry_cb_arg_t;
+
+#define ENTRIES_PER_PROGRESS_UPDATE 10000
+
+static int
+verify_checkpoint_sm_entry_cb(space_map_entry_t *sme, void *arg)
+{
+ verify_checkpoint_sm_entry_cb_arg_t *vcsec = arg;
+ vdev_t *vd = vcsec->vcsec_vd;
+ metaslab_t *ms = vd->vdev_ms[sme->sme_offset >> vd->vdev_ms_shift];
+ uint64_t end = sme->sme_offset + sme->sme_run;
+
+ ASSERT(sme->sme_type == SM_FREE);
+
+ if ((vcsec->vcsec_entryid % ENTRIES_PER_PROGRESS_UPDATE) == 0) {
+ (void) fprintf(stderr,
+ "\rverifying vdev %llu, space map entry %llu of %llu ...",
+ (longlong_t)vd->vdev_id,
+ (longlong_t)vcsec->vcsec_entryid,
+ (longlong_t)vcsec->vcsec_num_entries);
+ }
+ vcsec->vcsec_entryid++;
+
+ /*
+ * See comment in checkpoint_sm_exclude_entry_cb()
+ */
+ VERIFY3U(sme->sme_offset, >=, ms->ms_start);
+ VERIFY3U(end, <=, ms->ms_start + ms->ms_size);
+
+ /*
+ * The entries in the vdev_checkpoint_sm should be marked as
+ * allocated in the checkpointed state of the pool, therefore
+ * their respective ms_allocateable trees should not contain them.
+ */
+ mutex_enter(&ms->ms_lock);
+ range_tree_verify(ms->ms_allocatable, sme->sme_offset, sme->sme_run);
+ mutex_exit(&ms->ms_lock);
+
+ return (0);
+}
+
+/*
+ * Verify that all segments in the vdev_checkpoint_sm are allocated
+ * according to the checkpoint's ms_sm (i.e. are not in the checkpoint's
+ * ms_allocatable).
+ *
+ * Do so by comparing the checkpoint space maps (vdev_checkpoint_sm) of
+ * each vdev in the current state of the pool to the metaslab space maps
+ * (ms_sm) of the checkpointed state of the pool.
+ *
+ * Note that the function changes the state of the ms_allocatable
+ * trees of the current spa_t. The entries of these ms_allocatable
+ * trees are cleared out and then repopulated from with the free
+ * entries of their respective ms_sm space maps.
+ */
+static void
+verify_checkpoint_vdev_spacemaps(spa_t *checkpoint, spa_t *current)
+{
+ vdev_t *ckpoint_rvd = checkpoint->spa_root_vdev;
+ vdev_t *current_rvd = current->spa_root_vdev;
+
+ load_concrete_ms_allocatable_trees(checkpoint, SM_FREE);
+
+ for (uint64_t c = 0; c < ckpoint_rvd->vdev_children; c++) {
+ vdev_t *ckpoint_vd = ckpoint_rvd->vdev_child[c];
+ vdev_t *current_vd = current_rvd->vdev_child[c];
+
+ space_map_t *checkpoint_sm = NULL;
+ uint64_t checkpoint_sm_obj;
+
+ if (ckpoint_vd->vdev_ops == &vdev_indirect_ops) {
+ /*
+ * Since we don't allow device removal in a pool
+ * that has a checkpoint, we expect that all removed
+ * vdevs were removed from the pool before the
+ * checkpoint.
+ */
+ ASSERT3P(current_vd->vdev_ops, ==, &vdev_indirect_ops);
+ continue;
+ }
+
+ /*
+ * If the checkpoint space map doesn't exist, then nothing
+ * here is checkpointed so there's nothing to verify.
+ */
+ if (current_vd->vdev_top_zap == 0 ||
+ zap_contains(spa_meta_objset(current),
+ current_vd->vdev_top_zap,
+ VDEV_TOP_ZAP_POOL_CHECKPOINT_SM) != 0)
+ continue;
+
+ VERIFY0(zap_lookup(spa_meta_objset(current),
+ current_vd->vdev_top_zap, VDEV_TOP_ZAP_POOL_CHECKPOINT_SM,
+ sizeof (uint64_t), 1, &checkpoint_sm_obj));
+
+ VERIFY0(space_map_open(&checkpoint_sm, spa_meta_objset(current),
+ checkpoint_sm_obj, 0, current_vd->vdev_asize,
+ current_vd->vdev_ashift));
+ space_map_update(checkpoint_sm);
+
+ verify_checkpoint_sm_entry_cb_arg_t vcsec;
+ vcsec.vcsec_vd = ckpoint_vd;
+ vcsec.vcsec_entryid = 0;
+ vcsec.vcsec_num_entries =
+ space_map_length(checkpoint_sm) / sizeof (uint64_t);
+ VERIFY0(space_map_iterate(checkpoint_sm,
+ verify_checkpoint_sm_entry_cb, &vcsec));
+ dump_spacemap(current->spa_meta_objset, checkpoint_sm);
+ space_map_close(checkpoint_sm);
+ }
+
+ /*
+ * If we've added vdevs since we took the checkpoint, ensure
+ * that their checkpoint space maps are empty.
+ */
+ if (ckpoint_rvd->vdev_children < current_rvd->vdev_children) {
+ for (uint64_t c = ckpoint_rvd->vdev_children;
+ c < current_rvd->vdev_children; c++) {
+ vdev_t *current_vd = current_rvd->vdev_child[c];
+ ASSERT3P(current_vd->vdev_checkpoint_sm, ==, NULL);
+ }
+ }
+
+ /* for cleaner progress output */
+ (void) fprintf(stderr, "\n");
+}
+
+/*
+ * Verifies that all space that's allocated in the checkpoint is
+ * still allocated in the current version, by checking that everything
+ * in checkpoint's ms_allocatable (which is actually allocated, not
+ * allocatable/free) is not present in current's ms_allocatable.
+ *
+ * Note that the function changes the state of the ms_allocatable
+ * trees of both spas when called. The entries of all ms_allocatable
+ * trees are cleared out and then repopulated from their respective
+ * ms_sm space maps. In the checkpointed state we load the allocated
+ * entries, and in the current state we load the free entries.
+ */
+static void
+verify_checkpoint_ms_spacemaps(spa_t *checkpoint, spa_t *current)
+{
+ vdev_t *ckpoint_rvd = checkpoint->spa_root_vdev;
+ vdev_t *current_rvd = current->spa_root_vdev;
+
+ load_concrete_ms_allocatable_trees(checkpoint, SM_ALLOC);
+ load_concrete_ms_allocatable_trees(current, SM_FREE);
+
+ for (uint64_t i = 0; i < ckpoint_rvd->vdev_children; i++) {
+ vdev_t *ckpoint_vd = ckpoint_rvd->vdev_child[i];
+ vdev_t *current_vd = current_rvd->vdev_child[i];
+
+ if (ckpoint_vd->vdev_ops == &vdev_indirect_ops) {
+ /*
+ * See comment in verify_checkpoint_vdev_spacemaps()
+ */
+ ASSERT3P(current_vd->vdev_ops, ==, &vdev_indirect_ops);
+ continue;
+ }
+
+ for (uint64_t m = 0; m < ckpoint_vd->vdev_ms_count; m++) {
+ metaslab_t *ckpoint_msp = ckpoint_vd->vdev_ms[m];
+ metaslab_t *current_msp = current_vd->vdev_ms[m];
+
+ (void) fprintf(stderr,
+ "\rverifying vdev %llu of %llu, "
+ "metaslab %llu of %llu ...",
+ (longlong_t)current_vd->vdev_id,
+ (longlong_t)current_rvd->vdev_children,
+ (longlong_t)current_vd->vdev_ms[m]->ms_id,
+ (longlong_t)current_vd->vdev_ms_count);
+
+ /*
+ * We walk through the ms_allocatable trees that
+ * are loaded with the allocated blocks from the
+ * ms_sm spacemaps of the checkpoint. For each
+ * one of these ranges we ensure that none of them
+ * exists in the ms_allocatable trees of the
+ * current state which are loaded with the ranges
+ * that are currently free.
+ *
+ * This way we ensure that none of the blocks that
+ * are part of the checkpoint were freed by mistake.
+ */
+ range_tree_walk(ckpoint_msp->ms_allocatable,
+ (range_tree_func_t *)range_tree_verify,
+ current_msp->ms_allocatable);
+ }
+ }
+
+ /* for cleaner progress output */
+ (void) fprintf(stderr, "\n");
+}
+
+static void
+verify_checkpoint_blocks(spa_t *spa)
+{
+ spa_t *checkpoint_spa;
+ char *checkpoint_pool;
+ nvlist_t *config = NULL;
+ int error = 0;
+
+ /*
+ * We import the checkpointed state of the pool (under a different
+ * name) so we can do verification on it against the current state
+ * of the pool.
+ */
+ checkpoint_pool = import_checkpointed_state(spa->spa_name, config,
+ NULL);
+ ASSERT(strcmp(spa->spa_name, checkpoint_pool) != 0);
+
+ error = spa_open(checkpoint_pool, &checkpoint_spa, FTAG);
+ if (error != 0) {
+ fatal("Tried to open pool \"%s\" but spa_open() failed with "
+ "error %d\n", checkpoint_pool, error);
+ }
+
+ /*
+ * Ensure that ranges in the checkpoint space maps of each vdev
+ * are allocated according to the checkpointed state's metaslab
+ * space maps.
+ */
+ verify_checkpoint_vdev_spacemaps(checkpoint_spa, spa);
+
+ /*
+ * Ensure that allocated ranges in the checkpoint's metaslab
+ * space maps remain allocated in the metaslab space maps of
+ * the current state.
+ */
+ verify_checkpoint_ms_spacemaps(checkpoint_spa, spa);
+
+ /*
+ * Once we are done, we get rid of the checkpointed state.
+ */
+ spa_close(checkpoint_spa, FTAG);
+ free(checkpoint_pool);
+}
+
+static void
+dump_leftover_checkpoint_blocks(spa_t *spa)
+{
+ vdev_t *rvd = spa->spa_root_vdev;
+
+ for (uint64_t i = 0; i < rvd->vdev_children; i++) {
+ vdev_t *vd = rvd->vdev_child[i];
+
+ space_map_t *checkpoint_sm = NULL;
+ uint64_t checkpoint_sm_obj;
+
+ if (vd->vdev_top_zap == 0)
+ continue;
+
+ if (zap_contains(spa_meta_objset(spa), vd->vdev_top_zap,
+ VDEV_TOP_ZAP_POOL_CHECKPOINT_SM) != 0)
+ continue;
+
+ VERIFY0(zap_lookup(spa_meta_objset(spa), vd->vdev_top_zap,
+ VDEV_TOP_ZAP_POOL_CHECKPOINT_SM,
+ sizeof (uint64_t), 1, &checkpoint_sm_obj));
+
+ VERIFY0(space_map_open(&checkpoint_sm, spa_meta_objset(spa),
+ checkpoint_sm_obj, 0, vd->vdev_asize, vd->vdev_ashift));
+ space_map_update(checkpoint_sm);
+ dump_spacemap(spa->spa_meta_objset, checkpoint_sm);
+ space_map_close(checkpoint_sm);
+ }
+}
+
+static int
+verify_checkpoint(spa_t *spa)
+{
+ uberblock_t checkpoint;
+ int error;
+
+ if (!spa_feature_is_active(spa, SPA_FEATURE_POOL_CHECKPOINT))
+ return (0);
+
+ error = zap_lookup(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+ DMU_POOL_ZPOOL_CHECKPOINT, sizeof (uint64_t),
+ sizeof (uberblock_t) / sizeof (uint64_t), &checkpoint);
+
+ if (error == ENOENT && !dump_opt['L']) {
+ /*
+ * If the feature is active but the uberblock is missing
+ * then we must be in the middle of discarding the
+ * checkpoint.
+ */
+ (void) printf("\nPartially discarded checkpoint "
+ "state found:\n");
+ dump_leftover_checkpoint_blocks(spa);
+ return (0);
+ } else if (error != 0) {
+ (void) printf("lookup error %d when looking for "
+ "checkpointed uberblock in MOS\n", error);
+ return (error);
+ }
+ dump_uberblock(&checkpoint, "\nCheckpointed uberblock found:\n", "\n");
+
+ if (checkpoint.ub_checkpoint_txg == 0) {
+ (void) printf("\nub_checkpoint_txg not set in checkpointed "
+ "uberblock\n");
+ error = 3;
+ }
+
+ if (error == 0 && !dump_opt['L'])
+ verify_checkpoint_blocks(spa);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static void
+mos_leaks_cb(void *arg, uint64_t start, uint64_t size)
+{
+ for (uint64_t i = start; i < size; i++) {
+ (void) printf("MOS object %llu referenced but not allocated\n",
+ (u_longlong_t)i);
+ }
+}
+
+static range_tree_t *mos_refd_objs;
+
+static void
+mos_obj_refd(uint64_t obj)
+{
+ if (obj != 0 && mos_refd_objs != NULL)
+ range_tree_add(mos_refd_objs, obj, 1);
+}
+
+static void
+mos_leak_vdev(vdev_t *vd)
+{
+ mos_obj_refd(vd->vdev_dtl_object);
+ mos_obj_refd(vd->vdev_ms_array);
+ mos_obj_refd(vd->vdev_top_zap);
+ mos_obj_refd(vd->vdev_indirect_config.vic_births_object);
+ mos_obj_refd(vd->vdev_indirect_config.vic_mapping_object);
+ mos_obj_refd(vd->vdev_leaf_zap);
+ if (vd->vdev_checkpoint_sm != NULL)
+ mos_obj_refd(vd->vdev_checkpoint_sm->sm_object);
+ if (vd->vdev_indirect_mapping != NULL) {
+ mos_obj_refd(vd->vdev_indirect_mapping->
+ vim_phys->vimp_counts_object);
+ }
+ if (vd->vdev_obsolete_sm != NULL)
+ mos_obj_refd(vd->vdev_obsolete_sm->sm_object);
+
+ for (uint64_t m = 0; m < vd->vdev_ms_count; m++) {
+ metaslab_t *ms = vd->vdev_ms[m];
+ mos_obj_refd(space_map_object(ms->ms_sm));
+ }
+
+ for (uint64_t c = 0; c < vd->vdev_children; c++) {
+ mos_leak_vdev(vd->vdev_child[c]);
+ }
+}
+
+static int
+dump_mos_leaks(spa_t *spa)
+{
+ int rv = 0;
+ objset_t *mos = spa->spa_meta_objset;
+ dsl_pool_t *dp = spa->spa_dsl_pool;
+
+ /* Visit and mark all referenced objects in the MOS */
+
+ mos_obj_refd(DMU_POOL_DIRECTORY_OBJECT);
+ mos_obj_refd(spa->spa_pool_props_object);
+ mos_obj_refd(spa->spa_config_object);
+ mos_obj_refd(spa->spa_ddt_stat_object);
+ mos_obj_refd(spa->spa_feat_desc_obj);
+ mos_obj_refd(spa->spa_feat_enabled_txg_obj);
+ mos_obj_refd(spa->spa_feat_for_read_obj);
+ mos_obj_refd(spa->spa_feat_for_write_obj);
+ mos_obj_refd(spa->spa_history);
+ mos_obj_refd(spa->spa_errlog_last);
+ mos_obj_refd(spa->spa_errlog_scrub);
+ mos_obj_refd(spa->spa_all_vdev_zaps);
+ mos_obj_refd(spa->spa_dsl_pool->dp_bptree_obj);
+ mos_obj_refd(spa->spa_dsl_pool->dp_tmp_userrefs_obj);
+ mos_obj_refd(spa->spa_dsl_pool->dp_scan->scn_phys.scn_queue_obj);
+ bpobj_count_refd(&spa->spa_deferred_bpobj);
+ mos_obj_refd(dp->dp_empty_bpobj);
+ bpobj_count_refd(&dp->dp_obsolete_bpobj);
+ bpobj_count_refd(&dp->dp_free_bpobj);
+ mos_obj_refd(spa->spa_l2cache.sav_object);
+ mos_obj_refd(spa->spa_spares.sav_object);
+
+ mos_obj_refd(spa->spa_condensing_indirect_phys.
+ scip_next_mapping_object);
+ mos_obj_refd(spa->spa_condensing_indirect_phys.
+ scip_prev_obsolete_sm_object);
+ if (spa->spa_condensing_indirect_phys.scip_next_mapping_object != 0) {
+ vdev_indirect_mapping_t *vim =
+ vdev_indirect_mapping_open(mos,
+ spa->spa_condensing_indirect_phys.scip_next_mapping_object);
+ mos_obj_refd(vim->vim_phys->vimp_counts_object);
+ vdev_indirect_mapping_close(vim);
+ }
+
+ if (dp->dp_origin_snap != NULL) {
+ dsl_dataset_t *ds;
+
+ dsl_pool_config_enter(dp, FTAG);
+ VERIFY0(dsl_dataset_hold_obj(dp,
+ dsl_dataset_phys(dp->dp_origin_snap)->ds_next_snap_obj,
+ FTAG, &ds));
+ count_ds_mos_objects(ds);
+ dump_deadlist(&ds->ds_deadlist);
+ dsl_dataset_rele(ds, FTAG);
+ dsl_pool_config_exit(dp, FTAG);
+
+ count_ds_mos_objects(dp->dp_origin_snap);
+ dump_deadlist(&dp->dp_origin_snap->ds_deadlist);
+ }
+ count_dir_mos_objects(dp->dp_mos_dir);
+ if (dp->dp_free_dir != NULL)
+ count_dir_mos_objects(dp->dp_free_dir);
+ if (dp->dp_leak_dir != NULL)
+ count_dir_mos_objects(dp->dp_leak_dir);
+
+ mos_leak_vdev(spa->spa_root_vdev);
+
+ for (uint64_t class = 0; class < DDT_CLASSES; class++) {
+ for (uint64_t type = 0; type < DDT_TYPES; type++) {
+ for (uint64_t cksum = 0;
+ cksum < ZIO_CHECKSUM_FUNCTIONS; cksum++) {
+ ddt_t *ddt = spa->spa_ddt[cksum];
+ mos_obj_refd(ddt->ddt_object[type][class]);
+ }
+ }
+ }
+
+ /*
+ * Visit all allocated objects and make sure they are referenced.
+ */
+ uint64_t object = 0;
+ while (dmu_object_next(mos, &object, B_FALSE, 0) == 0) {
+ if (range_tree_contains(mos_refd_objs, object, 1)) {
+ range_tree_remove(mos_refd_objs, object, 1);
+ } else {
+ dmu_object_info_t doi;
+ const char *name;
+ dmu_object_info(mos, object, &doi);
+ if (doi.doi_type & DMU_OT_NEWTYPE) {
+ dmu_object_byteswap_t bswap =
+ DMU_OT_BYTESWAP(doi.doi_type);
+ name = dmu_ot_byteswap[bswap].ob_name;
+ } else {
+ name = dmu_ot[doi.doi_type].ot_name;
+ }
+
+ (void) printf("MOS object %llu (%s) leaked\n",
+ (u_longlong_t)object, name);
+ rv = 2;
+ }
+ }
+ (void) range_tree_walk(mos_refd_objs, mos_leaks_cb, NULL);
+ if (!range_tree_is_empty(mos_refd_objs))
+ rv = 2;
+ range_tree_vacate(mos_refd_objs, NULL, NULL);
+ range_tree_destroy(mos_refd_objs);
+ return (rv);
+}
+
+static void
+dump_zpool(spa_t *spa)
+{
+ dsl_pool_t *dp = spa_get_dsl(spa);
+ int rc = 0;
+
+ if (dump_opt['S']) {
+ dump_simulated_ddt(spa);
+ return;
+ }
+
+ if (!dump_opt['e'] && dump_opt['C'] > 1) {
+ (void) printf("\nCached configuration:\n");
+ dump_nvlist(spa->spa_config, 8);
+ }
+
+ if (dump_opt['C'])
+ dump_config(spa);
+
+ if (dump_opt['u'])
+ dump_uberblock(&spa->spa_uberblock, "\nUberblock:\n", "\n");
+
+ if (dump_opt['D'])
+ dump_all_ddts(spa);
+
+ if (dump_opt['d'] > 2 || dump_opt['m'])
+ dump_metaslabs(spa);
+ if (dump_opt['M'])
+ dump_metaslab_groups(spa);
+
+ if (dump_opt['d'] || dump_opt['i']) {
+ mos_refd_objs = range_tree_create(NULL, NULL);
+ dump_dir(dp->dp_meta_objset);
+
+ if (dump_opt['d'] >= 3) {
+ dsl_pool_t *dp = spa->spa_dsl_pool;
+ dump_full_bpobj(&spa->spa_deferred_bpobj,
+ "Deferred frees", 0);
+ if (spa_version(spa) >= SPA_VERSION_DEADLISTS) {
+ dump_full_bpobj(&dp->dp_free_bpobj,
+ "Pool snapshot frees", 0);
+ }
+ if (bpobj_is_open(&dp->dp_obsolete_bpobj)) {
+ ASSERT(spa_feature_is_enabled(spa,
+ SPA_FEATURE_DEVICE_REMOVAL));
+ dump_full_bpobj(&dp->dp_obsolete_bpobj,
+ "Pool obsolete blocks", 0);
+ }
+
+ if (spa_feature_is_active(spa,
+ SPA_FEATURE_ASYNC_DESTROY)) {
+ dump_bptree(spa->spa_meta_objset,
+ dp->dp_bptree_obj,
+ "Pool dataset frees");
+ }
+ dump_dtl(spa->spa_root_vdev, 0);
+ }
+ (void) dmu_objset_find(spa_name(spa), dump_one_dir,
+ NULL, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
+
+ if (rc == 0 && !dump_opt['L'])
+ rc = dump_mos_leaks(spa);
+
+ for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
+ uint64_t refcount;
+
+ if (!(spa_feature_table[f].fi_flags &
+ ZFEATURE_FLAG_PER_DATASET)) {
+ ASSERT0(dataset_feature_count[f]);
+ continue;
+ }
+ (void) feature_get_refcount(spa,
+ &spa_feature_table[f], &refcount);
+ if (dataset_feature_count[f] != refcount) {
+ (void) printf("%s feature refcount mismatch: "
+ "%lld datasets != %lld refcount\n",
+ spa_feature_table[f].fi_uname,
+ (longlong_t)dataset_feature_count[f],
+ (longlong_t)refcount);
+ rc = 2;
+ } else {
+ (void) printf("Verified %s feature refcount "
+ "of %llu is correct\n",
+ spa_feature_table[f].fi_uname,
+ (longlong_t)refcount);
+ }
+ }
+
+ if (rc == 0) {
+ rc = verify_device_removal_feature_counts(spa);
+ }
+ }
+
+ if (rc == 0 && (dump_opt['b'] || dump_opt['c']))
+ rc = dump_block_stats(spa);
+
+ if (rc == 0)
+ rc = verify_spacemap_refcounts(spa);
+
+ if (dump_opt['s'])
+ show_pool_stats(spa);
+
+ if (dump_opt['h'])
+ dump_history(spa);
+
+ if (rc == 0)
+ rc = verify_checkpoint(spa);
+
+ if (rc != 0) {
+ dump_debug_buffer();
+ exit(rc);
+ }
+}
+
+#define ZDB_FLAG_CHECKSUM 0x0001
+#define ZDB_FLAG_DECOMPRESS 0x0002
+#define ZDB_FLAG_BSWAP 0x0004
+#define ZDB_FLAG_GBH 0x0008
+#define ZDB_FLAG_INDIRECT 0x0010
+#define ZDB_FLAG_PHYS 0x0020
+#define ZDB_FLAG_RAW 0x0040
+#define ZDB_FLAG_PRINT_BLKPTR 0x0080
+
+static int flagbits[256];
+
+static void
+zdb_print_blkptr(blkptr_t *bp, int flags)
+{
+ char blkbuf[BP_SPRINTF_LEN];
+
+ if (flags & ZDB_FLAG_BSWAP)
+ byteswap_uint64_array((void *)bp, sizeof (blkptr_t));
+
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+ (void) printf("%s\n", blkbuf);
+}
+
+static void
+zdb_dump_indirect(blkptr_t *bp, int nbps, int flags)
+{
+ int i;
+
+ for (i = 0; i < nbps; i++)
+ zdb_print_blkptr(&bp[i], flags);
+}
+
+static void
+zdb_dump_gbh(void *buf, int flags)
+{
+ zdb_dump_indirect((blkptr_t *)buf, SPA_GBH_NBLKPTRS, flags);
+}
+
+static void
+zdb_dump_block_raw(void *buf, uint64_t size, int flags)
+{
+ if (flags & ZDB_FLAG_BSWAP)
+ byteswap_uint64_array(buf, size);
+ (void) write(1, buf, size);
+}
+
+static void
+zdb_dump_block(char *label, void *buf, uint64_t size, int flags)
+{
+ uint64_t *d = (uint64_t *)buf;
+ unsigned nwords = size / sizeof (uint64_t);
+ int do_bswap = !!(flags & ZDB_FLAG_BSWAP);
+ unsigned i, j;
+ const char *hdr;
+ char *c;
+
+
+ if (do_bswap)
+ hdr = " 7 6 5 4 3 2 1 0 f e d c b a 9 8";
+ else
+ hdr = " 0 1 2 3 4 5 6 7 8 9 a b c d e f";
+
+ (void) printf("\n%s\n%6s %s 0123456789abcdef\n", label, "", hdr);
+
+ for (i = 0; i < nwords; i += 2) {
+ (void) printf("%06llx: %016llx %016llx ",
+ (u_longlong_t)(i * sizeof (uint64_t)),
+ (u_longlong_t)(do_bswap ? BSWAP_64(d[i]) : d[i]),
+ (u_longlong_t)(do_bswap ? BSWAP_64(d[i + 1]) : d[i + 1]));
+
+ c = (char *)&d[i];
+ for (j = 0; j < 2 * sizeof (uint64_t); j++)
+ (void) printf("%c", isprint(c[j]) ? c[j] : '.');
+ (void) printf("\n");
+ }
+}
+
+/*
+ * There are two acceptable formats:
+ * leaf_name - For example: c1t0d0 or /tmp/ztest.0a
+ * child[.child]* - For example: 0.1.1
+ *
+ * The second form can be used to specify arbitrary vdevs anywhere
+ * in the heirarchy. For example, in a pool with a mirror of
+ * RAID-Zs, you can specify either RAID-Z vdev with 0.0 or 0.1 .
+ */
+static vdev_t *
+zdb_vdev_lookup(vdev_t *vdev, const char *path)
+{
+ char *s, *p, *q;
+ unsigned i;
+
+ if (vdev == NULL)
+ return (NULL);
+
+ /* First, assume the x.x.x.x format */
+ i = strtoul(path, &s, 10);
+ if (s == path || (s && *s != '.' && *s != '\0'))
+ goto name;
+ if (i >= vdev->vdev_children)
+ return (NULL);
+
+ vdev = vdev->vdev_child[i];
+ if (*s == '\0')
+ return (vdev);
+ return (zdb_vdev_lookup(vdev, s+1));
+
+name:
+ for (i = 0; i < vdev->vdev_children; i++) {
+ vdev_t *vc = vdev->vdev_child[i];
+
+ if (vc->vdev_path == NULL) {
+ vc = zdb_vdev_lookup(vc, path);
+ if (vc == NULL)
+ continue;
+ else
+ return (vc);
+ }
+
+ p = strrchr(vc->vdev_path, '/');
+ p = p ? p + 1 : vc->vdev_path;
+ q = &vc->vdev_path[strlen(vc->vdev_path) - 2];
+
+ if (strcmp(vc->vdev_path, path) == 0)
+ return (vc);
+ if (strcmp(p, path) == 0)
+ return (vc);
+ if (strcmp(q, "s0") == 0 && strncmp(p, path, q - p) == 0)
+ return (vc);
+ }
+
+ return (NULL);
+}
+
+/* ARGSUSED */
+static int
+random_get_pseudo_bytes_cb(void *buf, size_t len, void *unused)
+{
+ return (random_get_pseudo_bytes(buf, len));
+}
+
+/*
+ * Read a block from a pool and print it out. The syntax of the
+ * block descriptor is:
+ *
+ * pool:vdev_specifier:offset:size[:flags]
+ *
+ * pool - The name of the pool you wish to read from
+ * vdev_specifier - Which vdev (see comment for zdb_vdev_lookup)
+ * offset - offset, in hex, in bytes
+ * size - Amount of data to read, in hex, in bytes
+ * flags - A string of characters specifying options
+ * b: Decode a blkptr at given offset within block
+ * *c: Calculate and display checksums
+ * d: Decompress data before dumping
+ * e: Byteswap data before dumping
+ * g: Display data as a gang block header
+ * i: Display as an indirect block
+ * p: Do I/O to physical offset
+ * r: Dump raw data to stdout
+ *
+ * * = not yet implemented
+ */
+static void
+zdb_read_block(char *thing, spa_t *spa)
+{
+ blkptr_t blk, *bp = &blk;
+ dva_t *dva = bp->blk_dva;
+ int flags = 0;
+ uint64_t offset = 0, size = 0, psize = 0, lsize = 0, blkptr_offset = 0;
+ zio_t *zio;
+ vdev_t *vd;
+ abd_t *pabd;
+ void *lbuf, *buf;
+ const char *s, *vdev;
+ char *p, *dup, *flagstr;
+ int i, error;
+
+ dup = strdup(thing);
+ s = strtok(dup, ":");
+ vdev = s ? s : "";
+ s = strtok(NULL, ":");
+ offset = strtoull(s ? s : "", NULL, 16);
+ s = strtok(NULL, ":");
+ size = strtoull(s ? s : "", NULL, 16);
+ s = strtok(NULL, ":");
+ if (s)
+ flagstr = strdup(s);
+ else
+ flagstr = strdup("");
+
+ s = NULL;
+ if (size == 0)
+ s = "size must not be zero";
+ if (!IS_P2ALIGNED(size, DEV_BSIZE))
+ s = "size must be a multiple of sector size";
+ if (!IS_P2ALIGNED(offset, DEV_BSIZE))
+ s = "offset must be a multiple of sector size";
+ if (s) {
+ (void) printf("Invalid block specifier: %s - %s\n", thing, s);
+ free(flagstr);
+ free(dup);
+ return;
+ }
+
+ for (s = strtok(flagstr, ":"); s; s = strtok(NULL, ":")) {
+ for (i = 0; flagstr[i]; i++) {
+ int bit = flagbits[(uchar_t)flagstr[i]];
+
+ if (bit == 0) {
+ (void) printf("***Invalid flag: %c\n",
+ flagstr[i]);
+ continue;
+ }
+ flags |= bit;
+
+ /* If it's not something with an argument, keep going */
+ if ((bit & (ZDB_FLAG_CHECKSUM |
+ ZDB_FLAG_PRINT_BLKPTR)) == 0)
+ continue;
+
+ p = &flagstr[i + 1];
+ if (bit == ZDB_FLAG_PRINT_BLKPTR)
+ blkptr_offset = strtoull(p, &p, 16);
+ if (*p != ':' && *p != '\0') {
+ (void) printf("***Invalid flag arg: '%s'\n", s);
+ free(flagstr);
+ free(dup);
+ return;
+ }
+ i += p - &flagstr[i + 1]; /* skip over the number */
+ }
+ }
+ free(flagstr);
+
+ vd = zdb_vdev_lookup(spa->spa_root_vdev, vdev);
+ if (vd == NULL) {
+ (void) printf("***Invalid vdev: %s\n", vdev);
+ free(dup);
+ return;
+ } else {
+ if (vd->vdev_path)
+ (void) fprintf(stderr, "Found vdev: %s\n",
+ vd->vdev_path);
+ else
+ (void) fprintf(stderr, "Found vdev type: %s\n",
+ vd->vdev_ops->vdev_op_type);
+ }
+
+ psize = size;
+ lsize = size;
+
+ pabd = abd_alloc_linear(SPA_MAXBLOCKSIZE, B_FALSE);
+ lbuf = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
+
+ BP_ZERO(bp);
+
+ DVA_SET_VDEV(&dva[0], vd->vdev_id);
+ DVA_SET_OFFSET(&dva[0], offset);
+ DVA_SET_GANG(&dva[0], !!(flags & ZDB_FLAG_GBH));
+ DVA_SET_ASIZE(&dva[0], vdev_psize_to_asize(vd, psize));
+
+ BP_SET_BIRTH(bp, TXG_INITIAL, TXG_INITIAL);
+
+ BP_SET_LSIZE(bp, lsize);
+ BP_SET_PSIZE(bp, psize);
+ BP_SET_COMPRESS(bp, ZIO_COMPRESS_OFF);
+ BP_SET_CHECKSUM(bp, ZIO_CHECKSUM_OFF);
+ BP_SET_TYPE(bp, DMU_OT_NONE);
+ BP_SET_LEVEL(bp, 0);
+ BP_SET_DEDUP(bp, 0);
+ BP_SET_BYTEORDER(bp, ZFS_HOST_BYTEORDER);
+
+ spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+ zio = zio_root(spa, NULL, NULL, 0);
+
+ if (vd == vd->vdev_top) {
+ /*
+ * Treat this as a normal block read.
+ */
+ zio_nowait(zio_read(zio, spa, bp, pabd, psize, NULL, NULL,
+ ZIO_PRIORITY_SYNC_READ,
+ ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW, NULL));
+ } else {
+ /*
+ * Treat this as a vdev child I/O.
+ */
+ zio_nowait(zio_vdev_child_io(zio, bp, vd, offset, pabd,
+ psize, ZIO_TYPE_READ, ZIO_PRIORITY_SYNC_READ,
+ ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE |
+ ZIO_FLAG_DONT_PROPAGATE | ZIO_FLAG_DONT_RETRY |
+ ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW | ZIO_FLAG_OPTIONAL,
+ NULL, NULL));
+ }
+
+ error = zio_wait(zio);
+ spa_config_exit(spa, SCL_STATE, FTAG);
+
+ if (error) {
+ (void) printf("Read of %s failed, error: %d\n", thing, error);
+ goto out;
+ }
+
+ if (flags & ZDB_FLAG_DECOMPRESS) {
+ /*
+ * We don't know how the data was compressed, so just try
+ * every decompress function at every inflated blocksize.
+ */
+ enum zio_compress c;
+ void *pbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
+ void *lbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
+
+ abd_copy_to_buf(pbuf2, pabd, psize);
+
+ VERIFY0(abd_iterate_func(pabd, psize, SPA_MAXBLOCKSIZE - psize,
+ random_get_pseudo_bytes_cb, NULL));
+
+ VERIFY0(random_get_pseudo_bytes((uint8_t *)pbuf2 + psize,
+ SPA_MAXBLOCKSIZE - psize));
+
+ for (lsize = SPA_MAXBLOCKSIZE; lsize > psize;
+ lsize -= SPA_MINBLOCKSIZE) {
+ for (c = 0; c < ZIO_COMPRESS_FUNCTIONS; c++) {
+ if (zio_decompress_data(c, pabd,
+ lbuf, psize, lsize) == 0 &&
+ zio_decompress_data_buf(c, pbuf2,
+ lbuf2, psize, lsize) == 0 &&
+ bcmp(lbuf, lbuf2, lsize) == 0)
+ break;
+ }
+ if (c != ZIO_COMPRESS_FUNCTIONS)
+ break;
+ lsize -= SPA_MINBLOCKSIZE;
+ }
+
+ umem_free(pbuf2, SPA_MAXBLOCKSIZE);
+ umem_free(lbuf2, SPA_MAXBLOCKSIZE);
+
+ if (lsize <= psize) {
+ (void) printf("Decompress of %s failed\n", thing);
+ goto out;
+ }
+ buf = lbuf;
+ size = lsize;
+ } else {
+ buf = abd_to_buf(pabd);
+ size = psize;
+ }
+
+ if (flags & ZDB_FLAG_PRINT_BLKPTR)
+ zdb_print_blkptr((blkptr_t *)(void *)
+ ((uintptr_t)buf + (uintptr_t)blkptr_offset), flags);
+ else if (flags & ZDB_FLAG_RAW)
+ zdb_dump_block_raw(buf, size, flags);
+ else if (flags & ZDB_FLAG_INDIRECT)
+ zdb_dump_indirect((blkptr_t *)buf, size / sizeof (blkptr_t),
+ flags);
+ else if (flags & ZDB_FLAG_GBH)
+ zdb_dump_gbh(buf, flags);
+ else
+ zdb_dump_block(thing, buf, size, flags);
+
+out:
+ abd_free(pabd);
+ umem_free(lbuf, SPA_MAXBLOCKSIZE);
+ free(dup);
+}
+
+static void
+zdb_embedded_block(char *thing)
+{
+ blkptr_t bp;
+ unsigned long long *words = (void *)&bp;
+ char *buf;
+ int err;
+
+ bzero(&bp, sizeof (bp));
+ err = sscanf(thing, "%llx:%llx:%llx:%llx:%llx:%llx:%llx:%llx:"
+ "%llx:%llx:%llx:%llx:%llx:%llx:%llx:%llx",
+ words + 0, words + 1, words + 2, words + 3,
+ words + 4, words + 5, words + 6, words + 7,
+ words + 8, words + 9, words + 10, words + 11,
+ words + 12, words + 13, words + 14, words + 15);
+ if (err != 16) {
+ (void) fprintf(stderr, "invalid input format\n");
+ exit(1);
+ }
+ ASSERT3U(BPE_GET_LSIZE(&bp), <=, SPA_MAXBLOCKSIZE);
+ buf = malloc(SPA_MAXBLOCKSIZE);
+ if (buf == NULL) {
+ (void) fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ err = decode_embedded_bp(&bp, buf, BPE_GET_LSIZE(&bp));
+ if (err != 0) {
+ (void) fprintf(stderr, "decode failed: %u\n", err);
+ free(buf);
+ exit(1);
+ }
+ zdb_dump_block_raw(buf, BPE_GET_LSIZE(&bp), 0);
+ free(buf);
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ struct rlimit rl = { 1024, 1024 };
+ spa_t *spa = NULL;
+ objset_t *os = NULL;
+ int dump_all = 1;
+ int verbose = 0;
+ int error = 0;
+ char **searchdirs = NULL;
+ int nsearch = 0;
+ char *target, *target_pool;
+ nvlist_t *policy = NULL;
+ uint64_t max_txg = UINT64_MAX;
+ int flags = ZFS_IMPORT_MISSING_LOG;
+ int rewind = ZPOOL_NEVER_REWIND;
+ char *spa_config_path_env;
+ boolean_t target_is_spa = B_TRUE;
+ nvlist_t *cfg = NULL;
+
+ (void) setrlimit(RLIMIT_NOFILE, &rl);
+ (void) enable_extended_FILE_stdio(-1, -1);
+
+ dprintf_setup(&argc, argv);
+
+ /*
+ * If there is an environment variable SPA_CONFIG_PATH it overrides
+ * default spa_config_path setting. If -U flag is specified it will
+ * override this environment variable settings once again.
+ */
+ spa_config_path_env = getenv("SPA_CONFIG_PATH");
+ if (spa_config_path_env != NULL)
+ spa_config_path = spa_config_path_env;
+
+ while ((c = getopt(argc, argv,
+ "AbcCdDeEFGhiI:klLmMo:Op:PqRsSt:uU:vVx:X")) != -1) {
+ switch (c) {
+ case 'b':
+ case 'c':
+ case 'C':
+ case 'd':
+ case 'D':
+ case 'E':
+ case 'G':
+ case 'h':
+ case 'i':
+ case 'l':
+ case 'm':
+ case 'M':
+ case 'O':
+ case 'R':
+ case 's':
+ case 'S':
+ case 'u':
+ dump_opt[c]++;
+ dump_all = 0;
+ break;
+ case 'A':
+ case 'e':
+ case 'F':
+ case 'k':
+ case 'L':
+ case 'P':
+ case 'q':
+ case 'X':
+ dump_opt[c]++;
+ break;
+ /* NB: Sort single match options below. */
+ case 'I':
+ max_inflight = strtoull(optarg, NULL, 0);
+ if (max_inflight == 0) {
+ (void) fprintf(stderr, "maximum number "
+ "of inflight I/Os must be greater "
+ "than 0\n");
+ usage();
+ }
+ break;
+ case 'o':
+ error = set_global_var(optarg);
+ if (error != 0)
+ usage();
+ break;
+ case 'p':
+ if (searchdirs == NULL) {
+ searchdirs = umem_alloc(sizeof (char *),
+ UMEM_NOFAIL);
+ } else {
+ char **tmp = umem_alloc((nsearch + 1) *
+ sizeof (char *), UMEM_NOFAIL);
+ bcopy(searchdirs, tmp, nsearch *
+ sizeof (char *));
+ umem_free(searchdirs,
+ nsearch * sizeof (char *));
+ searchdirs = tmp;
+ }
+ searchdirs[nsearch++] = optarg;
+ break;
+ case 't':
+ max_txg = strtoull(optarg, NULL, 0);
+ if (max_txg < TXG_INITIAL) {
+ (void) fprintf(stderr, "incorrect txg "
+ "specified: %s\n", optarg);
+ usage();
+ }
+ break;
+ case 'U':
+ spa_config_path = optarg;
+ if (spa_config_path[0] != '/') {
+ (void) fprintf(stderr,
+ "cachefile must be an absolute path "
+ "(i.e. start with a slash)\n");
+ usage();
+ }
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'V':
+ flags = ZFS_IMPORT_VERBATIM;
+ break;
+ case 'x':
+ vn_dumpdir = optarg;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (!dump_opt['e'] && searchdirs != NULL) {
+ (void) fprintf(stderr, "-p option requires use of -e\n");
+ usage();
+ }
+
+ /*
+ * ZDB does not typically re-read blocks; therefore limit the ARC
+ * to 256 MB, which can be used entirely for metadata.
+ */
+ zfs_arc_max = zfs_arc_meta_limit = 256 * 1024 * 1024;
+
+ /*
+ * "zdb -c" uses checksum-verifying scrub i/os which are async reads.
+ * "zdb -b" uses traversal prefetch which uses async reads.
+ * For good performance, let several of them be active at once.
+ */
+ zfs_vdev_async_read_max_active = 10;
+
+ /*
+ * Disable reference tracking for better performance.
+ */
+ reference_tracking_enable = B_FALSE;
+
+ /*
+ * Do not fail spa_load when spa_load_verify fails. This is needed
+ * to load non-idle pools.
+ */
+ spa_load_verify_dryrun = B_TRUE;
+
+ kernel_init(FREAD);
+ g_zfs = libzfs_init();
+ if (g_zfs == NULL)
+ fatal("Fail to initialize zfs");
+
+ if (dump_all)
+ verbose = MAX(verbose, 1);
+
+ for (c = 0; c < 256; c++) {
+ if (dump_all && strchr("AeEFklLOPRSX", c) == NULL)
+ dump_opt[c] = 1;
+ if (dump_opt[c])
+ dump_opt[c] += verbose;
+ }
+
+ aok = (dump_opt['A'] == 1) || (dump_opt['A'] > 2);
+ zfs_recover = (dump_opt['A'] > 1);
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2 && dump_opt['R'])
+ usage();
+
+ if (dump_opt['E']) {
+ if (argc != 1)
+ usage();
+ zdb_embedded_block(argv[0]);
+ return (0);
+ }
+
+ if (argc < 1) {
+ if (!dump_opt['e'] && dump_opt['C']) {
+ dump_cachefile(spa_config_path);
+ return (0);
+ }
+ usage();
+ }
+
+ if (dump_opt['l'])
+ return (dump_label(argv[0]));
+
+ if (dump_opt['O']) {
+ if (argc != 2)
+ usage();
+ dump_opt['v'] = verbose + 3;
+ return (dump_path(argv[0], argv[1]));
+ }
+
+ if (dump_opt['X'] || dump_opt['F'])
+ rewind = ZPOOL_DO_REWIND |
+ (dump_opt['X'] ? ZPOOL_EXTREME_REWIND : 0);
+
+ if (nvlist_alloc(&policy, NV_UNIQUE_NAME_TYPE, 0) != 0 ||
+ nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, max_txg) != 0 ||
+ nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, rewind) != 0)
+ fatal("internal error: %s", strerror(ENOMEM));
+
+ error = 0;
+ target = argv[0];
+
+ if (strpbrk(target, "/@") != NULL) {
+ size_t targetlen;
+
+ target_pool = strdup(target);
+ *strpbrk(target_pool, "/@") = '\0';
+
+ target_is_spa = B_FALSE;
+ targetlen = strlen(target);
+ if (targetlen && target[targetlen - 1] == '/')
+ target[targetlen - 1] = '\0';
+ } else {
+ target_pool = target;
+ }
+
+ if (dump_opt['e']) {
+ importargs_t args = { 0 };
+
+ args.paths = nsearch;
+ args.path = searchdirs;
+ args.can_be_active = B_TRUE;
+
+ error = zpool_tryimport(g_zfs, target_pool, &cfg, &args);
+
+ if (error == 0) {
+
+ if (nvlist_add_nvlist(cfg,
+ ZPOOL_LOAD_POLICY, policy) != 0) {
+ fatal("can't open '%s': %s",
+ target, strerror(ENOMEM));
+ }
+
+ if (dump_opt['C'] > 1) {
+ (void) printf("\nConfiguration for import:\n");
+ dump_nvlist(cfg, 8);
+ }
+
+ /*
+ * Disable the activity check to allow examination of
+ * active pools.
+ */
+ error = spa_import(target_pool, cfg, NULL,
+ flags | ZFS_IMPORT_SKIP_MMP);
+ }
+ }
+
+ char *checkpoint_pool = NULL;
+ char *checkpoint_target = NULL;
+ if (dump_opt['k']) {
+ checkpoint_pool = import_checkpointed_state(target, cfg,
+ &checkpoint_target);
+
+ if (checkpoint_target != NULL)
+ target = checkpoint_target;
+
+ }
+
+ if (error == 0) {
+ if (dump_opt['k'] && (target_is_spa || dump_opt['R'])) {
+ ASSERT(checkpoint_pool != NULL);
+ ASSERT(checkpoint_target == NULL);
+
+ error = spa_open(checkpoint_pool, &spa, FTAG);
+ if (error != 0) {
+ fatal("Tried to open pool \"%s\" but "
+ "spa_open() failed with error %d\n",
+ checkpoint_pool, error);
+ }
+
+ } else if (target_is_spa || dump_opt['R']) {
+ zdb_set_skip_mmp(target);
+ error = spa_open_rewind(target, &spa, FTAG, policy,
+ NULL);
+ if (error) {
+ /*
+ * If we're missing the log device then
+ * try opening the pool after clearing the
+ * log state.
+ */
+ mutex_enter(&spa_namespace_lock);
+ if ((spa = spa_lookup(target)) != NULL &&
+ spa->spa_log_state == SPA_LOG_MISSING) {
+ spa->spa_log_state = SPA_LOG_CLEAR;
+ error = 0;
+ }
+ mutex_exit(&spa_namespace_lock);
+
+ if (!error) {
+ error = spa_open_rewind(target, &spa,
+ FTAG, policy, NULL);
+ }
+ }
+ } else {
+ zdb_set_skip_mmp(target);
+ error = open_objset(target, DMU_OST_ANY, FTAG, &os);
+ }
+ }
+ nvlist_free(policy);
+
+ if (error)
+ fatal("can't open '%s': %s", target, strerror(error));
+
+ argv++;
+ argc--;
+ if (!dump_opt['R']) {
+ if (argc > 0) {
+ zopt_objects = argc;
+ zopt_object = calloc(zopt_objects, sizeof (uint64_t));
+ for (unsigned i = 0; i < zopt_objects; i++) {
+ errno = 0;
+ zopt_object[i] = strtoull(argv[i], NULL, 0);
+ if (zopt_object[i] == 0 && errno != 0)
+ fatal("bad number %s: %s",
+ argv[i], strerror(errno));
+ }
+ }
+ if (os != NULL) {
+ dump_dir(os);
+ } else if (zopt_objects > 0 && !dump_opt['m']) {
+ dump_dir(spa->spa_meta_objset);
+ } else {
+ dump_zpool(spa);
+ }
+ } else {
+ flagbits['b'] = ZDB_FLAG_PRINT_BLKPTR;
+ flagbits['c'] = ZDB_FLAG_CHECKSUM;
+ flagbits['d'] = ZDB_FLAG_DECOMPRESS;
+ flagbits['e'] = ZDB_FLAG_BSWAP;
+ flagbits['g'] = ZDB_FLAG_GBH;
+ flagbits['i'] = ZDB_FLAG_INDIRECT;
+ flagbits['p'] = ZDB_FLAG_PHYS;
+ flagbits['r'] = ZDB_FLAG_RAW;
+
+ for (int i = 0; i < argc; i++)
+ zdb_read_block(argv[i], spa);
+ }
+
+ if (dump_opt['k']) {
+ free(checkpoint_pool);
+ if (!target_is_spa)
+ free(checkpoint_target);
+ }
+
+ if (os != NULL)
+ close_objset(os, FTAG);
+ else
+ spa_close(spa, FTAG);
+
+ fuid_table_destroy();
+
+ dump_debug_buffer();
+
+ libzfs_fini(g_zfs);
+ kernel_fini();
+
+ return (error);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.h b/cddl/contrib/opensolaris/cmd/zdb/zdb.h
new file mode 100644
index 000000000000..49579811efbb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.h
@@ -0,0 +1,33 @@
+/*
+ * 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 2017 Spectra Logic Corp Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _ZDB_H
+#define _ZDB_H
+
+void dump_intent_log(zilog_t *);
+extern uint8_t dump_opt[256];
+
+#endif /* _ZDB_H */
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c b/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
new file mode 100644
index 000000000000..9f3f23f82da1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
@@ -0,0 +1,424 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013, 2017 by Delphix. All rights reserved.
+ */
+
+/*
+ * Print intent log header and statistics.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+#include <sys/spa_impl.h>
+#include <sys/abd.h>
+
+#include "zdb.h"
+
+extern uint8_t dump_opt[256];
+
+static char tab_prefix[4] = "\t\t\t";
+
+static void
+print_log_bp(const blkptr_t *bp, const char *prefix)
+{
+ char blkbuf[BP_SPRINTF_LEN];
+
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+ (void) printf("%s%s\n", prefix, blkbuf);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_create(zilog_t *zilog, int txtype, void *arg)
+{
+ lr_create_t *lr = arg;
+ time_t crtime = lr->lr_crtime[0];
+ char *name, *link;
+ lr_attr_t *lrattr;
+
+ name = (char *)(lr + 1);
+
+ if (lr->lr_common.lrc_txtype == TX_CREATE_ATTR ||
+ lr->lr_common.lrc_txtype == TX_MKDIR_ATTR) {
+ lrattr = (lr_attr_t *)(lr + 1);
+ name += ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ }
+
+ if (txtype == TX_SYMLINK) {
+ link = name + strlen(name) + 1;
+ (void) printf("%s%s -> %s\n", tab_prefix, name, link);
+ } else if (txtype != TX_MKXATTR) {
+ (void) printf("%s%s\n", tab_prefix, name);
+ }
+
+ (void) printf("%s%s", tab_prefix, ctime(&crtime));
+ (void) printf("%sdoid %" PRIu64 ", foid %" PRIu64 ", slots %" PRIu64
+ ", mode %" PRIo64 "\n",
+ tab_prefix, lr->lr_doid,
+ (uint64_t)LR_FOID_GET_OBJ(lr->lr_foid),
+ (uint64_t)LR_FOID_GET_SLOTS(lr->lr_foid),
+ lr->lr_mode);
+ (void) printf("%suid %" PRIu64 ", gid %" PRIu64 ", gen %" PRIu64
+ ", rdev %#" PRIx64 "\n",
+ tab_prefix, lr->lr_uid, lr->lr_gid, lr->lr_gen, lr->lr_rdev);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_remove(zilog_t *zilog, int txtype, void *arg)
+{
+ lr_remove_t *lr = arg;
+
+ (void) printf("%sdoid %llu, name %s\n", tab_prefix,
+ (u_longlong_t)lr->lr_doid, (char *)(lr + 1));
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_link(zilog_t *zilog, int txtype, void *arg)
+{
+ lr_link_t *lr = arg;
+
+ (void) printf("%sdoid %llu, link_obj %llu, name %s\n", tab_prefix,
+ (u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_link_obj,
+ (char *)(lr + 1));
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_rename(zilog_t *zilog, int txtype, void *arg)
+{
+ lr_rename_t *lr = arg;
+ char *snm = (char *)(lr + 1);
+ char *tnm = snm + strlen(snm) + 1;
+
+ (void) printf("%ssdoid %llu, tdoid %llu\n", tab_prefix,
+ (u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid);
+ (void) printf("%ssrc %s tgt %s\n", tab_prefix, snm, tnm);
+}
+
+/* ARGSUSED */
+static int
+zil_prt_rec_write_cb(void *data, size_t len, void *unused)
+{
+ char *cdata = data;
+ for (size_t i = 0; i < len; i++) {
+ if (isprint(*cdata))
+ (void) printf("%c ", *cdata);
+ else
+ (void) printf("%2X", *cdata);
+ cdata++;
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_write(zilog_t *zilog, int txtype, void *arg)
+{
+ lr_write_t *lr = arg;
+ abd_t *data;
+ blkptr_t *bp = &lr->lr_blkptr;
+ zbookmark_phys_t zb;
+ int verbose = MAX(dump_opt['d'], dump_opt['i']);
+ int error;
+
+ (void) printf("%sfoid %llu, offset %llx, length %llx\n", tab_prefix,
+ (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset,
+ (u_longlong_t)lr->lr_length);
+
+ if (txtype == TX_WRITE2 || verbose < 5)
+ return;
+
+ if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
+ (void) printf("%shas blkptr, %s\n", tab_prefix,
+ !BP_IS_HOLE(bp) &&
+ bp->blk_birth >= spa_min_claim_txg(zilog->zl_spa) ?
+ "will claim" : "won't claim");
+ print_log_bp(bp, tab_prefix);
+
+ if (BP_IS_HOLE(bp)) {
+ (void) printf("\t\t\tLSIZE 0x%llx\n",
+ (u_longlong_t)BP_GET_LSIZE(bp));
+ (void) printf("%s<hole>\n", tab_prefix);
+ return;
+ }
+ if (bp->blk_birth < zilog->zl_header->zh_claim_txg) {
+ (void) printf("%s<block already committed>\n",
+ tab_prefix);
+ return;
+ }
+
+ SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os),
+ lr->lr_foid, ZB_ZIL_LEVEL,
+ lr->lr_offset / BP_GET_LSIZE(bp));
+
+ data = abd_alloc(BP_GET_LSIZE(bp), B_FALSE);
+ error = zio_wait(zio_read(NULL, zilog->zl_spa,
+ bp, data, BP_GET_LSIZE(bp), NULL, NULL,
+ ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &zb));
+ if (error)
+ goto out;
+ } else {
+ /* data is stored after the end of the lr_write record */
+ data = abd_alloc(lr->lr_length, B_FALSE);
+ abd_copy_from_buf(data, lr + 1, lr->lr_length);
+ }
+
+ (void) printf("%s", tab_prefix);
+ (void) abd_iterate_func(data,
+ 0, MIN(lr->lr_length, (verbose < 6 ? 20 : SPA_MAXBLOCKSIZE)),
+ zil_prt_rec_write_cb, NULL);
+ (void) printf("\n");
+
+out:
+ abd_free(data);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_truncate(zilog_t *zilog, int txtype, void *arg)
+{
+ lr_truncate_t *lr = arg;
+
+ (void) printf("%sfoid %llu, offset 0x%llx, length 0x%llx\n", tab_prefix,
+ (u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
+ (u_longlong_t)lr->lr_length);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_setattr(zilog_t *zilog, int txtype, void *arg)
+{
+ lr_setattr_t *lr = arg;
+ time_t atime = (time_t)lr->lr_atime[0];
+ time_t mtime = (time_t)lr->lr_mtime[0];
+
+ (void) printf("%sfoid %llu, mask 0x%llx\n", tab_prefix,
+ (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_mask);
+
+ if (lr->lr_mask & AT_MODE) {
+ (void) printf("%sAT_MODE %llo\n", tab_prefix,
+ (longlong_t)lr->lr_mode);
+ }
+
+ if (lr->lr_mask & AT_UID) {
+ (void) printf("%sAT_UID %llu\n", tab_prefix,
+ (u_longlong_t)lr->lr_uid);
+ }
+
+ if (lr->lr_mask & AT_GID) {
+ (void) printf("%sAT_GID %llu\n", tab_prefix,
+ (u_longlong_t)lr->lr_gid);
+ }
+
+ if (lr->lr_mask & AT_SIZE) {
+ (void) printf("%sAT_SIZE %llu\n", tab_prefix,
+ (u_longlong_t)lr->lr_size);
+ }
+
+ if (lr->lr_mask & AT_ATIME) {
+ (void) printf("%sAT_ATIME %llu.%09llu %s", tab_prefix,
+ (u_longlong_t)lr->lr_atime[0],
+ (u_longlong_t)lr->lr_atime[1],
+ ctime(&atime));
+ }
+
+ if (lr->lr_mask & AT_MTIME) {
+ (void) printf("%sAT_MTIME %llu.%09llu %s", tab_prefix,
+ (u_longlong_t)lr->lr_mtime[0],
+ (u_longlong_t)lr->lr_mtime[1],
+ ctime(&mtime));
+ }
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_acl(zilog_t *zilog, int txtype, void *arg)
+{
+ lr_acl_t *lr = arg;
+
+ (void) printf("%sfoid %llu, aclcnt %llu\n", tab_prefix,
+ (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_aclcnt);
+}
+
+typedef void (*zil_prt_rec_func_t)(zilog_t *, int, void *);
+typedef struct zil_rec_info {
+ zil_prt_rec_func_t zri_print;
+ const char *zri_name;
+ uint64_t zri_count;
+} zil_rec_info_t;
+
+static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
+ {.zri_print = NULL, .zri_name = "Total "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKXATTR "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_SYMLINK "},
+ {.zri_print = zil_prt_rec_remove, .zri_name = "TX_REMOVE "},
+ {.zri_print = zil_prt_rec_remove, .zri_name = "TX_RMDIR "},
+ {.zri_print = zil_prt_rec_link, .zri_name = "TX_LINK "},
+ {.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME "},
+ {.zri_print = zil_prt_rec_write, .zri_name = "TX_WRITE "},
+ {.zri_print = zil_prt_rec_truncate, .zri_name = "TX_TRUNCATE "},
+ {.zri_print = zil_prt_rec_setattr, .zri_name = "TX_SETATTR "},
+ {.zri_print = zil_prt_rec_acl, .zri_name = "TX_ACL_V0 "},
+ {.zri_print = zil_prt_rec_acl, .zri_name = "TX_ACL_ACL "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE_ACL "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE_ATTR "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE_ACL_ATTR "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ACL "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ATTR "},
+ {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ACL_ATTR "},
+ {.zri_print = zil_prt_rec_write, .zri_name = "TX_WRITE2 "},
+};
+
+/* ARGSUSED */
+static int
+print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
+{
+ int txtype;
+ int verbose = MAX(dump_opt['d'], dump_opt['i']);
+
+ /* reduce size of txtype to strip off TX_CI bit */
+ txtype = lr->lrc_txtype;
+
+ ASSERT(txtype != 0 && (uint_t)txtype < TX_MAX_TYPE);
+ ASSERT(lr->lrc_txg);
+
+ (void) printf("\t\t%s%s len %6llu, txg %llu, seq %llu\n",
+ (lr->lrc_txtype & TX_CI) ? "CI-" : "",
+ zil_rec_info[txtype].zri_name,
+ (u_longlong_t)lr->lrc_reclen,
+ (u_longlong_t)lr->lrc_txg,
+ (u_longlong_t)lr->lrc_seq);
+
+ if (txtype && verbose >= 3)
+ zil_rec_info[txtype].zri_print(zilog, txtype, lr);
+
+ zil_rec_info[txtype].zri_count++;
+ zil_rec_info[0].zri_count++;
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+print_log_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
+{
+ char blkbuf[BP_SPRINTF_LEN + 10];
+ int verbose = MAX(dump_opt['d'], dump_opt['i']);
+ const char *claim;
+
+ if (verbose <= 3)
+ return (0);
+
+ if (verbose >= 5) {
+ (void) strcpy(blkbuf, ", ");
+ snprintf_blkptr(blkbuf + strlen(blkbuf),
+ sizeof (blkbuf) - strlen(blkbuf), bp);
+ } else {
+ blkbuf[0] = '\0';
+ }
+
+ if (claim_txg != 0)
+ claim = "already claimed";
+ else if (bp->blk_birth >= spa_min_claim_txg(zilog->zl_spa))
+ claim = "will claim";
+ else
+ claim = "won't claim";
+
+ (void) printf("\tBlock seqno %llu, %s%s\n",
+ (u_longlong_t)bp->blk_cksum.zc_word[ZIL_ZC_SEQ], claim, blkbuf);
+
+ return (0);
+}
+
+static void
+print_log_stats(int verbose)
+{
+ unsigned i, w, p10;
+
+ if (verbose > 3)
+ (void) printf("\n");
+
+ if (zil_rec_info[0].zri_count == 0)
+ return;
+
+ for (w = 1, p10 = 10; zil_rec_info[0].zri_count >= p10; p10 *= 10)
+ w++;
+
+ for (i = 0; i < TX_MAX_TYPE; i++)
+ if (zil_rec_info[i].zri_count || verbose >= 3)
+ (void) printf("\t\t%s %*llu\n",
+ zil_rec_info[i].zri_name, w,
+ (u_longlong_t)zil_rec_info[i].zri_count);
+ (void) printf("\n");
+}
+
+/* ARGSUSED */
+void
+dump_intent_log(zilog_t *zilog)
+{
+ const zil_header_t *zh = zilog->zl_header;
+ int verbose = MAX(dump_opt['d'], dump_opt['i']);
+ int i;
+
+ if (BP_IS_HOLE(&zh->zh_log) || verbose < 1)
+ return;
+
+ (void) printf("\n ZIL header: claim_txg %llu, "
+ "claim_blk_seq %llu, claim_lr_seq %llu",
+ (u_longlong_t)zh->zh_claim_txg,
+ (u_longlong_t)zh->zh_claim_blk_seq,
+ (u_longlong_t)zh->zh_claim_lr_seq);
+ (void) printf(" replay_seq %llu, flags 0x%llx\n",
+ (u_longlong_t)zh->zh_replay_seq, (u_longlong_t)zh->zh_flags);
+
+ for (i = 0; i < TX_MAX_TYPE; i++)
+ zil_rec_info[i].zri_count = 0;
+
+ /* see comment in zil_claim() or zil_check_log_chain() */
+ if (zilog->zl_spa->spa_uberblock.ub_checkpoint_txg != 0 &&
+ zh->zh_claim_txg == 0)
+ return;
+
+ if (verbose >= 2) {
+ (void) printf("\n");
+ (void) zil_parse(zilog, print_log_block, print_log_record, NULL,
+ zh->zh_claim_txg);
+ print_log_stats(verbose);
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs-program.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs-program.8
new file mode 100644
index 000000000000..06a3205f05fa
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs-program.8
@@ -0,0 +1,551 @@
+.\" This file and its contents are supplied under the terms of the
+.\" Common Development and Distribution License ("CDDL"), version 1.0.
+.\" You may only use this file in accordance with the terms of version
+.\" 1.0 of the CDDL.
+.\"
+.\" A full copy of the text of the CDDL should have accompanied this
+.\" source. A copy of the CDDL is also available via the Internet at
+.\" http://www.illumos.org/license/CDDL.
+.\"
+.\"
+.\" Copyright (c) 2016, 2017 by Delphix. All rights reserved.
+.\" Copyright (c) 2018 Datto Inc.
+.\"
+.Dd October 02, 2017
+.Dt ZFS-PROGRAM 8
+.Os
+.Sh NAME
+.Nm zfs program
+.Nd executes ZFS channel programs
+.Sh SYNOPSIS
+.Cm zfs program
+.Op Fl jn
+.Op Fl t Ar instruction-limit
+.Op Fl m Ar memory-limit
+.Ar pool
+.Ar script
+.\".Op Ar optional arguments to channel program
+.Sh DESCRIPTION
+The ZFS channel program interface allows ZFS administrative operations to be
+run programmatically as a Lua script.
+The entire script is executed atomically, with no other administrative
+operations taking effect concurrently.
+A library of ZFS calls is made available to channel program scripts.
+Channel programs may only be run with root privileges.
+.Pp
+A modified version of the Lua 5.2 interpreter is used to run channel program
+scripts.
+The Lua 5.2 manual can be found at:
+.Bd -centered -offset indent
+.Lk http://www.lua.org/manual/5.2/
+.Ed
+.Pp
+The channel program given by
+.Ar script
+will be run on
+.Ar pool ,
+and any attempts to access or modify other pools will cause an error.
+.Sh OPTIONS
+.Bl -tag -width "-t"
+.It Fl j
+Display channel program output in JSON format.
+When this flag is specified and standard output is empty -
+channel program encountered an error.
+The details of such an error will be printed to standard error in plain text.
+.It Fl n
+Executes a read-only channel program, which runs faster.
+The program cannot change on-disk state by calling functions from the
+zfs.sync submodule.
+The program can be used to gather information such as properties and
+determining if changes would succeed (zfs.check.*).
+Without this flag, all pending changes must be synced to disk before a
+channel program can complete.
+.It Fl t Ar instruction-limit
+Execution time limit, in number of Lua instructions to execute.
+If a channel program executes more than the specified number of instructions,
+it will be stopped and an error will be returned.
+The default limit is 10 million instructions, and it can be set to a maximum of
+100 million instructions.
+.It Fl m Ar memory-limit
+Memory limit, in bytes.
+If a channel program attempts to allocate more memory than the given limit, it
+will be stopped and an error returned.
+The default memory limit is 10 MB, and can be set to a maximum of 100 MB.
+.El
+.Pp
+All remaining argument strings will be passed directly to the Lua script as
+described in the
+.Sx LUA INTERFACE
+section below.
+.Sh LUA INTERFACE
+A channel program can be invoked either from the command line, or via a library
+call to
+.Fn lzc_channel_program .
+.Ss Arguments
+Arguments passed to the channel program are converted to a Lua table.
+If invoked from the command line, extra arguments to the Lua script will be
+accessible as an array stored in the argument table with the key 'argv':
+.Bd -literal -offset indent
+args = ...
+argv = args["argv"]
+-- argv == {1="arg1", 2="arg2", ...}
+.Ed
+.Pp
+If invoked from the libZFS interface, an arbitrary argument list can be
+passed to the channel program, which is accessible via the same
+"..." syntax in Lua:
+.Bd -literal -offset indent
+args = ...
+-- args == {"foo"="bar", "baz"={...}, ...}
+.Ed
+.Pp
+Note that because Lua arrays are 1-indexed, arrays passed to Lua from the
+libZFS interface will have their indices incremented by 1.
+That is, the element
+in
+.Va arr[0]
+in a C array passed to a channel program will be stored in
+.Va arr[1]
+when accessed from Lua.
+.Ss Return Values
+Lua return statements take the form:
+.Bd -literal -offset indent
+return ret0, ret1, ret2, ...
+.Ed
+.Pp
+Return statements returning multiple values are permitted internally in a
+channel program script, but attempting to return more than one value from the
+top level of the channel program is not permitted and will throw an error.
+However, tables containing multiple values can still be returned.
+If invoked from the command line, a return statement:
+.Bd -literal -offset indent
+a = {foo="bar", baz=2}
+return a
+.Ed
+.Pp
+Will be output formatted as:
+.Bd -literal -offset indent
+Channel program fully executed with return value:
+ return:
+ baz: 2
+ foo: 'bar'
+.Ed
+.Ss Fatal Errors
+If the channel program encounters a fatal error while running, a non-zero exit
+status will be returned.
+If more information about the error is available, a singleton list will be
+returned detailing the error:
+.Bd -literal -offset indent
+error: "error string, including Lua stack trace"
+.Ed
+.Pp
+If a fatal error is returned, the channel program may have not executed at all,
+may have partially executed, or may have fully executed but failed to pass a
+return value back to userland.
+.Pp
+If the channel program exhausts an instruction or memory limit, a fatal error
+will be generated and the program will be stopped, leaving the program partially
+executed.
+No attempt is made to reverse or undo any operations already performed.
+Note that because both the instruction count and amount of memory used by a
+channel program are deterministic when run against the same inputs and
+filesystem state, as long as a channel program has run successfully once, you
+can guarantee that it will finish successfully against a similar size system.
+.Pp
+If a channel program attempts to return too large a value, the program will
+fully execute but exit with a nonzero status code and no return value.
+.Pp
+.Em Note:
+ZFS API functions do not generate Fatal Errors when correctly invoked, they
+return an error code and the channel program continues executing.
+See the
+.Sx ZFS API
+section below for function-specific details on error return codes.
+.Ss Lua to C Value Conversion
+When invoking a channel program via the libZFS interface, it is necessary to
+translate arguments and return values from Lua values to their C equivalents,
+and vice-versa.
+.Pp
+There is a correspondence between nvlist values in C and Lua tables.
+A Lua table which is returned from the channel program will be recursively
+converted to an nvlist, with table values converted to their natural
+equivalents:
+.Bd -literal -offset indent
+string -> string
+number -> int64
+boolean -> boolean_value
+nil -> boolean (no value)
+table -> nvlist
+.Ed
+.Pp
+Likewise, table keys are replaced by string equivalents as follows:
+.Bd -literal -offset indent
+string -> no change
+number -> signed decimal string ("%lld")
+boolean -> "true" | "false"
+.Ed
+.Pp
+Any collision of table key strings (for example, the string "true" and a
+true boolean value) will cause a fatal error.
+.Pp
+Lua numbers are represented internally as signed 64-bit integers.
+.Sh LUA STANDARD LIBRARY
+The following Lua built-in base library functions are available:
+.Bd -literal -offset indent
+assert rawlen
+collectgarbage rawget
+error rawset
+getmetatable select
+ipairs setmetatable
+next tonumber
+pairs tostring
+rawequal type
+.Ed
+.Pp
+All functions in the
+.Em coroutine ,
+.Em string ,
+and
+.Em table
+built-in submodules are also available.
+A complete list and documentation of these modules is available in the Lua
+manual.
+.Pp
+The following functions base library functions have been disabled and are
+not available for use in channel programs:
+.Bd -literal -offset indent
+dofile
+loadfile
+load
+pcall
+print
+xpcall
+.Ed
+.Sh ZFS API
+.Ss Function Arguments
+Each API function takes a fixed set of required positional arguments and
+optional keyword arguments.
+For example, the destroy function takes a single positional string argument
+(the name of the dataset to destroy) and an optional "defer" keyword boolean
+argument.
+When using parentheses to specify the arguments to a Lua function, only
+positional arguments can be used:
+.Bd -literal -offset indent
+zfs.sync.destroy("rpool@snap")
+.Ed
+.Pp
+To use keyword arguments, functions must be called with a single argument that
+is a Lua table containing entries mapping integers to positional arguments and
+strings to keyword arguments:
+.Bd -literal -offset indent
+zfs.sync.destroy({1="rpool@snap", defer=true})
+.Ed
+.Pp
+The Lua language allows curly braces to be used in place of parenthesis as
+syntactic sugar for this calling convention:
+.Bd -literal -offset indent
+zfs.sync.snapshot{"rpool@snap", defer=true}
+.Ed
+.Ss Function Return Values
+If an API function succeeds, it returns 0.
+If it fails, it returns an error code and the channel program continues
+executing.
+API functions do not generate Fatal Errors except in the case of an
+unrecoverable internal file system error.
+.Pp
+In addition to returning an error code, some functions also return extra
+details describing what caused the error.
+This extra description is given as a second return value, and will always be a
+Lua table, or Nil if no error details were returned.
+Different keys will exist in the error details table depending on the function
+and error case.
+Any such function may be called expecting a single return value:
+.Bd -literal -offset indent
+errno = zfs.sync.promote(dataset)
+.Ed
+.Pp
+Or, the error details can be retrieved:
+.Bd -literal -offset indent
+errno, details = zfs.sync.promote(dataset)
+if (errno == EEXIST) then
+ assert(details ~= Nil)
+ list_of_conflicting_snapshots = details
+end
+.Ed
+.Pp
+The following global aliases for API function error return codes are defined
+for use in channel programs:
+.Bd -literal -offset indent
+EPERM ECHILD ENODEV ENOSPC
+ENOENT EAGAIN ENOTDIR ESPIPE
+ESRCH ENOMEM EISDIR EROFS
+EINTR EACCES EINVAL EMLINK
+EIO EFAULT ENFILE EPIPE
+ENXIO ENOTBLK EMFILE EDOM
+E2BIG EBUSY ENOTTY ERANGE
+ENOEXEC EEXIST ETXTBSY EDQUOT
+EBADF EXDEV EFBIG
+.Ed
+.Ss API Functions
+For detailed descriptions of the exact behavior of any zfs administrative
+operations, see the main
+.Xr zfs 1
+manual page.
+.Bl -tag -width "xx"
+.It Em zfs.debug(msg)
+Record a debug message in the zfs_dbgmsg log.
+A log of these messages can be printed via mdb's "::zfs_dbgmsg" command, or
+can be monitored live by running:
+.Bd -literal -offset indent
+ dtrace -n 'zfs-dbgmsg{trace(stringof(arg0))}'
+.Ed
+.Pp
+msg (string)
+.Bd -ragged -compact -offset "xxxx"
+Debug message to be printed.
+.Ed
+.It Em zfs.exists(dataset)
+Returns true if the given dataset exists, or false if it doesn't.
+A fatal error will be thrown if the dataset is not in the target pool.
+That is, in a channel program running on rpool,
+zfs.exists("rpool/nonexistent_fs") returns false, but
+zfs.exists("somepool/fs_that_may_exist") will error.
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Dataset to check for existence.
+Must be in the target pool.
+.Ed
+.It Em zfs.get_prop(dataset, property)
+Returns two values.
+First, a string, number or table containing the property value for the given
+dataset.
+Second, a string containing the source of the property (i.e. the name of the
+dataset in which it was set or nil if it is readonly).
+Throws a Lua error if the dataset is invalid or the property doesn't exist.
+Note that Lua only supports int64 number types whereas ZFS number properties
+are uint64.
+This means very large values (like guid) may wrap around and appear negative.
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Filesystem or snapshot path to retrieve properties from.
+.Ed
+.Pp
+property (string)
+.Bd -ragged -compact -offset "xxxx"
+Name of property to retrieve.
+All filesystem, snapshot and volume properties are supported except
+for 'mounted' and 'iscsioptions.'
+Also supports the 'written@snap' and 'written#bookmark' properties and
+the '<user|group><quota|used>@id' properties, though the id must be in numeric
+form.
+.Ed
+.El
+.Bl -tag -width "xx"
+.It Sy zfs.sync submodule
+The sync submodule contains functions that modify the on-disk state.
+They are executed in "syncing context".
+.Pp
+The available sync submodule functions are as follows:
+.Bl -tag -width "xx"
+.It Em zfs.sync.destroy(dataset, [defer=true|false])
+Destroy the given dataset.
+Returns 0 on successful destroy, or a nonzero error code if the dataset could
+not be destroyed (for example, if the dataset has any active children or
+clones).
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Filesystem or snapshot to be destroyed.
+.Ed
+.Pp
+[optional] defer (boolean)
+.Bd -ragged -compact -offset "xxxx"
+Valid only for destroying snapshots.
+If set to true, and the snapshot has holds or clones, allows the snapshot to be
+marked for deferred deletion rather than failing.
+.Ed
+.It Em zfs.sync.promote(dataset)
+Promote the given clone to a filesystem.
+Returns 0 on successful promotion, or a nonzero error code otherwise.
+If EEXIST is returned, the second return value will be an array of the clone's
+snapshots whose names collide with snapshots of the parent filesystem.
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Clone to be promoted.
+.Ed
+.It Em zfs.sync.rollback(filesystem)
+Rollback to the previous snapshot for a dataset.
+Returns 0 on successful rollback, or a nonzero error code otherwise.
+Rollbacks can be performed on filesystems or zvols, but not on snapshots
+or mounted datasets.
+EBUSY is returned in the case where the filesystem is mounted.
+.Pp
+filesystem (string)
+.Bd -ragged -compact -offset "xxxx"
+Filesystem to rollback.
+.Ed
+.It Em zfs.sync.snapshot(dataset)
+Create a snapshot of a filesystem.
+Returns 0 if the snapshot was successfully created,
+and a nonzero error code otherwise.
+.Pp
+Note: Taking a snapshot will fail on any pool older than legacy version 27.
+To enable taking snapshots from ZCP scripts, the pool must be upgraded.
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Name of snapshot to create.
+.Ed
+.El
+.It Sy zfs.check submodule
+For each function in the zfs.sync submodule, there is a corresponding zfs.check
+function which performs a "dry run" of the same operation.
+Each takes the same arguments as its zfs.sync counterpart and returns 0 if the
+operation would succeed, or a non-zero error code if it would fail, along with
+any other error details.
+That is, each has the same behavior as the corresponding sync function except
+for actually executing the requested change.
+For example,
+.Em zfs.check.destroy("fs")
+returns 0 if
+.Em zfs.sync.destroy("fs")
+would successfully destroy the dataset.
+.Pp
+The available zfs.check functions are:
+.Bl -tag -width "xx"
+.It Em zfs.check.destroy(dataset, [defer=true|false])
+.It Em zfs.check.promote(dataset)
+.It Em zfs.check.rollback(filesystem)
+.It Em zfs.check.snapshot(dataset)
+.El
+.It Sy zfs.list submodule
+The zfs.list submodule provides functions for iterating over datasets and
+properties.
+Rather than returning tables, these functions act as Lua iterators, and are
+generally used as follows:
+.Bd -literal -offset indent
+for child in zfs.list.children("rpool") do
+ ...
+end
+.Ed
+.Pp
+The available zfs.list functions are:
+.Bl -tag -width "xx"
+.It Em zfs.list.clones(snapshot)
+Iterate through all clones of the given snapshot.
+.Pp
+snapshot (string)
+.Bd -ragged -compact -offset "xxxx"
+Must be a valid snapshot path in the current pool.
+.Ed
+.It Em zfs.list.snapshots(dataset)
+Iterate through all snapshots of the given dataset.
+Each snapshot is returned as a string containing the full dataset name, e.g.
+"pool/fs@snap".
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Must be a valid filesystem or volume.
+.Ed
+.It Em zfs.list.children(dataset)
+Iterate through all direct children of the given dataset.
+Each child is returned as a string containing the full dataset name, e.g.
+"pool/fs/child".
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Must be a valid filesystem or volume.
+.Ed
+.It Em zfs.list.properties(dataset)
+Iterate through all user properties for the given dataset.
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Must be a valid filesystem, snapshot, or volume.
+.Ed
+.It Em zfs.list.system_properties(dataset)
+Returns an array of strings, the names of the valid system (non-user defined)
+properties for the given dataset.
+Throws a Lua error if the dataset is invalid.
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Must be a valid filesystem, snapshot or volume.
+.Ed
+.El
+.El
+.Sh EXAMPLES
+.Ss Example 1
+The following channel program recursively destroys a filesystem and all its
+snapshots and children in a naive manner.
+Note that this does not involve any error handling or reporting.
+.Bd -literal -offset indent
+function destroy_recursive(root)
+ for child in zfs.list.children(root) do
+ destroy_recursive(child)
+ end
+ for snap in zfs.list.snapshots(root) do
+ zfs.sync.destroy(snap)
+ end
+ zfs.sync.destroy(root)
+end
+destroy_recursive("pool/somefs")
+.Ed
+.Ss Example 2
+A more verbose and robust version of the same channel program, which
+properly detects and reports errors, and also takes the dataset to destroy
+as a command line argument, would be as follows:
+.Bd -literal -offset indent
+succeeded = {}
+failed = {}
+
+function destroy_recursive(root)
+ for child in zfs.list.children(root) do
+ destroy_recursive(child)
+ end
+ for snap in zfs.list.snapshots(root) do
+ err = zfs.sync.destroy(snap)
+ if (err ~= 0) then
+ failed[snap] = err
+ else
+ succeeded[snap] = err
+ end
+ end
+ err = zfs.sync.destroy(root)
+ if (err ~= 0) then
+ failed[root] = err
+ else
+ succeeded[root] = err
+ end
+end
+
+args = ...
+argv = args["argv"]
+
+destroy_recursive(argv[1])
+
+results = {}
+results["succeeded"] = succeeded
+results["failed"] = failed
+return results
+.Ed
+.Ss Example 3
+The following function performs a forced promote operation by attempting to
+promote the given clone and destroying any conflicting snapshots.
+.Bd -literal -offset indent
+function force_promote(ds)
+ errno, details = zfs.check.promote(ds)
+ if (errno == EEXIST) then
+ assert(details ~= Nil)
+ for i, snap in ipairs(details) do
+ zfs.sync.destroy(ds .. "@" .. snap)
+ end
+ elseif (errno ~= 0) then
+ return errno
+ end
+ return zfs.sync.promote(ds)
+end
+.Ed
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
new file mode 100644
index 000000000000..e060db67867c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
@@ -0,0 +1,3965 @@
+'\" te
+.\" Copyright (c) 2013, Martin Matuska <mm@FreeBSD.org>.
+.\" All Rights Reserved.
+.\"
+.\" 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]
+.\"
+.\" Copyright (c) 2010, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+.\" Copyright (c) 2011, Pawel Jakub Dawidek <pjd@FreeBSD.org>
+.\" Copyright (c) 2012, Glen Barber <gjb@FreeBSD.org>
+.\" Copyright (c) 2012, Bryan Drewery <bdrewery@FreeBSD.org>
+.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+.\" Copyright (c) 2013, Steven Hartland <smh@FreeBSD.org>
+.\" Copyright (c) 2016 Nexenta Systems, Inc. All Rights Reserved.
+.\" Copyright (c) 2014, Xin LI <delphij@FreeBSD.org>
+.\" Copyright (c) 2014-2015, The FreeBSD Foundation, All Rights Reserved.
+.\" Copyright 2019 Joyent, Inc.
+.\" Copyright (c) 2018 Datto Inc.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 16, 2019
+.Dt ZFS 8
+.Os
+.Sh NAME
+.Nm zfs
+.Nd configures ZFS file systems
+.Sh SYNOPSIS
+.Nm
+.Op Fl \&?
+.Nm
+.Cm create
+.Op Fl pu
+.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ... Ar filesystem
+.Nm
+.Cm create
+.Op Fl ps
+.Op Fl b Ar blocksize
+.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
+.Fl V
+.Ar size volume
+.Nm
+.Cm destroy
+.Op Fl fnpRrv
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm destroy
+.Op Fl dnpRrv
+.Sm off
+.Ar filesystem Ns | Ns volume
+.Ns @snap
+.Op % Ns Ar snap
+.Op , Ns Ar snap Op % Ns Ar snap
+.Op , Ns ...
+.Sm on
+.Nm
+.Cm destroy
+.Ar filesystem Ns | Ns Ar volume Ns # Ns Ar bookmark
+.Nm
+.Cm snapshot Ns | Ns Cm snap
+.Op Fl r
+.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
+.Ar filesystem@snapname Ns | Ns Ar volume@snapname
+.Ar filesystem@snapname Ns | Ns Ar volume@snapname Ns ...
+.Nm
+.Cm rollback
+.Op Fl rRf
+.Ar snapshot
+.Nm
+.Cm clone
+.Op Fl p
+.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
+.Ar snapshot filesystem Ns | Ns Ar volume
+.Nm
+.Cm promote
+.Ar clone-filesystem
+.Nm
+.Cm rename
+.Op Fl f
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Nm
+.Cm rename
+.Op Fl f
+.Fl p
+.Ar filesystem Ns | Ns Ar volume
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm rename
+.Fl r
+.Ar snapshot snapshot
+.Nm
+.Cm rename
+.Ar bookmark bookmark
+.Nm
+.Cm rename
+.Fl u
+.Op Fl p
+.Ar filesystem filesystem
+.Nm
+.Cm list
+.Op Fl r Ns | Ns Fl d Ar depth
+.Op Fl Hp
+.Op Fl o Ar property Ns Oo , Ns property Ns Oc Ns ...
+.Op Fl t Ar type Ns Oo , Ns type Ns Oc Ns ...
+.Oo Fl s Ar property Oc Ns ...
+.Oo Fl S Ar property Oc Ns ...
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot | Ns Ar bookmark Ns ...
+.Nm
+.Cm remap
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm set
+.Ar property Ns = Ns Ar value Oo Ar property Ns = Ns Ar value Oc Ns ...
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns ...
+.Nm
+.Cm get
+.Op Fl r Ns | Ns Fl d Ar depth
+.Op Fl Hp
+.Op Fl o Ar all | field Ns Oo , Ns Ar field Oc Ns ...
+.Op Fl t Ar type Ns Oo Ns , Ar type Oc Ns ...
+.Op Fl s Ar source Ns Oo Ns , Ns Ar source Oc Ns ...
+.Ar all | property Ns Oo Ns , Ns Ar property Oc Ns ...
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns ...
+.Nm
+.Cm inherit
+.Op Fl rS
+.Ar property
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns ...
+.Nm
+.Cm upgrade
+.Op Fl v
+.Nm
+.Cm upgrade
+.Op Fl r
+.Op Fl V Ar version
+.Fl a | Ar filesystem
+.Nm
+.Cm userspace
+.Op Fl Hinp
+.Op Fl o Ar field Ns Oo , Ns Ar field Oc Ns ...
+.Oo Fl s Ar field Oc Ns ...
+.Oo Fl S Ar field Oc Ns ...
+.Op Fl t Ar type Ns Oo Ns , Ns Ar type Oc Ns ...
+.Ar filesystem Ns | Ns Ar snapshot
+.Nm
+.Cm groupspace
+.Op Fl Hinp
+.Op Fl o Ar field Ns Oo , Ns field Oc Ns ...
+.Oo Fl s Ar field Oc Ns ...
+.Oo Fl S Ar field Oc Ns ...
+.Op Fl t Ar type Ns Oo Ns , Ns Ar type Oc Ns ...
+.Ar filesystem Ns | Ns Ar snapshot
+.Nm
+.Cm mount
+.Nm
+.Cm mount
+.Op Fl vO
+.Op Fl o Ar property Ns Oo , Ns Ar property Oc Ns ...
+.Fl a | Ar filesystem
+.Nm
+.Cm unmount Ns | Ns Cm umount
+.Op Fl f
+.Fl a | Ar filesystem Ns | Ns Ar mountpoint
+.Nm
+.Cm share
+.Fl a | Ar filesystem
+.Nm
+.Cm unshare
+.Fl a | Ar filesystem Ns | Ns Ar mountpoint
+.Nm
+.Cm bookmark
+.Ar snapshot
+.Ar bookmark
+.Nm
+.Cm send
+.Op Fl DLPRVcenpv
+.Op Fl i Ar snapshot | Fl I Ar snapshot
+.Ar snapshot
+.Nm
+.Cm send
+.Op Fl LPcenv
+.Op Fl i Ar snapshot Ns | Ns Ar bookmark
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Nm
+.Cm send
+.Op Fl PVenv
+.Fl t Ar receive_resume_token
+.Nm
+.Cm receive Ns | Ns Cm recv
+.Op Fl vnsFu
+.Op Fl o Sy origin Ns = Ns Ar snapshot
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Nm
+.Cm receive Ns | Ns Cm recv
+.Op Fl vnsFu
+.Op Fl d | e
+.Op Fl o Sy origin Ns = Ns Ar snapshot
+.Ar filesystem
+.Nm
+.Cm receive Ns | Ns Cm recv
+.Fl A
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm allow
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm allow
+.Op Fl ldug
+.Ar user Ns | Ns Ar group Ns Oo Ns , Ns Ar user Ns | Ns Ar group Oc Ns ...
+.Ar perm Ns | Ns Ar @setname Ns
+.Oo Ns , Ns Ar perm Ns | Ns Ar @setname Oc Ns ...
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm allow
+.Op Fl ld
+.Fl e Ns | Ns Cm everyone
+.Ar perm Ns | Ns Ar @setname Ns Op Ns , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ...
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm allow
+.Fl c
+.Ar perm Ns | Ns Ar @setname Ns Op Ns , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ...
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm allow
+.Fl s
+.Ar @setname
+.Ar perm Ns | Ns Ar @setname Ns Op Ns , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ...
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm unallow
+.Op Fl rldug
+.Ar user Ns | Ns Ar group Ns Oo Ns , Ns Ar user Ns | Ns Ar group Oc Ns ...
+.Oo Ar perm Ns | Ns Ar @setname Ns Op , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ... Oc
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm unallow
+.Op Fl rld
+.Fl e Ns | Ns Cm everyone
+.Oo Ar perm Ns | Ns Ar @setname Ns Op , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ... Oc
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm unallow
+.Op Fl r
+.Fl c
+.Oo Ar perm Ns | Ns Ar @setname Ns Op , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ... Oc
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm unallow
+.Op Fl r
+.Fl s
+.Ar @setname
+.Oo Ar perm Ns | Ns Ar @setname Ns Op , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ... Oc
+.Ar filesystem Ns | Ns Ar volume
+.Nm
+.Cm hold
+.Op Fl r
+.Ar tag snapshot Ns ...
+.Nm
+.Cm holds
+.Op Fl Hp
+.Op Fl r Ns | Ns Fl d Ar depth
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns
+.Ns ...
+.Nm
+.Cm release
+.Op Fl r
+.Ar tag snapshot Ns ...
+.Nm
+.Cm diff
+.Op Fl FHt
+.Ar snapshot
+.Op Ar snapshot Ns | Ns Ar filesystem
+.Nm
+.Cm program
+.Op Fl jn
+.Op Fl t Ar timeout
+.Op Fl m Ar memory_limit
+.Ar pool script
+.Op Ar arg1 No ...
+.Nm
+.Cm jail
+.Ar jailid Ns | Ns Ar jailname filesystem
+.Nm
+.Cm unjail
+.Ar jailid Ns | Ns Ar jailname filesystem
+.Sh DESCRIPTION
+The
+.Nm
+command configures
+.Tn ZFS
+datasets within a
+.Tn ZFS
+storage pool, as described in
+.Xr zpool 8 .
+A dataset is identified by a unique path within the
+.Tn ZFS
+namespace. For example:
+.Bd -ragged -offset 4n
+.No pool/ Ns Brq filesystem,volume,snapshot
+.Ed
+.Pp
+where the maximum length of a dataset name is
+.Dv MAXNAMELEN
+(256 bytes)
+and the maximum amount of nesting allowed in a path is 50 levels deep.
+.Pp
+A dataset can be one of the following:
+.Bl -hang -width 12n
+.It Sy file system
+A
+.Tn ZFS
+dataset of type
+.Em filesystem
+can be mounted within the standard system namespace and behaves like other file
+systems. While
+.Tn ZFS
+file systems are designed to be
+.Tn POSIX
+compliant, known issues exist that prevent compliance in some cases.
+Applications that depend on standards conformance might fail due to nonstandard
+behavior when checking file system free space.
+.It Sy volume
+A logical volume exported as a raw or block device. This type of dataset should
+only be used under special circumstances. File systems are typically used in
+most environments.
+.It Sy snapshot
+A read-only version of a file system or volume at a given point in time. It is
+specified as
+.Em filesystem@name
+or
+.Em volume@name .
+.El
+.Ss ZFS File System Hierarchy
+A
+.Tn ZFS
+storage pool is a logical collection of devices that provide space for
+datasets. A storage pool is also the root of the
+.Tn ZFS
+file system hierarchy.
+.Pp
+The root of the pool can be accessed as a file system, such as mounting and
+unmounting, taking snapshots, and setting properties. The physical storage
+characteristics, however, are managed by the
+.Xr zpool 8
+command.
+.Pp
+See
+.Xr zpool 8
+for more information on creating and administering pools.
+.Ss Snapshots
+A snapshot is a read-only copy of a file system or volume. Snapshots can be
+created extremely quickly, and initially consume no additional space within the
+pool. As data within the active dataset changes, the snapshot consumes more
+data than would otherwise be shared with the active dataset.
+.Pp
+Snapshots can have arbitrary names. Snapshots of volumes can be cloned or
+rolled back, but cannot be accessed independently.
+.Pp
+File system snapshots can be accessed under the
+.Pa \&.zfs/snapshot
+directory in the root of the file system. Snapshots are automatically mounted
+on demand and may be unmounted at regular intervals. The visibility of the
+.Pa \&.zfs
+directory can be controlled by the
+.Sy snapdir
+property.
+.Ss Clones
+A clone is a writable volume or file system whose initial contents are the same
+as another dataset. As with snapshots, creating a clone is nearly
+instantaneous, and initially consumes no additional space.
+.Pp
+Clones can only be created from a snapshot. When a snapshot is cloned, it
+creates an implicit dependency between the parent and child. Even though the
+clone is created somewhere else in the dataset hierarchy, the original snapshot
+cannot be destroyed as long as a clone exists. The
+.Sy origin
+property exposes this dependency, and the
+.Cm destroy
+command lists any such dependencies, if they exist.
+.Pp
+The clone parent-child dependency relationship can be reversed by using the
+.Cm promote
+subcommand. This causes the "origin" file system to become a clone of the
+specified file system, which makes it possible to destroy the file system that
+the clone was created from.
+.Ss Mount Points
+Creating a
+.Tn ZFS
+file system is a simple operation, so the number of file systems per system is
+likely to be numerous. To cope with this,
+.Tn ZFS
+automatically manages mounting and unmounting file systems without the need to
+edit the
+.Pa /etc/fstab
+file. All automatically managed file systems are mounted by
+.Tn ZFS
+at boot time.
+.Pp
+By default, file systems are mounted under
+.Pa /path ,
+where
+.Ar path
+is the name of the file system in the
+.Tn ZFS
+namespace. Directories are created and destroyed as needed.
+.Pp
+A file system can also have a mount point set in the
+.Sy mountpoint
+property. This directory is created as needed, and
+.Tn ZFS
+automatically mounts the file system when the
+.Qq Nm Cm mount Fl a
+command is invoked (without editing
+.Pa /etc/fstab ) .
+The
+.Sy mountpoint
+property can be inherited, so if
+.Em pool/home
+has a mount point of
+.Pa /home ,
+then
+.Em pool/home/user
+automatically inherits a mount point of
+.Pa /home/user .
+.Pp
+A file system
+.Sy mountpoint
+property of
+.Cm none
+prevents the file system from being mounted.
+.Pp
+If needed,
+.Tn ZFS
+file systems can also be managed with traditional tools
+.Pq Xr mount 8 , Xr umount 8 , Xr fstab 5 .
+If a file system's mount point is set to
+.Cm legacy ,
+.Tn ZFS
+makes no attempt to manage the file system, and the administrator is
+responsible for mounting and unmounting the file system.
+.Ss Jails
+.No A Tn ZFS
+dataset can be attached to a jail by using the
+.Qq Nm Cm jail
+subcommand. You cannot attach a dataset to one jail and the children of the
+same dataset to another jail. You can also not attach the root file system
+of the jail or any dataset which needs to be mounted before the zfs rc script
+is run inside the jail, as it would be attached unmounted until it is
+mounted from the rc script inside the jail. To allow management of the
+dataset from within a jail, the
+.Sy jailed
+property has to be set and the jail needs access to the
+.Pa /dev/zfs
+device. The
+.Sy quota
+property cannot be changed from within a jail. See
+.Xr jail 8
+for information on how to allow mounting
+.Tn ZFS
+datasets from within a jail.
+.Pp
+.No A Tn ZFS
+dataset can be detached from a jail using the
+.Qq Nm Cm unjail
+subcommand.
+.Pp
+After a dataset is attached to a jail and the jailed property is set, a jailed
+file system cannot be mounted outside the jail, since the jail administrator
+might have set the mount point to an unacceptable value.
+.Ss Deduplication
+Deduplication is the process for removing redundant data at the block-level,
+reducing the total amount of data stored. If a file system has the
+.Cm dedup
+property enabled, duplicate data blocks are removed synchronously. The result
+is that only unique data is stored and common components are shared among
+files.
+.Ss Native Properties
+Properties are divided into two types, native properties and user-defined (or
+"user") properties. Native properties either export internal statistics or
+control
+.Tn ZFS
+behavior. In addition, native properties are either editable or read-only. User
+properties have no effect on
+.Tn ZFS
+behavior, but you can use them to annotate datasets in a way that is meaningful
+in your environment. For more information about user properties, see the
+.Qq Sx User Properties
+section, below.
+.Pp
+Every dataset has a set of properties that export statistics about the dataset
+as well as control various behaviors. Properties are inherited from the parent
+unless overridden by the child. Some properties apply only to certain types of
+datasets (file systems, volumes, or snapshots).
+.Pp
+The values of numeric properties can be specified using human-readable suffixes
+(for example,
+.Sy k , KB , M , Gb ,
+and so forth, up to
+.Sy Z
+for zettabyte). The following are all valid (and equal) specifications:
+.Bd -ragged -offset 4n
+1536M, 1.5g, 1.50GB
+.Ed
+.Pp
+The values of non-numeric properties are case sensitive and must be lowercase,
+except for
+.Sy mountpoint , sharenfs , No and Sy sharesmb .
+.Pp
+The following native properties consist of read-only statistics about the
+dataset. These properties can be neither set, nor inherited. Native properties
+apply to all dataset types unless otherwise noted.
+.Bl -tag -width 2n
+.It Sy available
+The amount of space available to the dataset and all its children, assuming
+that there is no other activity in the pool. Because space is shared within a
+pool, availability can be limited by any number of factors, including physical
+pool size, quotas, reservations, or other datasets within the pool.
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy avail .
+.It Sy compressratio
+For non-snapshots, the compression ratio achieved for the
+.Sy used
+space of this dataset, expressed as a multiplier. The
+.Sy used
+property includes descendant datasets, and, for clones, does not include
+the space shared with the origin snapshot. For snapshots, the
+.Sy compressratio
+is the same as the
+.Sy refcompressratio
+property. Compression can be turned on by running:
+.Qq Nm Cm set compression=on Ar dataset
+The default value is
+.Cm off .
+.It Sy createtxg
+The transaction group (txg) in which the dataset was created.
+Bookmarks have the same
+.Sy createtxg
+as the snapshot they are initially tied to.
+This property is suitable for ordering a list of snapshots,
+e.g. for incremental send and receive.
+.It Sy creation
+The time this dataset was created.
+.It Sy clones
+For snapshots, this property is a comma-separated list of filesystems or
+volumes which are clones of this snapshot. The clones'
+.Sy origin
+property is this snapshot. If the
+.Sy clones
+property is not empty, then this snapshot can not be destroyed (even with the
+.Fl r
+or
+.Fl f
+options).
+.It Sy defer_destroy
+This property is
+.Cm on
+if the snapshot has been marked for deferred destroy by using the
+.Qq Nm Cm destroy -d
+command. Otherwise, the property is
+.Cm off .
+.It Sy filesystem_count
+The total number of filesystems and volumes that exist under this location in the
+dataset tree.
+This value is only available when a
+.Sy filesystem_limit
+has
+been set somewhere in the tree under which the dataset resides.
+.It Sy guid
+The 64 bit GUID of this dataset or bookmark which does not change over its
+entire lifetime.
+When a snapshot is sent to another pool, the received snapshot has the same
+GUID.
+Thus, the
+.Sy guid
+is suitable to identify a snapshot across pools.
+.It Sy logicalreferenced
+The amount of space that is
+.Qq logically
+accessible by this dataset.
+See the
+.Sy referenced
+property.
+The logical space ignores the effect of the
+.Sy compression
+and
+.Sy copies
+properties, giving a quantity closer to the amount of data that applications
+see.
+However, it does include space consumed by metadata.
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy lrefer .
+.It Sy logicalused
+The amount of space that is
+.Qq logically
+consumed by this dataset and all its descendents.
+See the
+.Sy used
+property.
+The logical space ignores the effect of the
+.Sy compression
+and
+.Sy copies
+properties, giving a quantity closer to the amount of data that applications
+see.
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy lused .
+.It Sy mounted
+For file systems, indicates whether the file system is currently mounted. This
+property can be either
+.Cm yes
+or
+.Cm no .
+.It Sy origin
+For cloned file systems or volumes, the snapshot from which the clone was
+created. See also the
+.Sy clones
+property.
+.It Sy receive_resume_token
+For filesystems or volumes which have saved partially-completed state from
+.Sy zfs receive -s ,
+this opaque token can be provided to
+.Sy zfs send -t
+to resume and complete the
+.Sy zfs receive .
+.It Sy referenced
+The amount of data that is accessible by this dataset, which may or may not be
+shared with other datasets in the pool. When a snapshot or clone is created, it
+initially references the same amount of space as the file system or snapshot it
+was created from, since its contents are identical.
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy refer .
+.It Sy refcompressratio
+The compression ratio achieved for the
+.Sy referenced
+space of this dataset, expressed as a multiplier. See also the
+.Sy compressratio
+property.
+.It Sy snapshot_count
+The total number of snapshots that exist under this location in the dataset tree.
+This value is only available when a
+.Sy snapshot_limit
+has been set somewhere
+in the tree under which the dataset resides.
+.It Sy type
+The type of dataset:
+.Sy filesystem , volume , No or Sy snapshot .
+.It Sy used
+The amount of space consumed by this dataset and all its descendents. This is
+the value that is checked against this dataset's quota and reservation. The
+space used does not include this dataset's reservation, but does take into
+account the reservations of any descendent datasets. The amount of space that a
+dataset consumes from its parent, as well as the amount of space that are freed
+if this dataset is recursively destroyed, is the greater of its space used and
+its reservation.
+.Pp
+When snapshots (see the
+.Qq Sx Snapshots
+section) are created, their space is
+initially shared between the snapshot and the file system, and possibly with
+previous snapshots. As the file system changes, space that was previously
+shared becomes unique to the snapshot, and counted in the snapshot's space
+used. Additionally, deleting snapshots can increase the amount of space unique
+to (and used by) other snapshots.
+.Pp
+The amount of space used, available, or referenced does not take into account
+pending changes. Pending changes are generally accounted for within a few
+seconds. Committing a change to a disk using
+.Xr fsync 2
+or
+.Sy O_SYNC
+does not necessarily guarantee that the space usage information is updated
+immediately.
+.It Sy usedby*
+The
+.Sy usedby*
+properties decompose the
+.Sy used
+properties into the various reasons that space is used. Specifically,
+.Sy used No =
+.Sy usedbysnapshots + usedbydataset + usedbychildren + usedbyrefreservation .
+These properties are only available for datasets created
+with
+.Tn ZFS
+pool version 13 pools and higher.
+.It Sy usedbysnapshots
+The amount of space consumed by snapshots of this dataset. In particular, it is
+the amount of space that would be freed if all of this dataset's snapshots were
+destroyed. Note that this is not simply the sum of the snapshots'
+.Sy used
+properties because space can be shared by multiple snapshots.
+.It Sy usedbydataset
+The amount of space used by this dataset itself, which would be freed if the
+dataset were destroyed (after first removing any
+.Sy refreservation
+and destroying any necessary snapshots or descendents).
+.It Sy usedbychildren
+The amount of space used by children of this dataset, which would be freed if
+all the dataset's children were destroyed.
+.It Sy usedbyrefreservation
+The amount of space used by a
+.Sy refreservation
+set on this dataset, which would be freed if the
+.Sy refreservation
+was removed.
+.It Sy userused@ Ns Ar user
+The amount of space consumed by the specified user in this dataset. Space is
+charged to the owner of each file, as displayed by
+.Qq Nm ls Fl l .
+The amount of space charged is displayed by
+.Qq Nm du
+and
+.Qq Nm ls Fl s .
+See the
+.Qq Nm Cm userspace
+subcommand for more information.
+.Pp
+Unprivileged users can access only their own space usage. The root user, or a
+user who has been granted the
+.Sy userused
+privilege with
+.Qq Nm Cm allow ,
+can access everyone's usage.
+.Pp
+The
+.Sy userused@ Ns ...
+properties are not displayed by
+.Qq Nm Cm get all .
+The user's name must be appended after the
+.Sy @
+symbol, using one of the following forms:
+.Bl -bullet -offset 2n
+.It
+POSIX name (for example,
+.Em joe )
+.It
+POSIX numeric ID (for example,
+.Em 1001 )
+.El
+.It Sy userrefs
+This property is set to the number of user holds on this snapshot. User holds
+are set by using the
+.Qq Nm Cm hold
+command.
+.It Sy groupused@ Ns Ar group
+The amount of space consumed by the specified group in this dataset. Space is
+charged to the group of each file, as displayed by
+.Nm ls Fl l .
+See the
+.Sy userused@ Ns Ar user
+property for more information.
+.Pp
+Unprivileged users can only access their own groups' space usage. The root
+user, or a user who has been granted the
+.Sy groupused
+privilege with
+.Qq Nm Cm allow ,
+can access all groups' usage.
+.It Sy volblocksize Ns = Ns Ar blocksize
+For volumes, specifies the block size of the volume. The
+.Ar blocksize
+cannot be changed once the volume has been written, so it should be set at
+volume creation time. The default
+.Ar blocksize
+for volumes is 8 Kbytes. Any
+power of 2 from 512 bytes to 128 Kbytes is valid.
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy volblock .
+.It Sy written
+The amount of
+.Sy referenced
+space written to this dataset since the previous snapshot.
+.It Sy written@ Ns Ar snapshot
+The amount of
+.Sy referenced
+space written to this dataset since the specified snapshot. This is the space
+that is referenced by this dataset but was not referenced by the specified
+snapshot.
+.Pp
+The
+.Ar snapshot
+may be specified as a short snapshot name (just the part after the
+.Sy @ ) ,
+in which case it will be interpreted as a snapshot in the same filesystem as
+this dataset. The
+.Ar snapshot
+may be a full snapshot name
+.Pq Em filesystem@snapshot ,
+which for clones may be a snapshot in the origin's filesystem (or the origin of
+the origin's filesystem, etc).
+.El
+.Pp
+The following native properties can be used to change the behavior of a
+.Tn ZFS
+dataset.
+.Bl -tag -width 2n
+.It Xo
+.Sy aclinherit Ns = Ns Cm discard |
+.Cm noallow |
+.Cm restricted |
+.Cm passthrough |
+.Cm passthrough-x
+.Xc
+Controls how
+.Tn ACL
+entries are inherited when files and directories are created. A file system
+with an
+.Sy aclinherit
+property of
+.Cm discard
+does not inherit any
+.Tn ACL
+entries. A file system with an
+.Sy aclinherit
+property value of
+.Cm noallow
+only inherits inheritable
+.Tn ACL
+entries that specify "deny" permissions. The property value
+.Cm restricted
+(the default) removes the
+.Em write_acl
+and
+.Em write_owner
+permissions when the
+.Tn ACL
+entry is inherited. A file system with an
+.Sy aclinherit
+property value of
+.Cm passthrough
+inherits all inheritable
+.Tn ACL
+entries without any modifications made to the
+.Tn ACL
+entries when they are inherited. A file system with an
+.Sy aclinherit
+property value of
+.Cm passthrough-x
+has the same meaning as
+.Cm passthrough ,
+except that the
+.Em owner@ , group@ , No and Em everyone@ Tn ACE Ns s
+inherit the execute permission only if the file creation mode also requests the
+execute bit.
+.Pp
+When the property value is set to
+.Cm passthrough ,
+files are created with a mode determined by the inheritable
+.Tn ACE Ns s.
+If no inheritable
+.Tn ACE Ns s
+exist that affect the mode, then the mode is set in accordance to the requested
+mode from the application.
+.It Sy aclmode Ns = Ns Cm discard | groupmask | passthrough | restricted
+Controls how an
+.Tn ACL
+is modified during
+.Xr chmod 2 .
+A file system with an
+.Sy aclmode
+property of
+.Cm discard
+(the default) deletes all
+.Tn ACL
+entries that do not represent the mode of the file. An
+.Sy aclmode
+property of
+.Cm groupmask
+reduces permissions granted in all
+.Em ALLOW
+entries found in the
+.Tn ACL
+such that they are no greater than the group permissions specified by
+.Xr chmod 2 .
+A file system with an
+.Sy aclmode
+property of
+.Cm passthrough
+indicates that no changes are made to the
+.Tn ACL
+other than creating or updating the necessary
+.Tn ACL
+entries to represent the new mode of the file or directory.
+An
+.Sy aclmode
+property of
+.Cm restricted
+will cause the
+.Xr chmod 2
+operation to return an error when used on any file or directory which has
+a non-trivial
+.Tn ACL
+whose entries can not be represented by a mode.
+.Xr chmod 2
+is required to change the set user ID, set group ID, or sticky bits on a file
+or directory, as they do not have equivalent
+.Tn ACL
+entries.
+In order to use
+.Xr chmod 2
+on a file or directory with a non-trivial
+.Tn ACL
+when
+.Sy aclmode
+is set to
+.Cm restricted ,
+you must first remove all
+.Tn ACL
+entries which do not represent the current mode.
+.It Sy atime Ns = Ns Cm on | off
+Controls whether the access time for files is updated when they are read.
+Turning this property off avoids producing write traffic when reading files and
+can result in significant performance gains, though it might confuse mailers
+and other similar utilities. The default value is
+.Cm on .
+.It Sy canmount Ns = Ns Cm on | off | noauto
+If this property is set to
+.Cm off ,
+the file system cannot be mounted, and is ignored by
+.Qq Nm Cm mount Fl a .
+Setting this property to
+.Cm off
+is similar to setting the
+.Sy mountpoint
+property to
+.Cm none ,
+except that the dataset still has a normal
+.Sy mountpoint
+property, which can be inherited. Setting this property to
+.Cm off
+allows datasets to be used solely as a mechanism to inherit properties. One
+example of setting
+.Sy canmount Ns = Ns Cm off
+is to have two datasets with the same
+.Sy mountpoint ,
+so that the children of both datasets appear in the same directory, but might
+have different inherited characteristics.
+.Pp
+When the
+.Cm noauto
+value is set, a dataset can only be mounted and unmounted explicitly. The
+dataset is not mounted automatically when the dataset is created or imported,
+nor is it mounted by the
+.Qq Nm Cm mount Fl a
+command or unmounted by the
+.Qq Nm Cm umount Fl a
+command.
+.Pp
+This property is not inherited.
+.It Sy checksum Ns = Ns Cm on | off | fletcher2 | fletcher4 | sha256 | noparity | sha512 | skein
+Controls the checksum used to verify data integrity. The default value is
+.Cm on ,
+which automatically selects an appropriate algorithm (currently,
+.Cm fletcher4 ,
+but this may change in future releases). The value
+.Cm off
+disables integrity checking on user data.
+The value
+.Cm noparity
+not only
+disables integrity but also disables maintaining parity for user data. This
+setting is used internally by a dump device residing on a RAID-Z pool and should
+not be used by any other dataset.
+Disabling checksums is
+.Em NOT
+a recommended practice.
+The
+.Sy sha512 ,
+and
+.Sy skein
+checksum algorithms require enabling the appropriate features on the pool.
+Please see
+.Xr zpool-features 7
+for more information on these algorithms.
+.Pp
+Changing this property affects only newly-written data.
+.Pp
+Salted checksum algorithms
+.Pq Cm edonr , skein
+are currently not supported for any filesystem on the boot pools.
+.It Sy compression Ns = Ns Cm on | off | lzjb | gzip | gzip- Ns Ar N | Cm zle | Cm lz4
+Controls the compression algorithm used for this dataset.
+Setting compression to
+.Cm on
+indicates that the current default compression algorithm should be used.
+The default balances compression and decompression speed, with compression
+ratio and is expected to work well on a wide variety of workloads.
+Unlike all other settings for this property, on does not select a fixed
+compression type.
+As new compression algorithms are added to ZFS and enabled on a pool, the
+default compression algorithm may change.
+The current default compression algorthm is either
+.Cm lzjb
+or, if the
+.Sy lz4_compress
+feature is enabled,
+.Cm lz4 .
+The
+.Cm lzjb
+compression algorithm is optimized for performance while providing decent data
+compression. Setting compression to
+.Cm on
+uses the
+.Cm lzjb
+compression algorithm. The
+.Cm gzip
+compression algorithm uses the same compression as the
+.Xr gzip 1
+command. You can specify the
+.Cm gzip
+level by using the value
+.Cm gzip- Ns Ar N
+where
+.Ar N
+is an integer from 1 (fastest) to 9 (best compression ratio). Currently,
+.Cm gzip
+is equivalent to
+.Cm gzip-6
+(which is also the default for
+.Xr gzip 1 ) .
+The
+.Cm zle
+compression algorithm compresses runs of zeros.
+.Pp
+The
+.Sy lz4
+compression algorithm is a high-performance replacement
+for the
+.Sy lzjb
+algorithm. It features significantly faster
+compression and decompression, as well as a moderately higher
+compression ratio than
+.Sy lzjb ,
+but can only be used on pools with
+the
+.Sy lz4_compress
+feature set to
+.Sy enabled .
+See
+.Xr zpool-features 7
+for details on ZFS feature flags and the
+.Sy lz4_compress
+feature.
+.Pp
+This property can also be referred to by its shortened column name
+.Cm compress .
+Changing this property affects only newly-written data.
+.It Sy copies Ns = Ns Cm 1 | 2 | 3
+Controls the number of copies of data stored for this dataset. These copies are
+in addition to any redundancy provided by the pool, for example, mirroring or
+RAID-Z. The copies are stored on different disks, if possible. The space used
+by multiple copies is charged to the associated file and dataset, changing the
+.Sy used
+property and counting against quotas and reservations.
+.Pp
+Changing this property only affects newly-written data. Therefore, set this
+property at file system creation time by using the
+.Fl o Cm copies= Ns Ar N
+option.
+.It Sy dedup Ns = Ns Cm on | off | verify | sha256 Ns Oo Cm ,verify Oc | Sy sha512 Ns Oo Cm ,verify Oc | Sy skein Ns Oo Cm ,verify Oc
+Configures deduplication for a dataset. The default value is
+.Cm off .
+The default deduplication checksum is
+.Cm sha256
+(this may change in the future).
+When
+.Sy dedup
+is enabled, the checksum defined here overrides the
+.Sy checksum
+property. Setting the value to
+.Cm verify
+has the same effect as the setting
+.Cm sha256,verify .
+.Pp
+If set to
+.Cm verify ,
+.Tn ZFS
+will do a byte-to-byte comparsion in case of two blocks having the same
+signature to make sure the block contents are identical.
+.It Sy devices Ns = Ns Cm on | off
+The
+.Sy devices
+property is currently not supported on
+.Fx .
+.It Sy exec Ns = Ns Cm on | off
+Controls whether processes can be executed from within this file system. The
+default value is
+.Cm on .
+.It Sy mlslabel Ns = Ns Ar label | Cm none
+The
+.Sy mlslabel
+property is currently not supported on
+.Fx .
+.It Sy filesystem_limit Ns = Ns Ar count | Cm none
+Limits the number of filesystems and volumes that can exist under this point in
+the dataset tree.
+The limit is not enforced if the user is allowed to change
+the limit.
+Setting a
+.Sy filesystem_limit
+on a descendent of a filesystem that
+already has a
+.Sy filesystem_limit
+does not override the ancestor's
+.Sy filesystem_limit ,
+but rather imposes an additional limit.
+This feature must be enabled to be used
+.Po see
+.Xr zpool-features 7
+.Pc .
+.It Sy special_small_blocks Ns = Ns Ar size
+This value represents the threshold block size for including small file
+blocks into the special allocation class.
+Blocks smaller than or equal to this value will be assigned to the special
+allocation class while greater blocks will be assigned to the regular class.
+Valid values are zero or a power of two from 512B up to 128K.
+The default size is 0 which means no small file blocks will be allocated in
+the special class.
+.Pp
+Before setting this property, a special class vdev must be added to the
+pool.
+See
+.Xr zpool 8
+for more details on the special allocation class.
+.It Sy mountpoint Ns = Ns Ar path | Cm none | legacy
+Controls the mount point used for this file system.
+See the
+.Qq Sx Mount Points
+section for more information on how this property is used.
+.Pp
+When the
+.Sy mountpoint
+property is changed for a file system, the file system and any children that
+inherit the mount point are unmounted. If the new value is
+.Cm legacy ,
+then they remain unmounted. Otherwise, they are automatically remounted in the
+new location if the property was previously
+.Cm legacy
+or
+.Cm none ,
+or if they were mounted before the property was changed. In addition, any
+shared file systems are unshared and shared in the new location.
+.It Sy nbmand Ns = Ns Cm on | off
+The
+.Sy nbmand
+property is currently not supported on
+.Fx .
+.It Sy primarycache Ns = Ns Cm all | none | metadata
+Controls what is cached in the primary cache (ARC). If this property is set to
+.Cm all ,
+then both user data and metadata is cached. If this property is set to
+.Cm none ,
+then neither user data nor metadata is cached. If this property is set to
+.Cm metadata ,
+then only metadata is cached. The default value is
+.Cm all .
+.It Sy quota Ns = Ns Ar size | Cm none
+Limits the amount of space a dataset and its descendents can consume. This
+property enforces a hard limit on the amount of space used. This includes all
+space consumed by descendents, including file systems and snapshots. Setting a
+quota on a descendent of a dataset that already has a quota does not override
+the ancestor's quota, but rather imposes an additional limit.
+.Pp
+Quotas cannot be set on volumes, as the
+.Sy volsize
+property acts as an implicit quota.
+.It Sy snapshot_limit Ns = Ns Ar count | Cm none
+Limits the number of snapshots that can be created on a dataset and its
+descendents.
+Setting a
+.Sy snapshot_limit
+on a descendent of a dataset that already
+has a
+.Sy snapshot_limit
+does not override the ancestor's
+.Sy snapshot_limit ,
+but
+rather imposes an additional limit.
+The limit is not enforced if the user is
+allowed to change the limit.
+For example, this means that recursive snapshots
+taken from the global zone are counted against each delegated dataset within
+a jail.
+This feature must be enabled to be used
+.Po see
+.Xr zpool-features 7
+.Pc .
+.It Sy userquota@ Ns Ar user Ns = Ns Ar size | Cm none
+Limits the amount of space consumed by the specified user.
+Similar to the
+.Sy refquota
+property, the
+.Sy userquota
+space calculation does not include space that is used by descendent datasets,
+such as snapshots and clones. User space consumption is identified by the
+.Sy userspace@ Ns Ar user
+property.
+.Pp
+Enforcement of user quotas may be delayed by several seconds. This delay means
+that a user might exceed their quota before the system notices that they are
+over quota and begins to refuse additional writes with the
+.Em EDQUOT
+error message. See the
+.Cm userspace
+subcommand for more information.
+.Pp
+Unprivileged users can only access their own groups' space usage. The root
+user, or a user who has been granted the
+.Sy userquota
+privilege with
+.Qq Nm Cm allow ,
+can get and set everyone's quota.
+.Pp
+This property is not available on volumes, on file systems before version 4, or
+on pools before version 15. The
+.Sy userquota@ Ns ...
+properties are not displayed by
+.Qq Nm Cm get all .
+The user's name must be appended after the
+.Sy @
+symbol, using one of the following forms:
+.Bl -bullet -offset 2n
+.It
+POSIX name (for example,
+.Em joe )
+.It
+POSIX numeric ID (for example,
+.Em 1001 )
+.El
+.It Sy groupquota@ Ns Ar group Ns = Ns Ar size | Cm none
+Limits the amount of space consumed by the specified group. Group space
+consumption is identified by the
+.Sy userquota@ Ns Ar user
+property.
+.Pp
+Unprivileged users can access only their own groups' space usage. The root
+user, or a user who has been granted the
+.Sy groupquota
+privilege with
+.Qq Nm Cm allow ,
+can get and set all groups' quotas.
+.It Sy readonly Ns = Ns Cm on | off
+Controls whether this dataset can be modified. The default value is
+.Cm off .
+.It Sy recordsize Ns = Ns Ar size
+Specifies a suggested block size for files in the file system. This property is
+designed solely for use with database workloads that access files in fixed-size
+records.
+.Tn ZFS
+automatically tunes block sizes according to internal algorithms optimized for
+typical access patterns.
+.Pp
+For databases that create very large files but access them in small random
+chunks, these algorithms may be suboptimal. Specifying a
+.Sy recordsize
+greater than or equal to the record size of the database can result in
+significant performance gains. Use of this property for general purpose file
+systems is strongly discouraged, and may adversely affect performance.
+.Pp
+The size specified must be a power of two greater than or equal to 512 and less
+than or equal to 128 Kbytes.
+If the
+.Sy large_blocks
+feature is enabled on the pool, the size may be up to 1 Mbyte.
+See
+.Xr zpool-features 7
+for details on ZFS feature flags.
+.Pp
+Changing the file system's
+.Sy recordsize
+affects only files created afterward; existing files are unaffected.
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy recsize .
+.It Sy redundant_metadata Ns = Ns Cm all | most
+Controls what types of metadata are stored redundantly.
+ZFS stores an extra copy of metadata, so that if a single block is corrupted,
+the amount of user data lost is limited.
+This extra copy is in addition to any redundancy provided at the pool level
+.Pq e.g. by mirroring or RAID-Z ,
+and is in addition to an extra copy specified by the
+.Sy copies
+property
+.Pq up to a total of 3 copies .
+For example if the pool is mirrored,
+.Cm copies Ns = Ns Ar 2 ,
+and
+.Cm redundant_metadata Ns = Ns Ar most ,
+then ZFS
+stores 6 copies of most metadata, and 4 copies of data and some
+metadata.
+.Pp
+When set to
+.Cm all ,
+ZFS stores an extra copy of all metadata.
+If a
+single on-disk block is corrupt, at worst a single block of user data
+.Po which is
+.Cm recordsize
+bytes long
+can be lost.
+.Pc
+.Pp
+When set to
+.Cm most ,
+ZFS stores an extra copy of most types of
+metadata.
+This can improve performance of random writes, because less
+metadata must be written.
+In practice, at worst about 100 blocks
+.Po of
+.Cm recordsize
+bytes each
+.Pc
+of user data can be lost if a single
+on-disk block is corrupt.
+The exact behavior of which metadata blocks
+are stored redundantly may change in future releases.
+.Pp
+The default value is
+.Cm all .
+.It Sy refquota Ns = Ns Ar size | Cm none
+Limits the amount of space a dataset can consume. This property enforces a hard
+limit on the amount of space used. This hard limit does not include space used
+by descendents, including file systems and snapshots.
+.It Sy refreservation Ns = Ns Ar size | Cm none | Cm auto
+The minimum amount of space guaranteed to a dataset, not including its
+descendents. When the amount of space used is below this value, the dataset is
+treated as if it were taking up the amount of space specified by
+.Sy refreservation .
+The
+.Sy refreservation
+reservation is accounted for in the parent datasets' space used, and counts
+against the parent datasets' quotas and reservations.
+.Pp
+If
+.Sy refreservation
+is set, a snapshot is only allowed if there is enough free pool space outside
+of this reservation to accommodate the current number of "referenced" bytes in
+the dataset.
+.Pp
+If
+.Sy refreservation
+is set to
+.Sy auto ,
+a volume is thick provisioned or not sparse.
+.Sy refreservation Ns = Cm auto
+is only supported on volumes.
+See
+.Sy volsize
+in the Native Properties
+section for more information about sparse volumes.
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy refreserv .
+.It Sy reservation Ns = Ns Ar size | Cm none
+The minimum amount of space guaranteed to a dataset and its descendents. When
+the amount of space used is below this value, the dataset is treated as if it
+were taking up the amount of space specified by its reservation. Reservations
+are accounted for in the parent datasets' space used, and count against the
+parent datasets' quotas and reservations.
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy reserv .
+.It Sy secondarycache Ns = Ns Cm all | none | metadata
+Controls what is cached in the secondary cache (L2ARC). If this property is set
+to
+.Cm all ,
+then both user data and metadata is cached. If this property is set to
+.Cm none ,
+then neither user data nor metadata is cached. If this property is set to
+.Cm metadata ,
+then only metadata is cached. The default value is
+.Cm all .
+.It Sy setuid Ns = Ns Cm on | off
+Controls whether the
+.No set- Ns Tn UID
+bit is respected for the file system. The default value is
+.Cm on .
+.It Sy sharesmb Ns = Ns Cm on | off | Ar opts
+The
+.Sy sharesmb
+property currently has no effect on
+.Fx .
+.It Sy sharenfs Ns = Ns Cm on | off | Ar opts
+Controls whether the file system is shared via
+.Tn NFS ,
+and what options are used. A file system with a
+.Sy sharenfs
+property of
+.Cm off
+is managed the traditional way via
+.Xr exports 5 .
+Otherwise, the file system is automatically shared and unshared with the
+.Qq Nm Cm share
+and
+.Qq Nm Cm unshare
+commands. If the property is set to
+.Cm on
+no
+.Tn NFS
+export options are used. Otherwise,
+.Tn NFS
+export options are equivalent to the contents of this property. The export
+options may be comma-separated. See
+.Xr exports 5
+for a list of valid options.
+.Pp
+When the
+.Sy sharenfs
+property is changed for a dataset, the
+.Xr mountd 8
+daemon is reloaded.
+.It Sy logbias Ns = Ns Cm latency | throughput
+Provide a hint to
+.Tn ZFS
+about handling of synchronous requests in this dataset.
+If
+.Sy logbias
+is set to
+.Cm latency
+(the default),
+.Tn ZFS
+will use pool log devices (if configured) to handle the requests at low
+latency. If
+.Sy logbias
+is set to
+.Cm throughput ,
+.Tn ZFS
+will not use configured pool log devices.
+.Tn ZFS
+will instead optimize synchronous operations for global pool throughput and
+efficient use of resources.
+.It Sy snapdir Ns = Ns Cm hidden | visible
+Controls whether the
+.Pa \&.zfs
+directory is hidden or visible in the root of the file system as discussed in
+the
+.Qq Sx Snapshots
+section. The default value is
+.Cm hidden .
+.It Sy sync Ns = Ns Cm standard | always | disabled
+Controls the behavior of synchronous requests (e.g.
+.Xr fsync 2 ,
+O_DSYNC). This property accepts the following values:
+.Bl -tag -offset 4n -width 8n
+.It Sy standard
+This is the POSIX specified behavior of ensuring all synchronous requests are
+written to stable storage and all devices are flushed to ensure data is not
+cached by device controllers (this is the default).
+.It Sy always
+All file system transactions are written and flushed before their system calls
+return. This has a large performance penalty.
+.It Sy disabled
+Disables synchronous requests. File system transactions are only committed to
+stable storage periodically. This option will give the highest performance.
+However, it is very dangerous as
+.Tn ZFS
+would be ignoring the synchronous transaction demands of applications such as
+databases or
+.Tn NFS .
+Administrators should only use this option when the risks are understood.
+.El
+.It Sy volsize Ns = Ns Ar size
+For volumes, specifies the logical size of the volume. By default, creating a
+volume establishes a reservation of equal size. For storage pools with a
+version number of 9 or higher, a
+.Sy refreservation
+is set instead. Any changes to
+.Sy volsize
+are reflected in an equivalent change to the reservation (or
+.Sy refreservation ) .
+The
+.Sy volsize
+can only be set to a multiple of
+.Cm volblocksize ,
+and cannot be zero.
+.Pp
+The reservation is kept equal to the volume's logical size to prevent
+unexpected behavior for consumers. Without the reservation, the volume could
+run out of space, resulting in undefined behavior or data corruption, depending
+on how the volume is used. These effects can also occur when the volume size is
+changed while it is in use (particularly when shrinking the size). Extreme care
+should be used when adjusting the volume size.
+.Pp
+Though not recommended, a "sparse volume" (also known as "thin provisioned")
+can be created by specifying the
+.Fl s
+option to the
+.Qq Nm Cm create Fl V
+command, or by changing the value of the
+.Sy refreservation
+property, or
+.Sy reservation
+property on pool
+.Po
+version 8 or earlier
+.Pc
+after the volume has been created.
+A "sparse volume" is a volume where the value of
+.Sy refreservation
+is less then the size of the volume plus the space required to store its
+metadata.
+Consequently, writes to a sparse volume can fail with
+.Sy ENOSPC
+when the pool is low on space. For a sparse volume, changes to
+.Sy volsize
+are not reflected in the
+.Sy refreservation .
+A volume that is not sparse is said to be "thick provisioned".
+A sparse volume can become thick provisioned by setting
+.Sy refreservation
+to
+.Sy auto .
+.It Sy volmode Ns = Ns Cm default | geom | dev | none
+This property specifies how volumes should be exposed to the OS.
+Setting it to
+.Sy geom
+exposes volumes as
+.Xr geom 4
+providers, providing maximal functionality.
+Setting it to
+.Sy dev
+exposes volumes only as cdev device in devfs.
+Such volumes can be accessed only as raw disk device files, i.e. they
+can not be partitioned, mounted, participate in RAIDs, etc, but they
+are faster, and in some use scenarios with untrusted consumer, such as
+NAS or VM storage, can be more safe.
+Volumes with property set to
+.Sy none
+are not exposed outside ZFS, but can be snapshoted, cloned, replicated, etc,
+that can be suitable for backup purposes.
+Value
+.Sy default
+means that volumes exposition is controlled by system-wide sysctl/tunable
+.Va vfs.zfs.vol.mode ,
+where
+.Sy geom ,
+.Sy dev
+and
+.Sy none
+are encoded as 1, 2 and 3 respectively.
+The default values is
+.Sy geom .
+This property can be changed any time, but so far it is processed only
+during volume creation and pool import.
+.It Sy vscan Ns = Ns Cm off | on
+The
+.Sy vscan
+property is currently not supported on
+.Fx .
+.It Sy xattr Ns = Ns Cm off | on
+The
+.Sy xattr
+property is currently not supported on
+.Fx .
+.It Sy jailed Ns = Ns Cm off | on
+Controls whether the dataset is managed from a jail. See the
+.Qq Sx Jails
+section for more information. The default value is
+.Cm off .
+.El
+.Pp
+The following three properties cannot be changed after the file system is
+created, and therefore, should be set when the file system is created. If the
+properties are not set with the
+.Qq Nm Cm create
+or
+.Nm zpool Cm create
+commands, these properties are inherited from the parent dataset. If the parent
+dataset lacks these properties due to having been created prior to these
+features being supported, the new file system will have the default values for
+these properties.
+.Bl -tag -width 4n
+.It Sy casesensitivity Ns = Ns Cm sensitive | insensitive | mixed
+Indicates whether the file name matching algorithm used by the file system
+should be case-sensitive, case-insensitive, or allow a combination of both
+styles of matching. The default value for the
+.Sy casesensitivity
+property is
+.Cm sensitive .
+Traditionally, UNIX and POSIX file systems have case-sensitive file names.
+.Pp
+The
+.Cm mixed
+value for the
+.Sy casesensitivity
+property indicates that the
+file system can support requests for both case-sensitive and case-insensitive
+matching behavior.
+.It Sy normalization Ns = Ns Cm none | formC | formD | formKC | formKD
+Indicates whether the file system should perform a
+.Sy unicode
+normalization of file names whenever two file names are compared, and which
+normalization algorithm should be used. File names are always stored
+unmodified, names are normalized as part of any comparison process. If this
+property is set to a legal value other than
+.Cm none ,
+and the
+.Sy utf8only
+property was left unspecified, the
+.Sy utf8only
+property is automatically set to
+.Cm on .
+The default value of the
+.Sy normalization
+property is
+.Cm none .
+This property cannot be changed after the file system is created.
+.It Sy utf8only Ns = Ns Cm on | off
+Indicates whether the file system should reject file names that include
+characters that are not present in the
+.Sy UTF-8
+character code set. If this property is explicitly set to
+.Cm off ,
+the normalization property must either not be explicitly set or be set to
+.Cm none .
+The default value for the
+.Sy utf8only
+property is
+.Cm off .
+This property cannot be changed after the file system is created.
+.El
+.Pp
+The
+.Sy casesensitivity , normalization , No and Sy utf8only
+properties are also new permissions that can be assigned to non-privileged
+users by using the
+.Tn ZFS
+delegated administration feature.
+.Ss Temporary Mount Point Properties
+When a file system is mounted, either through
+.Xr mount 8
+for legacy mounts or the
+.Qq Nm Cm mount
+command for normal file systems, its mount options are set according to its
+properties. The correlation between properties and mount options is as follows:
+.Bl -column -offset 4n "PROPERTY" "MOUNT OPTION"
+.It "PROPERTY MOUNT OPTION"
+.It "atime atime/noatime"
+.It "exec exec/noexec"
+.It "readonly ro/rw"
+.It "setuid suid/nosuid"
+.El
+.Pp
+In addition, these options can be set on a per-mount basis using the
+.Fl o
+option, without affecting the property that is stored on disk. The values
+specified on the command line override the values stored in the dataset. These
+properties are reported as "temporary" by the
+.Qq Nm Cm get
+command. If the properties are changed while the dataset is mounted, the new
+setting overrides any temporary settings.
+.Ss User Properties
+In addition to the standard native properties,
+.Tn ZFS
+supports arbitrary user properties. User properties have no effect on
+.Tn ZFS
+behavior, but applications or administrators can use them to annotate datasets
+(file systems, volumes, and snapshots).
+.Pp
+User property names must contain a colon
+.Pq Sy \&:
+character to distinguish them from native properties. They may contain
+lowercase letters, numbers, and the following punctuation characters: colon
+.Pq Sy \&: ,
+dash
+.Pq Sy \&- ,
+period
+.Pq Sy \&.
+and underscore
+.Pq Sy \&_ .
+The expected convention is that the property name is divided into two portions
+such as
+.Em module Ns Sy \&: Ns Em property ,
+but this namespace is not enforced by
+.Tn ZFS .
+User property names can be at most 256 characters, and cannot begin with a dash
+.Pq Sy \&- .
+.Pp
+When making programmatic use of user properties, it is strongly suggested to
+use a reversed
+.Tn DNS
+domain name for the
+.Ar module
+component of property names to reduce the chance that two
+independently-developed packages use the same property name for different
+purposes. Property names beginning with
+.Em com.sun
+are reserved for use by Sun Microsystems.
+.Pp
+The values of user properties are arbitrary strings, are always inherited, and
+are never validated. All of the commands that operate on properties
+.Po
+.Qq Nm Cm list ,
+.Qq Nm Cm get ,
+.Qq Nm Cm set
+and so forth
+.Pc
+can be used to manipulate both native properties and user properties. Use the
+.Qq Nm Cm inherit
+command to clear a user property. If the property is not defined in any parent
+dataset, it is removed entirely. Property values are limited to 1024
+characters.
+.Sh SUBCOMMANDS
+All subcommands that modify state are logged persistently to the pool in their
+original form.
+.Bl -tag -width 2n
+.It Xo
+.Nm
+.Op Fl \&?
+.Xc
+.Pp
+Displays a help message.
+.It Xo
+.Nm
+.Cm create
+.Op Fl pu
+.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
+.Ar filesystem
+.Xc
+.Pp
+Creates a new
+.Tn ZFS
+file system. The file system is automatically mounted according to the
+.Sy mountpoint
+property inherited from the parent.
+.Bl -tag -width indent
+.It Fl p
+Creates all the non-existing parent datasets. Datasets created in this manner
+are automatically mounted according to the
+.Sy mountpoint
+property inherited from their parent. Any property specified on the command
+line using the
+.Fl o
+option is ignored. If the target filesystem already exists, the operation
+completes successfully.
+.It Fl u
+Newly created file system is not mounted.
+.It Fl o Ar property Ns = Ns Ar value
+Sets the specified property as if the command
+.Qq Nm Cm set Ar property Ns = Ns Ar value
+was invoked at the same time the dataset was created. Any editable
+.Tn ZFS
+property can also be set at creation time. Multiple
+.Fl o
+options can be specified. An error results if the same property is specified in
+multiple
+.Fl o
+options.
+.El
+.It Xo
+.Nm
+.Cm create
+.Op Fl ps
+.Op Fl b Ar blocksize
+.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
+.Fl V
+.Ar size volume
+.Xc
+.Pp
+Creates a volume of the given size. The volume is exported as a block device in
+.Pa /dev/zvol/path ,
+where
+.Ar path
+is the name of the volume in the
+.Tn ZFS
+namespace. The size represents the logical size as exported by the device. By
+default, a reservation of equal size is created.
+.Pp
+.Ar size
+is automatically rounded up to the nearest 128 Kbytes to ensure that
+the volume has an integral number of blocks regardless of
+.Ar blocksize .
+.Bl -tag -width indent
+.It Fl p
+Creates all the non-existing parent datasets. Datasets created in this manner
+are automatically mounted according to the
+.Sy mountpoint
+property inherited from their parent. Any property specified on the command
+line using the
+.Fl o
+option is ignored. If the target filesystem already exists, the operation
+completes successfully.
+.It Fl s
+Creates a sparse volume with no reservation. See
+.Sy volsize
+in the
+.Qq Sx Native Properties
+section for more information about sparse volumes.
+.It Fl b Ar blocksize
+Equivalent to
+.Fl o Cm volblocksize Ns = Ns Ar blocksize .
+If this option is specified in conjunction with
+.Fl o Cm volblocksize ,
+the resulting behavior is undefined.
+.It Fl o Ar property Ns = Ns Ar value
+Sets the specified property as if the
+.Qq Nm Cm set Ar property Ns = Ns Ar value
+command was invoked at the same time the dataset was created. Any editable
+.Tn ZFS
+property can also be set at creation time. Multiple
+.Fl o
+options can be specified. An error results if the same property is specified in
+multiple
+.Fl o
+options.
+.El
+.It Xo
+.Nm
+.Cm destroy
+.Op Fl fnpRrv
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.Pp
+Destroys the given dataset. By default, the command unshares any file systems
+that are currently shared, unmounts any file systems that are currently
+mounted, and refuses to destroy a dataset that has active dependents (children
+or clones).
+.Bl -tag -width indent
+.It Fl r
+Recursively destroy all children.
+.It Fl R
+Recursively destroy all dependents, including cloned file systems outside the
+target hierarchy.
+.It Fl f
+Force an unmount of any file systems using the
+.Qq Nm Cm unmount Fl f
+command. This option has no effect on non-file systems or unmounted file
+systems.
+.It Fl n
+Do a dry-run ("No-op") deletion. No data will be deleted. This is useful in
+conjunction with the
+.Fl v
+or
+.Fl p
+flags to determine what data would be deleted.
+.It Fl p
+Print machine-parsable verbose information about the deleted data.
+.It Fl v
+Print verbose information about the deleted data.
+.El
+.Pp
+Extreme care should be taken when applying either the
+.Fl r
+or the
+.Fl R
+options, as they can destroy large portions of a pool and cause unexpected
+behavior for mounted file systems in use.
+.It Xo
+.Nm
+.Cm destroy
+.Op Fl dnpRrv
+.Sm off
+.Ar snapshot
+.Op % Ns Ar snapname
+.Op , Ns ...
+.Sm on
+.Xc
+.Pp
+The given snapshots are destroyed immediately if and only if the
+.Qq Nm Cm destroy
+command without the
+.Fl d
+option would have destroyed it. Such immediate destruction would occur, for
+example, if the snapshot had no clones and the user-initiated reference count
+were zero.
+.Pp
+If a snapshot does not qualify for immediate destruction, it is marked for
+deferred deletion. In this state, it exists as a usable, visible snapshot until
+both of the preconditions listed above are met, at which point it is destroyed.
+.Pp
+An inclusive range of snapshots may be specified by separating the
+first and last snapshots with a percent sign
+.Pq Sy % .
+The first and/or last snapshots may be left blank, in which case the
+filesystem's oldest or newest snapshot will be implied.
+.Pp
+Multiple snapshots
+(or ranges of snapshots) of the same filesystem or volume may be specified
+in a comma-separated list of snapshots.
+Only the snapshot's short name (the
+part after the
+.Sy @ )
+should be specified when using a range or comma-separated list to identify
+multiple snapshots.
+.Bl -tag -width indent
+.It Fl r
+Destroy (or mark for deferred deletion) all snapshots with this name in
+descendent file systems.
+.It Fl R
+Recursively destroy all clones of these snapshots, including the clones,
+snapshots, and children.
+If this flag is specified, the
+.Fl d
+flag will have no effect.
+.It Fl n
+Do a dry-run ("No-op") deletion. No data will be deleted. This is useful in
+conjunction with the
+.Fl v
+or
+.Fl p
+flags to determine what data would be deleted.
+.It Fl p
+Print machine-parsable verbose information about the deleted data.
+.It Fl v
+Print verbose information about the deleted data.
+.It Fl d
+Defer snapshot deletion.
+.El
+.Pp
+Extreme care should be taken when applying either the
+.Fl r
+or the
+.Fl R
+options, as they can destroy large portions of a pool and cause unexpected
+behavior for mounted file systems in use.
+.It Xo
+.Nm
+.Cm destroy
+.Ar filesystem Ns | Ns Ar volume Ns # Ns Ar bookmark
+.Xc
+.Pp
+The given bookmark is destroyed.
+.It Xo
+.Nm
+.Cm snapshot Ns | Ns Cm snap
+.Op Fl r
+.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
+.Ar filesystem@snapname Ns | Ns volume@snapname
+.Ar filesystem@snapname Ns | Ns volume@snapname Ns ...
+.Xc
+.Pp
+Creates snapshots with the given names. All previous modifications by
+successful system calls to the file system are part of the snapshots.
+Snapshots are taken atomically, so that all snapshots correspond to the same
+moment in time. See the
+.Qq Sx Snapshots
+section for details.
+.Bl -tag -width indent
+.It Fl r
+Recursively create snapshots of all descendent datasets
+.It Fl o Ar property Ns = Ns Ar value
+Sets the specified property; see
+.Qq Nm Cm create
+for details.
+.El
+.It Xo
+.Nm
+.Cm rollback
+.Op Fl rRf
+.Ar snapshot
+.Xc
+.Pp
+Roll back the given dataset to a previous snapshot. When a dataset is rolled
+back, all data that has changed since the snapshot is discarded, and the
+dataset reverts to the state at the time of the snapshot. By default, the
+command refuses to roll back to a snapshot other than the most recent one. In
+order to do so, all intermediate snapshots and bookmarks must be destroyed
+by specifying the
+.Fl r
+option.
+.Pp
+The
+.Fl rR
+options do not recursively destroy the child snapshots of a
+recursive snapshot.
+Only direct snapshots of the specified filesystem
+are destroyed by either of these options.
+To completely roll back a
+recursive snapshot, you must rollback the individual child snapshots.
+.Bl -tag -width indent
+.It Fl r
+Destroy any snapshots and bookmarks more recent than the one specified.
+.It Fl R
+Destroy any more recent snapshots and bookmarks, as well as any clones of those
+snapshots.
+.It Fl f
+Used with the
+.Fl R
+option to force an unmount of any clone file systems that are to be destroyed.
+.El
+.It Xo
+.Nm
+.Cm clone
+.Op Fl p
+.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
+.Ar snapshot filesystem Ns | Ns Ar volume
+.Xc
+.Pp
+Creates a clone of the given snapshot. See the
+.Qq Sx Clones
+section for details. The target dataset can be located anywhere in the
+.Tn ZFS
+hierarchy, and is created as the same type as the original.
+.Bl -tag -width indent
+.It Fl p
+Creates all the non-existing parent datasets. Datasets created in this manner
+are automatically mounted according to the
+.Sy mountpoint
+property inherited from their parent. If the target filesystem or volume
+already exists, the operation completes successfully.
+.It Fl o Ar property Ns = Ns Ar value
+Sets the specified property; see
+.Qq Nm Cm create
+for details.
+.El
+.It Xo
+.Nm
+.Cm promote
+.Ar clone-filesystem
+.Xc
+.Pp
+Promotes a clone file system to no longer be dependent on its "origin"
+snapshot. This makes it possible to destroy the file system that the clone was
+created from. The clone parent-child dependency relationship is reversed, so
+that the origin file system becomes a clone of the specified file system.
+.Pp
+The snapshot that was cloned, and any snapshots previous to this snapshot, are
+now owned by the promoted clone. The space they use moves from the origin file
+system to the promoted clone, so enough space must be available to accommodate
+these snapshots. No new space is consumed by this operation, but the space
+accounting is adjusted. The promoted clone must not have any conflicting
+snapshot names of its own. The
+.Cm rename
+subcommand can be used to rename any conflicting snapshots.
+.It Xo
+.Nm
+.Cm rename
+.Op Fl f
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Xc
+.It Xo
+.Nm
+.Cm rename
+.Op Fl f
+.Fl p
+.Ar filesystem Ns | Ns Ar volume
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.It Xo
+.Nm
+.Cm rename
+.Fl u
+.Op Fl p
+.Ar filesystem filesystem
+.Xc
+.Pp
+Renames the given dataset. The new target can be located anywhere in the
+.Tn ZFS
+hierarchy, with the exception of snapshots. Snapshots can only be renamed
+within the parent file system or volume. When renaming a snapshot, the parent
+file system of the snapshot does not need to be specified as part of the second
+argument. Renamed file systems can inherit new mount points, in which case they
+are unmounted and remounted at the new mount point.
+.Bl -tag -width indent
+.It Fl p
+Creates all the nonexistent parent datasets. Datasets created in this manner
+are automatically mounted according to the
+.Sy mountpoint
+property inherited from their parent.
+.It Fl u
+Do not remount file systems during rename. If a file system's
+.Sy mountpoint
+property is set to
+.Cm legacy
+or
+.Cm none ,
+file system is not unmounted even if this option is not given.
+.It Fl f
+Force unmount any filesystems that need to be unmounted in the process.
+This flag has no effect if used together with the
+.Fl u
+flag.
+.El
+.It Xo
+.Nm
+.Cm rename
+.Fl r
+.Ar snapshot snapshot
+.Xc
+.Pp
+Recursively rename the snapshots of all descendent datasets. Snapshots are the
+only dataset that can be renamed recursively.
+.It Xo
+.Nm
+.Cm rename
+.Ar bookmark bookmark
+.Xc
+.Pp
+Renames the given bookmark.
+Bookmarks can only be renamed within the parent file system or volume.
+When renaming a bookmark, the parent file system or volume of the bookmark
+does not need to be specified as part of the second argument.
+.It Xo
+.Nm
+.Cm list
+.Op Fl r Ns | Ns Fl d Ar depth
+.Op Fl Hp
+.Op Fl o Ar property Ns Oo , Ns Ar property Oc Ns ...
+.Op Fl t Ar type Ns Oo , Ns Ar type Oc Ns ...
+.Oo Fl s Ar property Oc Ns ...
+.Oo Fl S Ar property Oc Ns ...
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns ...
+.Xc
+.Pp
+Lists the property information for the given datasets in tabular form. If
+specified, you can list property information by the absolute pathname or the
+relative pathname. By default, all file systems and volumes are displayed.
+Snapshots are displayed if the
+.Sy listsnaps
+property is
+.Cm on
+(the default is
+.Cm off ) .
+The following fields are displayed,
+.Sy name , used , available , referenced , mountpoint .
+.Bl -tag -width indent
+.It Fl r
+Recursively display any children of the dataset on the command line.
+.It Fl d Ar depth
+Recursively display any children of the dataset, limiting the recursion to
+.Ar depth .
+A depth of
+.Sy 1
+will display only the dataset and its direct children.
+.It Fl H
+Used for scripting mode. Do not print headers and separate fields by a single
+tab instead of arbitrary white space.
+.It Fl p
+Display numbers in parsable (exact) values.
+.It Fl o Ar property Ns Oo , Ns Ar property Oc Ns ...
+A comma-separated list of properties to display. The property must be:
+.Bl -bullet -offset 2n
+.It
+One of the properties described in the
+.Qq Sx Native Properties
+section
+.It
+A user property
+.It
+The value
+.Cm name
+to display the dataset name
+.It
+The value
+.Cm space
+to display space usage properties on file systems and volumes. This is a
+shortcut for specifying
+.Fl o
+.Sy name,avail,used,usedsnap,usedds,usedrefreserv,usedchild
+.Fl t
+.Sy filesystem,volume
+syntax.
+.El
+.It Fl t Ar type Ns Oo , Ns Ar type Oc Ns ...
+A comma-separated list of types to display, where
+.Ar type
+is one of
+.Sy filesystem , snapshot , snap , volume , bookmark , No or Sy all .
+For example, specifying
+.Fl t Cm snapshot
+displays only snapshots.
+.It Fl s Ar property
+A property for sorting the output by column in ascending order based on the
+value of the property. The property must be one of the properties described in
+the
+.Qq Sx Properties
+section, or the special value
+.Cm name
+to sort by the dataset name. Multiple properties can be specified at one time
+using multiple
+.Fl s
+property options. Multiple
+.Fl s
+options are evaluated from left to right in decreasing order of importance.
+.Pp
+The following is a list of sorting criteria:
+.Bl -bullet -offset 2n
+.It
+Numeric types sort in numeric order.
+.It
+String types sort in alphabetical order.
+.It
+Types inappropriate for a row sort that row to the literal bottom, regardless
+of the specified ordering.
+.It
+If no sorting options are specified the existing behavior of
+.Qq Nm Cm list
+is preserved.
+.El
+.It Fl S Ar property
+Same as the
+.Fl s
+option, but sorts by property in descending order.
+.El
+.It Xo
+.Nm
+.Cm set
+.Ar property Ns = Ns Ar value Oo Ar property Ns = Ns Ar value Oc Ns ...
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Xc
+.Pp
+Sets the property or list of properties to the given value(s) for each dataset.
+Only some properties can be edited. See the "Properties" section for more
+information on what properties can be set and acceptable values. Numeric values
+can be specified as exact values, or in a human-readable form with a suffix of
+.Sy B , K , M , G , T , P , E , Z
+(for bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes, exabytes, or
+zettabytes, respectively). User properties can be set on snapshots. For more
+information, see the
+.Qq Sx User Properties
+section.
+.It Xo
+.Nm
+.Cm get
+.Op Fl r Ns | Ns Fl d Ar depth
+.Op Fl Hp
+.Op Fl o Ar all | field Ns Oo , Ns Ar field Oc Ns ...
+.Op Fl t Ar type Ns Oo , Ns Ar type Oc Ns ...
+.Op Fl s Ar source Ns Oo , Ns Ar source Oc Ns ...
+.Ar all | property Ns Oo , Ns Ar property Oc Ns ...
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns | Ns Ar bookmark Ns ...
+.Xc
+.Pp
+Displays properties for the given datasets. If no datasets are specified, then
+the command displays properties for all datasets on the system. For each
+property, the following columns are displayed:
+.Pp
+.Bl -hang -width "property" -offset indent -compact
+.It name
+Dataset name
+.It property
+Property name
+.It value
+Property value
+.It source
+Property source. Can either be local, default, temporary, inherited, received,
+or none
+(\&-).
+.El
+.Pp
+All columns except the
+.Sy RECEIVED
+column are displayed by default. The columns to display can be specified
+by using the
+.Fl o
+option. This command takes a comma-separated list of properties as described in
+the
+.Qq Sx Native Properties
+and
+.Qq Sx User Properties
+sections.
+.Pp
+The special value
+.Cm all
+can be used to display all properties that apply to the given dataset's type
+(filesystem, volume, snapshot, or bookmark).
+.Bl -tag -width indent
+.It Fl r
+Recursively display properties for any children.
+.It Fl d Ar depth
+Recursively display any children of the dataset, limiting the recursion to
+.Ar depth .
+A depth of
+.Sy 1
+will display only the dataset and its direct children.
+.It Fl H
+Display output in a form more easily parsed by scripts. Any headers are
+omitted, and fields are explicitly separated by a single tab instead of an
+arbitrary amount of space.
+.It Fl p
+Display numbers in parsable (exact) values.
+.It Fl o Cm all | Ar field Ns Oo , Ns Ar field Oc Ns ...
+A comma-separated list of columns to display. Supported values are
+.Sy name,property,value,received,source .
+Default values are
+.Sy name,property,value,source .
+The keyword
+.Cm all
+specifies all columns.
+.It Fl t Ar type Ns Oo , Ns Ar type Oc Ns ...
+A comma-separated list of types to display, where
+.Ar type
+is one of
+.Sy filesystem , snapshot , volume , No or Sy all .
+For example, specifying
+.Fl t Cm snapshot
+displays only snapshots.
+.It Fl s Ar source Ns Oo , Ns Ar source Oc Ns ...
+A comma-separated list of sources to display. Those properties coming from a
+source other than those in this list are ignored. Each source must be one of
+the following:
+.Sy local,default,inherited,temporary,received,none .
+The default value is all sources.
+.El
+.It Xo
+.Nm
+.Cm inherit
+.Op Fl rS
+.Ar property
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns ...
+.Xc
+.Pp
+Clears the specified property, causing it to be inherited from an ancestor,
+restored to default if no ancestor has the property set, or with the
+.Fl S
+option reverted to the received value if one exists.
+See the
+.Qq Sx Properties
+section for a listing of default values, and details on which properties can be
+inherited.
+.Bl -tag -width indent
+.It Fl r
+Recursively inherit the given property for all children.
+.It Fl S
+Revert the property to the received value if one exists; otherwise operate as
+if the
+.Fl S
+option was not specified.
+.El
+.It Xo
+.Nm
+.Cm remap
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.Pp
+Remap the indirect blocks in the given filesystem or volume so that they no
+longer reference blocks on previously removed vdevs and we can eventually
+shrink the size of the indirect mapping objects for the previously removed
+vdevs. Note that remapping all blocks might not be possible and that
+references from snapshots will still exist and cannot be remapped.
+.It Xo
+.Nm
+.Cm upgrade
+.Op Fl v
+.Xc
+.Pp
+Displays a list of file systems that are not the most recent version.
+.Bl -tag -width indent
+.It Fl v
+Displays
+.Tn ZFS
+filesystem versions supported by the current software. The current
+.Tn ZFS
+filesystem version and all previous supported versions are displayed, along
+with an explanation of the features provided with each version.
+.El
+.It Xo
+.Nm
+.Cm upgrade
+.Op Fl r
+.Op Fl V Ar version
+.Fl a | Ar filesystem
+.Xc
+.Pp
+Upgrades file systems to a new on-disk version. Once this is done, the file
+systems will no longer be accessible on systems running older versions of the
+software.
+.Qq Nm Cm send
+streams generated from new snapshots of these file systems cannot be accessed
+on systems running older versions of the software.
+.Pp
+In general, the file system version is independent of the pool version. See
+.Xr zpool 8
+for information on the
+.Nm zpool Cm upgrade
+command.
+.Pp
+In some cases, the file system version and the pool version are interrelated
+and the pool version must be upgraded before the file system version can be
+upgraded.
+.Bl -tag -width indent
+.It Fl r
+Upgrade the specified file system and all descendent file systems.
+.It Fl V Ar version
+Upgrade to the specified
+.Ar version .
+If the
+.Fl V
+flag is not specified, this command upgrades to the most recent version. This
+option can only be used to increase the version number, and only up to the most
+recent version supported by this software.
+.It Fl a
+Upgrade all file systems on all imported pools.
+.It Ar filesystem
+Upgrade the specified file system.
+.El
+.It Xo
+.Nm
+.Cm userspace
+.Op Fl Hinp
+.Op Fl o Ar field Ns Oo , Ns Ar field Oc Ns ...
+.Oo Fl s Ar field Oc Ns ...
+.Oo Fl S Ar field Oc Ns ...
+.Op Fl t Ar type Ns Oo , Ns Ar type Oc Ns ...
+.Ar filesystem Ns | Ns Ar snapshot
+.Xc
+.Pp
+Displays space consumed by, and quotas on, each user in the specified
+filesystem or snapshot. This corresponds to the
+.Sy userused@ Ns Ar user
+and
+.Sy userquota@ Ns Ar user
+properties.
+.Bl -tag -width indent
+.It Fl n
+Print numeric ID instead of user/group name.
+.It Fl H
+Do not print headers, use tab-delimited output.
+.It Fl p
+Use exact (parsable) numeric output.
+.It Fl o Ar field Ns Oo , Ns Ar field Oc Ns ...
+Display only the specified fields from the following set:
+.Sy type,name,used,quota .
+The default is to display all fields.
+.It Fl s Ar field
+Sort output by this field. The
+.Fl s
+and
+.Fl S
+flags may be specified multiple times to sort first by one field, then by
+another. The default is
+.Fl s Cm type Fl s Cm name .
+.It Fl S Ar field
+Sort by this field in reverse order. See
+.Fl s .
+.It Fl t Ar type Ns Oo , Ns Ar type Oc Ns ...
+Print only the specified types from the following set:
+.Sy all,posixuser,smbuser,posixgroup,smbgroup .
+.Pp
+The default is
+.Fl t Cm posixuser,smbuser .
+.Pp
+The default can be changed to include group types.
+.It Fl i
+Translate SID to POSIX ID. This flag currently has no effect on
+.Fx .
+.El
+.It Xo
+.Nm
+.Cm groupspace
+.Op Fl Hinp
+.Op Fl o Ar field Ns Oo , Ns Ar field Oc Ns ...
+.Oo Fl s Ar field Oc Ns ...
+.Oo Fl S Ar field Oc Ns ...
+.Op Fl t Ar type Ns Oo , Ns Ar type Oc Ns ...
+.Ar filesystem Ns | Ns Ar snapshot
+.Xc
+.Pp
+Displays space consumed by, and quotas on, each group in the specified
+filesystem or snapshot. This subcommand is identical to
+.Qq Nm Cm userspace ,
+except that the default types to display are
+.Fl t Sy posixgroup,smbgroup .
+.It Xo
+.Nm
+.Cm mount
+.Xc
+.Pp
+Displays all
+.Tn ZFS
+file systems currently mounted.
+.Bl -tag -width indent
+.It Fl f
+.El
+.It Xo
+.Nm
+.Cm mount
+.Op Fl vO
+.Op Fl o Ar property Ns Oo , Ns Ar property Oc Ns ...
+.Fl a | Ar filesystem
+.Xc
+.Pp
+Mounts
+.Tn ZFS
+file systems.
+.Bl -tag -width indent
+.It Fl v
+Report mount progress.
+.It Fl O
+Perform an overlay mount. Overlay mounts are not supported on
+.Fx .
+.It Fl o Ar property Ns Oo , Ns Ar property Oc Ns ...
+An optional, comma-separated list of mount options to use temporarily for the
+duration of the mount. See the
+.Qq Sx Temporary Mount Point Properties
+section for details.
+.It Fl a
+Mount all available
+.Tn ZFS
+file systems.
+This command may be executed on
+.Fx
+system startup by
+.Pa /etc/rc.d/zfs .
+For more information, see variable
+.Va zfs_enable
+in
+.Xr rc.conf 5 .
+.It Ar filesystem
+Mount the specified filesystem.
+.El
+.It Xo
+.Nm
+.Cm unmount Ns | Ns Cm umount
+.Op Fl f
+.Fl a | Ar filesystem Ns | Ns Ar mountpoint
+.Xc
+.Pp
+Unmounts currently mounted
+.Tn ZFS
+file systems.
+.Bl -tag -width indent
+.It Fl f
+Forcefully unmount the file system, even if it is currently in use.
+.It Fl a
+Unmount all available
+.Tn ZFS
+file systems.
+.It Ar filesystem | mountpoint
+Unmount the specified filesystem. The command can also be given a path to a
+.Tn ZFS
+file system mount point on the system.
+.El
+.It Xo
+.Nm
+.Cm share
+.Fl a | Ar filesystem
+.Xc
+.Pp
+Shares
+.Tn ZFS
+file systems that have the
+.Sy sharenfs
+property set.
+.Bl -tag -width indent
+.It Fl a
+Share all
+.Tn ZFS
+file systems that have the
+.Sy sharenfs
+property set.
+This command may be executed on
+.Fx
+system startup by
+.Pa /etc/rc.d/zfs .
+For more information, see variable
+.Va zfs_enable
+in
+.Xr rc.conf 5 .
+.It Ar filesystem
+Share the specified filesystem according to the
+.Tn sharenfs
+property. File systems are shared when the
+.Tn sharenfs
+property is set.
+.El
+.It Xo
+.Nm
+.Cm unshare
+.Fl a | Ar filesystem Ns | Ns Ar mountpoint
+.Xc
+.Pp
+Unshares
+.Tn ZFS
+file systems that have the
+.Tn sharenfs
+property set.
+.Bl -tag -width indent
+.It Fl a
+Unshares
+.Tn ZFS
+file systems that have the
+.Sy sharenfs
+property set.
+This command may be executed on
+.Fx
+system shutdown by
+.Pa /etc/rc.d/zfs .
+For more information, see variable
+.Va zfs_enable
+in
+.Xr rc.conf 5 .
+.It Ar filesystem | mountpoint
+Unshare the specified filesystem. The command can also be given a path to a
+.Tn ZFS
+file system shared on the system.
+.El
+.It Xo
+.Nm
+.Cm bookmark
+.Ar snapshot
+.Ar bookmark
+.Xc
+.Pp
+Creates a bookmark of the given snapshot.
+Bookmarks mark the point in time
+when the snapshot was created, and can be used as the incremental source for
+a
+.Qq Nm Cm send
+command.
+.Pp
+This feature must be enabled to be used.
+See
+.Xr zpool-features 7
+for details on ZFS feature flags and the
+.Sy bookmark
+feature.
+.It Xo
+.Nm
+.Cm send
+.Op Fl DLPRVcenpv
+.Op Fl i Ar snapshot | Fl I Ar snapshot
+.Ar snapshot
+.Xc
+.Pp
+Creates a stream representation of the last
+.Ar snapshot
+argument (not part of
+.Fl i
+or
+.Fl I )
+which is written to standard output. The output can be redirected to
+a file or to a different system (for example, using
+.Xr ssh 1 ) .
+By default, a full stream is generated.
+.Bl -tag -width indent
+.It Fl i Ar snapshot
+Generate an incremental stream from the first
+.Ar snapshot Pq the incremental source
+to the second
+.Ar snapshot Pq the incremental target .
+The incremental source can be specified as the last component of the
+snapshot name
+.Pq the Em @ No character and following
+and
+it is assumed to be from the same file system as the incremental target.
+.Pp
+If the destination is a clone, the source may be the origin snapshot, which
+must be fully specified (for example,
+.Cm pool/fs@origin ,
+not just
+.Cm @origin ) .
+.It Fl I Ar snapshot
+Generate a stream package that sends all intermediary snapshots from the first
+.Ar snapshot
+to the second
+.Ar snapshot .
+For example,
+.Ic -I @a fs@d
+is similar to
+.Ic -i @a fs@b; -i @b fs@c; -i @c fs@d .
+The incremental
+source may be specified as with the
+.Fl i
+option.
+.It Fl R, -replicate
+Generate a replication stream package, which will replicate the specified
+filesystem, and all descendent file systems, up to the named snapshot. When
+received, all properties, snapshots, descendent file systems, and clones are
+preserved.
+.Pp
+If the
+.Fl i
+or
+.Fl I
+flags are used in conjunction with the
+.Fl R
+flag, an incremental replication stream is generated. The current values of
+properties, and current snapshot and file system names are set when the stream
+is received. If the
+.Fl F
+flag is specified when this stream is received, snapshots and file systems that
+do not exist on the sending side are destroyed.
+.It Fl D, -dedup
+Generate a deduplicated stream. Blocks which would have been sent multiple
+times in the send stream will only be sent once. The receiving system must
+also support this feature to receive a deduplicated stream. This flag can
+be used regardless of the dataset's
+.Sy dedup
+property, but performance will be much better if the filesystem uses a
+dedup-capable checksum (eg.
+.Sy sha256 ) .
+.It Fl L, -large-block
+Generate a stream which may contain blocks larger than 128KB.
+This flag
+has no effect if the
+.Sy large_blocks
+pool feature is disabled, or if the
+.Sy recordsize
+property of this filesystem has never been set above 128KB.
+The receiving system must have the
+.Sy large_blocks
+pool feature enabled as well.
+See
+.Xr zpool-features 7
+for details on ZFS feature flags and the
+.Sy large_blocks
+feature.
+.It Fl e, -embed
+Generate a more compact stream by using WRITE_EMBEDDED records for blocks
+which are stored more compactly on disk by the
+.Sy embedded_data
+pool
+feature.
+This flag has no effect if the
+.Sy embedded_data
+feature is
+disabled.
+The receiving system must have the
+.Sy embedded_data
+feature
+enabled.
+If the
+.Sy lz4_compress
+feature is active on the sending system,
+then the receiving system must have that feature enabled as well.
+See
+.Xr zpool-features 7
+for details on ZFS feature flags and the
+.Sy embedded_data
+feature.
+.It Fl c, -compressed
+Generate a more compact stream by using compressed WRITE records for blocks
+which are compressed on disk and in memory (see the
+.Sy compression
+property for details).
+If the
+.Sy lz4_compress
+feature is active on the sending system, then the receiving system must have that
+feature enabled as well. If the
+.Sy large_blocks
+feature is enabled on the sending system but the
+.Fl L
+option is not supplied in conjunction with
+.Fl c
+then the data will be decompressed before sending so it can be split
+into smaller block sizes.
+.It Fl p, -props
+Include the dataset's properties in the stream. This flag is implicit when
+.Fl R
+is specified. The receiving system must also support this feature.
+.It Fl n, -dryrun
+Do a dry-run ("No-op") send. Do not generate any actual send data. This is
+useful in conjunction with the
+.Fl v
+or
+.Fl P
+flags to determine what data will be sent.
+In this case, the verbose output will be written to
+standard output (contrast with a non-dry-run, where the stream is written
+to standard output and the verbose output goes to standard error).
+.It Fl P, -parsable
+Print machine-parsable verbose information about the stream package generated.
+.It Fl v, -verbose
+Print verbose information about the stream package generated.
+This information includes a per-second report of how much data has been sent.
+.It Fl V
+Set the process title to a per-second report of how much data has been sent.
+.El
+.Pp
+The format of the stream is committed. You will be able to receive your streams
+on future versions of
+.Tn ZFS .
+.It Xo
+.Nm
+.Cm send
+.Op Fl LPcenv
+.Op Fl i Ar snapshot Ns | Ns Ar bookmark
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Xc
+.Pp
+Generate a send stream, which may be of a filesystem, and may be
+incremental from a bookmark.
+If the destination is a filesystem or volume,
+the pool must be read-only, or the filesystem must not be mounted.
+When the
+stream generated from a filesystem or volume is received, the default snapshot
+name will be
+.Pq --head-- .
+.Bl -tag -width indent
+.It Fl i Ar snapshot Ns | Ns Ar bookmark
+Generate an incremental send stream.
+The incremental source must be an earlier
+snapshot in the destination's history.
+It will commonly be an earlier
+snapshot in the destination's filesystem, in which case it can be
+specified as the last component of the name
+.Pq the Em # No or Em @ No character and following .
+.Pp
+If the incremental target is a clone, the incremental source can
+be the origin snapshot, or an earlier snapshot in the origin's filesystem,
+or the origin's origin, etc.
+.It Fl n, -dryrun
+Do a dry-run
+.Pq Qq No-op
+send.
+Do not generate any actual send data.
+This is useful in conjunction with the
+.Fl v
+or
+.Fl P
+flags to determine what data will be sent.
+In this case, the verbose output will be written to standard output
+.Po contrast with a non-dry-run, where the stream is written to standard output
+and the verbose output goes to standard error
+.Pc .
+.It Fl v, -verbose
+Print verbose information about the stream package generated.
+This information includes a per-second report of how much data has been sent.
+.It Fl L, -large-block
+Generate a stream which may contain blocks larger than 128KB.
+This flag
+has no effect if the
+.Sy large_blocks
+pool feature is disabled, or if the
+.Sy recordsize
+property of this filesystem has never been set above 128KB.
+The receiving system must have the
+.Sy large_blocks
+pool feature enabled as well.
+See
+.Xr zpool-features 7
+for details on ZFS feature flags and the
+.Sy large_blocks
+feature.
+.It Fl P, -parsable
+Print machine-parsable verbose information about the stream package generated.
+.It Fl c, -compressed
+Generate a more compact stream by using compressed WRITE records for blocks
+which are compressed on disk and in memory (see the
+.Sy compression
+property for details). If the
+.Sy lz4_compress
+feature is active on the sending system, then the receiving system must have
+that feature enabled as well. If the
+.Sy large_blocks
+feature is enabled on the sending system but the
+.Fl L
+option is not supplied in conjunction with
+.Fl c
+then the data will be decompressed before sending so it can be split
+into smaller block sizes.
+.It Fl e, -embed
+Generate a more compact stream by using WRITE_EMBEDDED records for blocks
+which are stored more compactly on disk by the
+.Sy embedded_data
+pool
+feature.
+This flag has no effect if the
+.Sy embedded_data
+feature is
+disabled.
+The receiving system must have the
+.Sy embedded_data
+feature
+enabled.
+If the
+.Sy lz4_compress
+feature is active on the sending system,
+then the receiving system must have that feature enabled as well.
+See
+.Xr zpool-features 7
+for details on ZFS feature flags and the
+.Sy embedded_data
+feature.
+.El
+.It Xo
+.Nm
+.Cm send
+.Op Fl Penv
+.Fl t
+.Ar receive_resume_token
+.Xc
+Creates a send stream which resumes an interrupted receive. The
+.Ar receive_resume_token
+is the value of this property on the filesystem
+or volume that was being received into. See the documentation for
+.Sy zfs receive -s
+for more details.
+.It Xo
+.Nm
+.Cm receive Ns | Ns Cm recv
+.Op Fl vnsFu
+.Op Fl o Sy origin Ns = Ns Ar snapshot
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Xc
+.It Xo
+.Nm
+.Cm receive Ns | Ns Cm recv
+.Op Fl vnsFu
+.Op Fl d | e
+.Op Fl o Sy origin Ns = Ns Ar snapshot
+.Ar filesystem
+.Xc
+.Pp
+Creates a snapshot whose contents are as specified in the stream provided on
+standard input. If a full stream is received, then a new file system is created
+as well. Streams are created using the
+.Qq Nm Cm send
+subcommand, which by default creates a full stream.
+.Qq Nm Cm recv
+can be used as an alias for
+.Qq Nm Cm receive .
+.Pp
+If an incremental stream is received, then the destination file system must
+already exist, and its most recent snapshot must match the incremental stream's
+source. For
+.Sy zvol Ns s,
+the destination device link is destroyed and recreated, which means the
+.Sy zvol
+cannot be accessed during the
+.Sy receive
+operation.
+.Pp
+When a snapshot replication package stream that is generated by using the
+.Qq Nm Cm send Fl R
+command is received, any snapshots that do not exist on the sending location
+are destroyed by using the
+.Qq Nm Cm destroy Fl d
+command.
+.Pp
+The name of the snapshot (and file system, if a full stream is received) that
+this subcommand creates depends on the argument type and the
+.Fl d
+or
+.Fl e
+option.
+.Pp
+If the argument is a snapshot name, the specified
+.Ar snapshot
+is created. If the argument is a file system or volume name, a snapshot with
+the same name as the sent snapshot is created within the specified
+.Ar filesystem
+or
+.Ar volume .
+If the
+.Fl d
+or
+.Fl e
+option is specified, the snapshot name is determined by appending the sent
+snapshot's name to the specified
+.Ar filesystem .
+If the
+.Fl d
+option is specified, all but the pool name of the sent snapshot path is
+appended (for example,
+.Sy b/c@1
+appended from sent snapshot
+.Sy a/b/c@1 ) ,
+and if the
+.Fl e
+option is specified, only the tail of the sent snapshot path is appended (for
+example,
+.Sy c@1
+appended from sent snapshot
+.Sy a/b/c@1 ) .
+In the case of
+.Fl d ,
+any file systems needed to replicate the path of the sent snapshot are created
+within the specified file system.
+.Bl -tag -width indent
+.It Fl d
+Use the full sent snapshot path without the first element (without pool name)
+to determine the name of the new snapshot as described in the paragraph above.
+.It Fl e
+Use only the last element of the sent snapshot path to determine the name of
+the new snapshot as described in the paragraph above.
+.It Fl u
+File system that is associated with the received stream is not mounted.
+.It Fl v
+Print verbose information about the stream and the time required to perform the
+receive operation.
+.It Fl n
+Do not actually receive the stream. This can be useful in conjunction with the
+.Fl v
+option to verify the name the receive operation would use.
+.It Fl o Sy origin Ns = Ns Ar snapshot
+Forces the stream to be received as a clone of the given snapshot.
+If the stream is a full send stream, this will create the filesystem
+described by the stream as a clone of the specified snapshot. Which
+snapshot was specified will not affect the success or failure of the
+receive, as long as the snapshot does exist. If the stream is an
+incremental send stream, all the normal verification will be performed.
+.It Fl F
+Force a rollback of the file system to the most recent snapshot before
+performing the receive operation. If receiving an incremental replication
+stream (for example, one generated by
+.Qq Nm Cm send Fl R Bro Fl i | Fl I Brc ) ,
+destroy snapshots and file systems that do not exist on the sending side.
+.It Fl s
+If the receive is interrupted, save the partially received state, rather
+than deleting it. Interruption may be due to premature termination of
+the stream
+.Po e.g. due to network failure or failure of the remote system
+if the stream is being read over a network connection
+.Pc ,
+a checksum error in the stream, termination of the
+.Nm zfs Cm receive
+process, or unclean shutdown of the system.
+.Pp
+The receive can be resumed with a stream generated by
+.Nm zfs Cm send Fl t Ar token ,
+where the
+.Ar token
+is the value of the
+.Sy receive_resume_token
+property of the filesystem or volume which is received into.
+.Pp
+To use this flag, the storage pool must have the
+.Sy extensible_dataset
+feature enabled. See
+.Xr zpool-features 7
+for details on ZFS feature flags.
+.El
+.It Xo
+.Nm
+.Cm receive Ns | Ns Cm recv
+.Fl A
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+Abort an interrupted
+.Nm zfs Cm receive Fl s ,
+deleting its saved partially received state.
+.It Xo
+.Nm
+.Cm allow
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.Pp
+Displays permissions that have been delegated on the specified filesystem or
+volume. See the other forms of
+.Qq Nm Cm allow
+for more information.
+.It Xo
+.Nm
+.Cm allow
+.Op Fl ldug
+.Ar user Ns | Ns Ar group Ns Oo Ns , Ns Ar user Ns | Ns Ar group Oc Ns ...
+.Ar perm Ns | Ns Ar @setname Ns
+.Oo Ns , Ns Ar perm Ns | Ns Ar @setname Oc Ns ...
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.It Xo
+.Nm
+.Cm allow
+.Op Fl ld
+.Fl e Ns | Ns Cm everyone
+.Ar perm Ns | Ns Ar @setname Ns Op Ns , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ...
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.Pp
+Delegates
+.Tn ZFS
+administration permission for the file systems to non-privileged users.
+.Bl -tag -width indent
+.It Xo
+.Op Fl ug
+.Ar user Ns | Ns Ar group Ns Oo , Ar user Ns | Ns Ar group Oc Ns ...
+.Xc
+Specifies to whom the permissions are delegated. Multiple entities can be
+specified as a comma-separated list. If neither of the
+.Fl ug
+options are specified, then the argument is interpreted preferentially as the
+keyword
+.Cm everyone ,
+then as a user name, and lastly as a group name. To specify
+a user or group named
+.Qq everyone ,
+use the
+.Fl u
+or
+.Fl g
+options. To specify a group with the same name as a user, use the
+.Fl g
+option.
+.It Op Fl e Ns | Ns Cm everyone
+Specifies that the permissions be delegated to
+.Qq everyone .
+.It Xo
+.Ar perm Ns | Ns Ar @setname Ns Oo , Ns Ar perm Ns | Ns Ar @setname Oc Ns ...
+.Xc
+The permissions to delegate. Multiple permissions
+may be specified as a comma-separated list. Permission names are the same as
+.Tn ZFS
+subcommand and property names. See the property list below. Property set names,
+which begin with an at sign
+.Pq Sy @ ,
+may be specified. See the
+.Fl s
+form below for details.
+.It Xo
+.Op Fl ld
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+Specifies where the permissions are delegated. If neither of the
+.Fl ld
+options are specified, or both are, then the permissions are allowed for the
+file system or volume, and all of its descendents. If only the
+.Fl l
+option is used, then is allowed "locally" only for the specified file system.
+If only the
+.Fl d
+option is used, then is allowed only for the descendent file systems.
+.El
+.Pp
+Permissions are generally the ability to use a
+.Tn ZFS
+subcommand or change a
+.Tn ZFS
+property. The following permissions are available:
+.Bl -column -offset 4n "secondarycache" "subcommand"
+.It NAME Ta TYPE Ta NOTES
+.It allow Ta subcommand Ta Must Xo
+also have the permission that is being allowed
+.Xc
+.It clone Ta subcommand Ta Must Xo
+also have the 'create' ability and 'mount' ability in the origin file system
+.Xc
+.It create Ta subcommand Ta Must also have the 'mount' ability
+.It destroy Ta subcommand Ta Must also have the 'mount' ability
+.It diff Ta subcommand Ta Allows lookup of paths within a dataset given an
+object number, and the ability to create snapshots necessary to 'zfs diff'
+.It hold Ta subcommand Ta Allows adding a user hold to a snapshot
+.It mount Ta subcommand Ta Allows mount/umount of Tn ZFS No datasets
+.It promote Ta subcommand Ta Must Xo
+also have the 'mount' and 'promote' ability in the origin file system
+.Xc
+.It receive Ta subcommand Ta Must also have the 'mount' and 'create' ability
+.It release Ta subcommand Ta Allows Xo
+releasing a user hold which might destroy the snapshot
+.Xc
+.It rename Ta subcommand Ta Must Xo
+also have the 'mount' and 'create' ability in the new parent
+.Xc
+.It rollback Ta subcommand Ta Must also have the 'mount' ability
+.It send Ta subcommand
+.It share Ta subcommand Ta Allows Xo
+sharing file systems over the
+.Tn NFS
+protocol
+.Xc
+.It snapshot Ta subcommand Ta Must also have the 'mount' ability
+.It groupquota Ta other Ta Allows accessing any groupquota@... property
+.It groupused Ta other Ta Allows reading any groupused@... property
+.It userprop Ta other Ta Allows changing any user property
+.It userquota Ta other Ta Allows accessing any userquota@... property
+.It userused Ta other Ta Allows reading any userused@... property
+.It aclinherit Ta property
+.It aclmode Ta property
+.It atime Ta property
+.It canmount Ta property
+.It casesensitivity Ta property
+.It checksum Ta property
+.It compression Ta property
+.It copies Ta property
+.It dedup Ta property
+.It devices Ta property
+.It exec Ta property
+.It filesystem_limit Ta property
+.It logbias Ta property
+.It jailed Ta property
+.It mlslabel Ta property
+.It mountpoint Ta property
+.It nbmand Ta property
+.It normalization Ta property
+.It primarycache Ta property
+.It quota Ta property
+.It readonly Ta property
+.It recordsize Ta property
+.It refquota Ta property
+.It refreservation Ta property
+.It reservation Ta property
+.It secondarycache Ta property
+.It setuid Ta property
+.It sharenfs Ta property
+.It sharesmb Ta property
+.It snapdir Ta property
+.It snapshot_limit Ta property
+.It sync Ta property
+.It utf8only Ta property
+.It version Ta property
+.It volblocksize Ta property
+.It volsize Ta property
+.It vscan Ta property
+.It xattr Ta property
+.El
+.It Xo
+.Nm
+.Cm allow
+.Fl c
+.Ar perm Ns | Ns Ar @setname Ns Op Ns , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ...
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.Pp
+Sets "create time" permissions. These permissions are granted (locally) to the
+creator of any newly-created descendent file system.
+.It Xo
+.Nm
+.Cm allow
+.Fl s
+.Ar @setname
+.Ar perm Ns | Ns Ar @setname Ns Op Ns , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ...
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.Pp
+Defines or adds permissions to a permission set. The set can be used by other
+.Qq Nm Cm allow
+commands for the specified file system and its descendents. Sets are evaluated
+dynamically, so changes to a set are immediately reflected. Permission sets
+follow the same naming restrictions as ZFS file systems, but the name must
+begin with an "at sign"
+.Pq Sy @ ,
+and can be no more than 64 characters long.
+.It Xo
+.Nm
+.Cm unallow
+.Op Fl rldug
+.Ar user Ns | Ns Ar group Ns Oo Ns , Ns Ar user Ns | Ns Ar group Oc Ns ...
+.Oo Ar perm Ns | Ns Ar @setname Ns Op , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ... Oc
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.It Xo
+.Nm
+.Cm unallow
+.Op Fl rld
+.Fl e Ns | Ns Cm everyone
+.Oo Ar perm Ns | Ns Ar @setname Ns Op , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ... Oc
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.It Xo
+.Nm
+.Cm unallow
+.Op Fl r
+.Fl c
+.Oo Ar perm Ns | Ns Ar @setname Ns Op , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ... Oc
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.Pp
+Removes permissions that were granted with the
+.Qq Nm Cm allow
+command. No permissions are explicitly denied, so other permissions granted are
+still in effect. For example, if the permission is granted by an ancestor. If
+no permissions are specified, then all permissions for the specified
+.Ar user , group , No or everyone
+are removed. Specifying
+.Cm everyone
+.Po or using the Fl e
+option
+.Pc only removes the permissions that were granted to everyone ,
+not all permissions for every user and group. See the
+.Qq Nm Cm allow
+command for a description of the
+.Fl ldugec
+options.
+.Bl -tag -width indent
+.It Fl r
+Recursively remove the permissions from this file system and all descendents.
+.El
+.It Xo
+.Nm
+.Cm unallow
+.Op Fl r
+.Fl s
+.Ar @setname
+.Oo Ar perm Ns | Ns Ar @setname Ns Op , Ns Ar perm Ns | Ns Ar @setname Ns
+.Ns ... Oc
+.Ar filesystem Ns | Ns Ar volume
+.Xc
+.Pp
+Removes permissions from a permission set. If no permissions are specified,
+then all permissions are removed, thus removing the set entirely.
+.It Xo
+.Nm
+.Cm hold
+.Op Fl r
+.Ar tag snapshot Ns ...
+.Xc
+.Pp
+Adds a single reference, named with the
+.Ar tag
+argument, to the specified snapshot or snapshots. Each snapshot has its own tag
+namespace, and tags must be unique within that space.
+.Pp
+If a hold exists on a snapshot, attempts to destroy that snapshot by using the
+.Qq Nm Cm destroy
+command returns
+.Em EBUSY .
+.Bl -tag -width indent
+.It Fl r
+Specifies that a hold with the given tag is applied recursively to the
+snapshots of all descendent file systems.
+.El
+.It Xo
+.Nm
+.Cm holds
+.Op Fl Hp
+.Op Fl r Ns | Ns Fl d Ar depth
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns
+.Ns ...
+.Xc
+.Pp
+Lists all existing user references for the given dataset or datasets.
+.Bl -tag -width indent
+.It Fl H
+Used for scripting mode. Do not print headers and separate fields by a single
+tab instead of arbitrary white space.
+.It Fl p
+Display numbers in parsable (exact) values.
+.It Fl r
+Lists the holds that are set on the descendent snapshots of the named datasets
+or snapshots, in addition to listing the holds on the named snapshots, if any.
+.It Fl d Ar depth
+Recursively display any holds on the named snapshots, or descendent snapshots of
+the named datasets or snapshots, limiting the recursion to
+.Ar depth .
+.El
+.It Xo
+.Nm
+.Cm release
+.Op Fl r
+.Ar tag snapshot Ns ...
+.Xc
+.Pp
+Removes a single reference, named with the
+.Ar tag
+argument, from the specified snapshot or snapshots. The tag must already exist
+for each snapshot.
+.Bl -tag -width indent
+.It Fl r
+Recursively releases a hold with the given tag on the snapshots of all
+descendent file systems.
+.El
+.It Xo
+.Nm
+.Cm diff
+.Op Fl FHt
+.Ar snapshot
+.Op Ar snapshot Ns | Ns Ar filesystem
+.Xc
+.Pp
+Display the difference between a snapshot of a given filesystem and another
+snapshot of that filesystem from a later time or the current contents of the
+filesystem. The first column is a character indicating the type of change,
+the other columns indicate pathname, new pathname
+.Pq in case of rename ,
+change in link count, and optionally file type and/or change time.
+.Pp
+The types of change are:
+.Bl -column -offset 2n indent
+.It \&- Ta path was removed
+.It \&+ Ta path was added
+.It \&M Ta path was modified
+.It \&R Ta path was renamed
+.El
+.Bl -tag -width indent
+.It Fl F
+Display an indication of the type of file, in a manner similar to the
+.Fl F
+option of
+.Xr ls 1 .
+.Bl -column -offset 2n indent
+.It \&B Ta block device
+.It \&C Ta character device
+.It \&F Ta regular file
+.It \&/ Ta directory
+.It \&@ Ta symbolic link
+.It \&= Ta socket
+.It \&> Ta door (not supported on Fx )
+.It \&| Ta named pipe (not supported on Fx )
+.It \&P Ta event port (not supported on Fx )
+.El
+.It Fl H
+Give more parsable tab-separated output, without header lines and without
+arrows.
+.It Fl t
+Display the path's inode change time as the first column of output.
+.El
+.It Xo
+.Nm
+.Cm program
+.Op Fl jn
+.Op Fl t Ar timeout
+.Op Fl m Ar memory_limit
+.Ar pool script
+.Op Ar arg1 No ...
+.Xc
+.Pp
+Executes
+.Ar script
+as a ZFS channel program on
+.Ar pool .
+The ZFS channel
+program interface allows ZFS administrative operations to be run
+programmatically via a Lua script.
+The entire script is executed atomically, with no other administrative
+operations taking effect concurrently.
+A library of ZFS calls is made available to channel program scripts.
+Channel programs may only be run with root privileges.
+.Pp
+For full documentation of the ZFS channel program interface, see the manual
+page for
+.Xr zfs-program 8 .
+.Bl -tag -width indent
+.It Fl j
+Display channel program output in JSON format.
+When this flag is specified and standard output is empty -
+channel program encountered an error.
+The details of such an error will be printed to standard error in plain text.
+.It Fl n
+Executes a read-only channel program, which runs faster.
+The program cannot change on-disk state by calling functions from
+the zfs.sync submodule.
+The program can be used to gather information such as properties and
+determining if changes would succeed (zfs.check.*).
+Without this flag, all pending changes must be synced to disk before
+a channel program can complete.
+.It Fl t Ar timeout
+Execution time limit, in milliseconds.
+If a channel program executes for longer than the provided timeout, it will
+be stopped and an error will be returned.
+The default timeout is 1000 ms, and can be set to a maximum of 10000 ms.
+.It Fl m Ar memory-limit
+Memory limit, in bytes.
+If a channel program attempts to allocate more memory than the given limit,
+it will be stopped and an error returned.
+The default memory limit is 10 MB, and can be set to a maximum of 100 MB.
+.Pp
+All remaining argument strings are passed directly to the channel program as
+arguments.
+See
+.Xr zfs-program 8
+for more information.
+.El
+.It Xo
+.Nm
+.Cm jail
+.Ar jailid filesystem
+.Xc
+.Pp
+Attaches the specified
+.Ar filesystem
+to the jail identified by JID
+.Ar jailid .
+From now on this file system tree can be managed from within a jail if the
+.Sy jailed
+property has been set. To use this functionality, the jail needs the
+.Va allow.mount
+and
+.Va allow.mount.zfs
+parameters set to 1 and the
+.Va enforce_statfs
+parameter set to a value lower than 2.
+.Pp
+See
+.Xr jail 8
+for more information on managing jails and configuring the parameters above.
+.It Xo
+.Nm
+.Cm unjail
+.Ar jailid filesystem
+.Xc
+.Pp
+Detaches the specified
+.Ar filesystem
+from the jail identified by JID
+.Ar jailid .
+.El
+.Sh EXIT STATUS
+The following exit values are returned:
+.Bl -tag -offset 2n -width 2n
+.It 0
+Successful completion.
+.It 1
+An error occurred.
+.It 2
+Invalid command line options were specified.
+.El
+.Sh EXAMPLES
+.Bl -tag -width 0n
+.It Sy Example 1 No Creating a Tn ZFS No File System Hierarchy
+.Pp
+The following commands create a file system named
+.Em pool/home
+and a file system named
+.Em pool/home/bob .
+The mount point
+.Pa /home
+is set for the parent file system, and is automatically inherited by the child
+file system.
+.Bd -literal -offset 2n
+.Li # Ic zfs create pool/home
+.Li # Ic zfs set mountpoint=/home pool/home
+.Li # Ic zfs create pool/home/bob
+.Ed
+.It Sy Example 2 No Creating a Tn ZFS No Snapshot
+.Pp
+The following command creates a snapshot named
+.Sy yesterday .
+This snapshot is mounted on demand in the
+.Pa \&.zfs/snapshot
+directory at the root of the
+.Em pool/home/bob
+file system.
+.Bd -literal -offset 2n
+.Li # Ic zfs snapshot pool/home/bob@yesterday
+.Ed
+.It Sy Example 3 No Creating and Destroying Multiple Snapshots
+.Pp
+The following command creates snapshots named
+.Em yesterday
+of
+.Em pool/home
+and all of its descendent file systems. Each snapshot is mounted on demand in
+the
+.Pa \&.zfs/snapshot
+directory at the root of its file system. The second command destroys the newly
+created snapshots.
+.Bd -literal -offset 2n
+.Li # Ic zfs snapshot -r pool/home@yesterday
+.Li # Ic zfs destroy -r pool/home@yesterday
+.Ed
+.It Sy Example 4 No Disabling and Enabling File System Compression
+.Pp
+The following command disables the
+.Sy compression
+property for all file systems under
+.Em pool/home .
+The next command explicitly enables
+.Sy compression
+for
+.Em pool/home/anne .
+.Bd -literal -offset 2n
+.Li # Ic zfs set compression=off pool/home
+.Li # Ic zfs set compression=on pool/home/anne
+.Ed
+.It Sy Example 5 No Listing Tn ZFS No Datasets
+.Pp
+The following command lists all active file systems and volumes in the system.
+Snapshots are displayed if the
+.Sy listsnaps
+property is
+.Cm on .
+The default is
+.Cm off .
+See
+.Xr zpool 8
+for more information on pool properties.
+.Bd -literal -offset 2n
+.Li # Ic zfs list
+ NAME USED AVAIL REFER MOUNTPOINT
+ pool 450K 457G 18K /pool
+ pool/home 315K 457G 21K /home
+ pool/home/anne 18K 457G 18K /home/anne
+ pool/home/bob 276K 457G 276K /home/bob
+.Ed
+.It Sy Example 6 No Setting a Quota on a Tn ZFS No File System
+.Pp
+The following command sets a quota of 50 Gbytes for
+.Em pool/home/bob .
+.Bd -literal -offset 2n
+.Li # Ic zfs set quota=50G pool/home/bob
+.Ed
+.It Sy Example 7 No Listing Tn ZFS No Properties
+.Pp
+The following command lists all properties for
+.Em pool/home/bob .
+.Bd -literal -offset 2n
+.Li # Ic zfs get all pool/home/bob
+NAME PROPERTY VALUE SOURCE
+pool/home/bob type filesystem -
+pool/home/bob creation Tue Jul 21 15:53 2009 -
+pool/home/bob used 21K -
+pool/home/bob available 20.0G -
+pool/home/bob referenced 21K -
+pool/home/bob compressratio 1.00x -
+pool/home/bob mounted yes -
+pool/home/bob quota 20G local
+pool/home/bob reservation none default
+pool/home/bob recordsize 128K default
+pool/home/bob mountpoint /home/bob default
+pool/home/bob sharenfs off default
+pool/home/bob checksum on default
+pool/home/bob compression on local
+pool/home/bob atime on default
+pool/home/bob devices on default
+pool/home/bob exec on default
+pool/home/bob filesystem_limit none default
+pool/home/bob setuid on default
+pool/home/bob readonly off default
+pool/home/bob jailed off default
+pool/home/bob snapdir hidden default
+pool/home/bob snapshot_limit none default
+pool/home/bob aclmode discard default
+pool/home/bob aclinherit restricted default
+pool/home/bob canmount on default
+pool/home/bob xattr on default
+pool/home/bob copies 1 default
+pool/home/bob version 5 -
+pool/home/bob utf8only off -
+pool/home/bob normalization none -
+pool/home/bob casesensitivity sensitive -
+pool/home/bob vscan off default
+pool/home/bob nbmand off default
+pool/home/bob sharesmb off default
+pool/home/bob refquota none default
+pool/home/bob refreservation none default
+pool/home/bob primarycache all default
+pool/home/bob secondarycache all default
+pool/home/bob usedbysnapshots 0 -
+pool/home/bob usedbydataset 21K -
+pool/home/bob usedbychildren 0 -
+pool/home/bob usedbyrefreservation 0 -
+pool/home/bob logbias latency default
+pool/home/bob dedup off default
+pool/home/bob mlslabel -
+pool/home/bob sync standard default
+pool/home/bob refcompressratio 1.00x -
+.Ed
+.Pp
+The following command gets a single property value.
+.Bd -literal -offset 2n
+.Li # Ic zfs get -H -o value compression pool/home/bob
+on
+.Ed
+.Pp
+The following command lists all properties with local settings for
+.Em pool/home/bob .
+.Bd -literal -offset 2n
+.Li # Ic zfs get -s local -o name,property,value all pool/home/bob
+NAME PROPERTY VALUE
+pool/home/bob quota 20G
+pool/home/bob compression on
+.Ed
+.It Sy Example 8 No Rolling Back a Tn ZFS No File System
+.Pp
+The following command reverts the contents of
+.Em pool/home/anne
+to the snapshot named
+.Em yesterday ,
+deleting all intermediate snapshots.
+.Bd -literal -offset 2n
+.Li # Ic zfs rollback -r pool/home/anne@yesterday
+.Ed
+.It Sy Example 9 No Creating a Tn ZFS No Clone
+.Pp
+The following command creates a writable file system whose initial contents are
+the same as
+.Em pool/home/bob@yesterday .
+.Bd -literal -offset 2n
+.Li # Ic zfs clone pool/home/bob@yesterday pool/clone
+.Ed
+.It Sy Example 10 No Promoting a Tn ZFS No Clone
+.Pp
+The following commands illustrate how to test out changes to a file system, and
+then replace the original file system with the changed one, using clones, clone
+promotion, and renaming:
+.Bd -literal -offset 2n
+.Li # Ic zfs create pool/project/production
+.Ed
+.Pp
+Populate
+.Pa /pool/project/production
+with data and continue with the following commands:
+.Bd -literal -offset 2n
+.Li # Ic zfs snapshot pool/project/production@today
+.Li # Ic zfs clone pool/project/production@today pool/project/beta
+.Ed
+.Pp
+Now make changes to
+.Pa /pool/project/beta
+and continue with the following commands:
+.Bd -literal -offset 2n
+.Li # Ic zfs promote pool/project/beta
+.Li # Ic zfs rename pool/project/production pool/project/legacy
+.Li # Ic zfs rename pool/project/beta pool/project/production
+.Ed
+.Pp
+Once the legacy version is no longer needed, it can be destroyed.
+.Bd -literal -offset 2n
+.Li # Ic zfs destroy pool/project/legacy
+.Ed
+.It Sy Example 11 No Inheriting Tn ZFS No Properties
+.Pp
+The following command causes
+.Em pool/home/bob
+and
+.Em pool/home/anne
+to inherit the
+.Sy checksum
+property from their parent.
+.Bd -literal -offset 2n
+.Li # Ic zfs inherit checksum pool/home/bob pool/home/anne
+.Ed
+.It Sy Example 12 No Remotely Replicating Tn ZFS No Data
+.Pp
+The following commands send a full stream and then an incremental stream to a
+remote machine, restoring them into
+.Sy poolB/received/fs@a
+and
+.Sy poolB/received/fs@b ,
+respectively.
+.Sy poolB
+must contain the file system
+.Sy poolB/received ,
+and must not initially contain
+.Sy poolB/received/fs .
+.Bd -literal -offset 2n
+.Li # Ic zfs send pool/fs@a | ssh host zfs receive poolB/received/fs@a
+.Li # Ic zfs send -i a pool/fs@b | ssh host zfs receive poolB/received/fs
+.Ed
+.It Xo
+.Sy Example 13
+Using the
+.Qq zfs receive -d
+Option
+.Xc
+.Pp
+The following command sends a full stream of
+.Sy poolA/fsA/fsB@snap
+to a remote machine, receiving it into
+.Sy poolB/received/fsA/fsB@snap .
+The
+.Sy fsA/fsB@snap
+portion of the received snapshot's name is determined from the name of the sent
+snapshot.
+.Sy poolB
+must contain the file system
+.Sy poolB/received .
+If
+.Sy poolB/received/fsA
+does not exist, it is created as an empty file system.
+.Bd -literal -offset 2n
+.Li # Ic zfs send poolA/fsA/fsB@snap | ssh host zfs receive -d poolB/received
+.Ed
+.It Sy Example 14 No Setting User Properties
+.Pp
+The following example sets the user-defined
+.Sy com.example:department
+property for a dataset.
+.Bd -literal -offset 2n
+.Li # Ic zfs set com.example:department=12345 tank/accounting
+.Ed
+.It Sy Example 15 No Performing a Rolling Snapshot
+.Pp
+The following example shows how to maintain a history of snapshots with a
+consistent naming scheme. To keep a week's worth of snapshots, the user
+destroys the oldest snapshot, renames the remaining snapshots, and then creates
+a new snapshot, as follows:
+.Bd -literal -offset 2n
+.Li # Ic zfs destroy -r pool/users@7daysago
+.Li # Ic zfs rename -r pool/users@6daysago @7daysago
+.Li # Ic zfs rename -r pool/users@5daysago @6daysago
+.Li # Ic zfs rename -r pool/users@4daysago @5daysago
+.Li # Ic zfs rename -r pool/users@3daysago @4daysago
+.Li # Ic zfs rename -r pool/users@2daysago @3daysago
+.Li # Ic zfs rename -r pool/users@yesterday @2daysago
+.Li # Ic zfs rename -r pool/users@today @yesterday
+.Li # Ic zfs snapshot -r pool/users@today
+.Ed
+.It Xo
+.Sy Example 16
+Setting
+.Qq sharenfs
+Property Options on a ZFS File System
+.Xc
+.Pp
+The following command shows how to set
+.Sy sharenfs
+property options to enable root access for a specific network on the
+.Em tank/home
+file system. The contents of the
+.Sy sharenfs
+property are valid
+.Xr exports 5
+options.
+.Bd -literal -offset 2n
+.Li # Ic zfs set sharenfs="maproot=root,network 192.168.0.0/24" tank/home
+.Ed
+.Pp
+Another way to write this command with the same result is:
+.Bd -literal -offset 2n
+.Li # Ic set zfs sharenfs="-maproot=root -network 192.168.0.0/24" tank/home
+.Ed
+.It Xo
+.Sy Example 17
+Delegating
+.Tn ZFS
+Administration Permissions on a
+.Tn ZFS
+Dataset
+.Xc
+.Pp
+The following example shows how to set permissions so that user
+.Em cindys
+can create, destroy, mount, and take snapshots on
+.Em tank/cindys .
+The permissions on
+.Em tank/cindys
+are also displayed.
+.Bd -literal -offset 2n
+.Li # Ic zfs allow cindys create,destroy,mount,snapshot tank/cindys
+.Li # Ic zfs allow tank/cindys
+---- Permissions on tank/cindys --------------------------------------
+Local+Descendent permissions:
+ user cindys create,destroy,mount,snapshot
+.Ed
+.It Sy Example 18 No Delegating Create Time Permissions on a Tn ZFS No Dataset
+.Pp
+The following example shows how to grant anyone in the group
+.Em staff
+to create file systems in
+.Em tank/users .
+This syntax also allows staff members to destroy their own file systems, but
+not destroy anyone else's file system. The permissions on
+.Em tank/users
+are also displayed.
+.Bd -literal -offset 2n
+.Li # Ic zfs allow staff create,mount tank/users
+.Li # Ic zfs allow -c destroy tank/users
+.Li # Ic zfs allow tank/users
+---- Permissions on tank/users ---------------------------------------
+Permission sets:
+ destroy
+Local+Descendent permissions:
+ group staff create,mount
+.Ed
+.It Xo
+.Sy Example 19
+Defining and Granting a Permission Set on a
+.Tn ZFS
+Dataset
+.Xc
+.Pp
+The following example shows how to define and grant a permission set on the
+.Em tank/users
+file system. The permissions on
+.Em tank/users
+are also displayed.
+.Bd -literal -offset 2n
+.Li # Ic zfs allow -s @pset create,destroy,snapshot,mount tank/users
+.Li # Ic zfs allow staff @pset tank/users
+.Li # Ic zfs allow tank/users
+---- Permissions on tank/users ---------------------------------------
+Permission sets:
+ @pset create,destroy,mount,snapshot
+Local+Descendent permissions:
+ group staff @pset
+.Ed
+.It Sy Example 20 No Delegating Property Permissions on a Tn ZFS No Dataset
+.Pp
+The following example shows to grant the ability to set quotas and reservations
+on the
+.Sy users/home
+file system. The permissions on
+.Sy users/home
+are also displayed.
+.Bd -literal -offset 2n
+.Li # Ic zfs allow cindys quota,reservation users/home
+.Li # Ic zfs allow users/home
+---- Permissions on users/home ---------------------------------------
+Local+Descendent permissions:
+ user cindys quota,reservation
+.Li # Ic su - cindys
+.Li cindys% Ic zfs set quota=10G users/home/marks
+.Li cindys% Ic zfs get quota users/home/marks
+NAME PROPERTY VALUE SOURCE
+users/home/marks quota 10G local
+.Ed
+.It Sy Example 21 No Removing ZFS Delegated Permissions on a Tn ZFS No Dataset
+.Pp
+The following example shows how to remove the snapshot permission from the
+.Em staff
+group on the
+.Em tank/users
+file system. The permissions on
+.Em tank/users
+are also displayed.
+.Bd -literal -offset 2n
+.Li # Ic zfs unallow staff snapshot tank/users
+.Li # Ic zfs allow tank/users
+---- Permissions on tank/users ---------------------------------------
+Permission sets:
+ @pset create,destroy,mount,snapshot
+Local+Descendent permissions:
+ group staff @pset
+.Ed
+.It Sy Example 22 Showing the differences between a snapshot and a ZFS Dataset
+.Pp
+The following example shows how to see what has changed between a prior
+snapshot of a ZFS Dataset and its current state. The
+.Fl F
+option is used to indicate type information for the files affected.
+.Bd -literal -offset 2n
+.Li # Ic zfs diff tank/test@before tank/test
+M / /tank/test/
+M F /tank/test/linked (+1)
+R F /tank/test/oldname -> /tank/test/newname
+- F /tank/test/deleted
++ F /tank/test/created
+M F /tank/test/modified
+.Ed
+.El
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr fsync 2 ,
+.Xr exports 5 ,
+.Xr fstab 5 ,
+.Xr rc.conf 5 ,
+.Xr jail 8 ,
+.Xr mount 8 ,
+.Xr umount 8 ,
+.Xr zfs-program 8 ,
+.Xr zpool 8
+.Sh AUTHORS
+This manual page is a
+.Xr mdoc 7
+reimplementation of the
+.Tn OpenSolaris
+manual page
+.Em zfs(1M) ,
+modified and customized for
+.Fx
+and licensed under the
+Common Development and Distribution License
+.Pq Tn CDDL .
+.Pp
+The
+.Xr mdoc 7
+implementation of this manual page was initially written by
+.An Martin Matuska Aq mm@FreeBSD.org .
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.c
new file mode 100644
index 000000000000..a291db083568
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.c
@@ -0,0 +1,497 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <libintl.h>
+#include <libuutil.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <libzfs.h>
+
+#include "zfs_util.h"
+#include "zfs_iter.h"
+
+/*
+ * This is a private interface used to gather up all the datasets specified on
+ * the command line so that we can iterate over them in order.
+ *
+ * First, we iterate over all filesystems, gathering them together into an
+ * AVL tree. We report errors for any explicitly specified datasets
+ * that we couldn't open.
+ *
+ * When finished, we have an AVL tree of ZFS handles. We go through and execute
+ * the provided callback for each one, passing whatever data the user supplied.
+ */
+
+typedef struct zfs_node {
+ zfs_handle_t *zn_handle;
+ uu_avl_node_t zn_avlnode;
+} zfs_node_t;
+
+typedef struct callback_data {
+ uu_avl_t *cb_avl;
+ int cb_flags;
+ zfs_type_t cb_types;
+ zfs_sort_column_t *cb_sortcol;
+ zprop_list_t **cb_proplist;
+ int cb_depth_limit;
+ int cb_depth;
+ uint8_t cb_props_table[ZFS_NUM_PROPS];
+} callback_data_t;
+
+uu_avl_pool_t *avl_pool;
+
+/*
+ * Include snaps if they were requested or if this a zfs list where types
+ * were not specified and the "listsnapshots" property is set on this pool.
+ */
+static boolean_t
+zfs_include_snapshots(zfs_handle_t *zhp, callback_data_t *cb)
+{
+ zpool_handle_t *zph;
+
+ if ((cb->cb_flags & ZFS_ITER_PROP_LISTSNAPS) == 0)
+ return (cb->cb_types & ZFS_TYPE_SNAPSHOT);
+
+ zph = zfs_get_pool_handle(zhp);
+ return (zpool_get_prop_int(zph, ZPOOL_PROP_LISTSNAPS, NULL));
+}
+
+/*
+ * Called for each dataset. If the object is of an appropriate type,
+ * add it to the avl tree and recurse over any children as necessary.
+ */
+static int
+zfs_callback(zfs_handle_t *zhp, void *data)
+{
+ callback_data_t *cb = data;
+ boolean_t should_close = B_TRUE;
+ boolean_t include_snaps = zfs_include_snapshots(zhp, cb);
+ boolean_t include_bmarks = (cb->cb_types & ZFS_TYPE_BOOKMARK);
+
+ if ((zfs_get_type(zhp) & cb->cb_types) ||
+ ((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) {
+ uu_avl_index_t idx;
+ zfs_node_t *node = safe_malloc(sizeof (zfs_node_t));
+
+ node->zn_handle = zhp;
+ uu_avl_node_init(node, &node->zn_avlnode, avl_pool);
+ if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol,
+ &idx) == NULL) {
+ if (cb->cb_proplist) {
+ if ((*cb->cb_proplist) &&
+ !(*cb->cb_proplist)->pl_all)
+ zfs_prune_proplist(zhp,
+ cb->cb_props_table);
+
+ if (zfs_expand_proplist(zhp, cb->cb_proplist,
+ (cb->cb_flags & ZFS_ITER_RECVD_PROPS),
+ (cb->cb_flags & ZFS_ITER_LITERAL_PROPS))
+ != 0) {
+ free(node);
+ return (-1);
+ }
+ }
+ uu_avl_insert(cb->cb_avl, node, idx);
+ should_close = B_FALSE;
+ } else {
+ free(node);
+ }
+ }
+
+ /*
+ * Recurse if necessary.
+ */
+ if (cb->cb_flags & ZFS_ITER_RECURSE &&
+ ((cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 ||
+ cb->cb_depth < cb->cb_depth_limit)) {
+ cb->cb_depth++;
+ if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)
+ (void) zfs_iter_filesystems(zhp, zfs_callback, data);
+ if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
+ ZFS_TYPE_BOOKMARK)) == 0) && include_snaps)
+ (void) zfs_iter_snapshots(zhp,
+ (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback,
+ data, 0, 0);
+ if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
+ ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks)
+ (void) zfs_iter_bookmarks(zhp, zfs_callback, data);
+ cb->cb_depth--;
+ }
+
+ if (should_close)
+ zfs_close(zhp);
+
+ return (0);
+}
+
+int
+zfs_add_sort_column(zfs_sort_column_t **sc, const char *name,
+ boolean_t reverse)
+{
+ zfs_sort_column_t *col;
+ zfs_prop_t prop;
+
+ if ((prop = zfs_name_to_prop(name)) == ZPROP_INVAL &&
+ !zfs_prop_user(name))
+ return (-1);
+
+ col = safe_malloc(sizeof (zfs_sort_column_t));
+
+ col->sc_prop = prop;
+ col->sc_reverse = reverse;
+ if (prop == ZPROP_INVAL) {
+ col->sc_user_prop = safe_malloc(strlen(name) + 1);
+ (void) strcpy(col->sc_user_prop, name);
+ }
+
+ if (*sc == NULL) {
+ col->sc_last = col;
+ *sc = col;
+ } else {
+ (*sc)->sc_last->sc_next = col;
+ (*sc)->sc_last = col;
+ }
+
+ return (0);
+}
+
+void
+zfs_free_sort_columns(zfs_sort_column_t *sc)
+{
+ zfs_sort_column_t *col;
+
+ while (sc != NULL) {
+ col = sc->sc_next;
+ free(sc->sc_user_prop);
+ free(sc);
+ sc = col;
+ }
+}
+
+boolean_t
+zfs_sort_only_by_name(const zfs_sort_column_t *sc)
+{
+
+ return (sc != NULL && sc->sc_next == NULL &&
+ sc->sc_prop == ZFS_PROP_NAME);
+}
+
+/* ARGSUSED */
+static int
+zfs_compare(const void *larg, const void *rarg, void *unused)
+{
+ zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
+ zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
+ const char *lname = zfs_get_name(l);
+ const char *rname = zfs_get_name(r);
+ char *lat, *rat;
+ uint64_t lcreate, rcreate;
+ int ret;
+
+ lat = (char *)strchr(lname, '@');
+ rat = (char *)strchr(rname, '@');
+
+ if (lat != NULL)
+ *lat = '\0';
+ if (rat != NULL)
+ *rat = '\0';
+
+ ret = strcmp(lname, rname);
+ if (ret == 0 && (lat != NULL || rat != NULL)) {
+ /*
+ * If we're comparing a dataset to one of its snapshots, we
+ * always make the full dataset first.
+ */
+ if (lat == NULL) {
+ ret = -1;
+ } else if (rat == NULL) {
+ ret = 1;
+ } else {
+ /*
+ * If we have two snapshots from the same dataset, then
+ * we want to sort them according to creation time. We
+ * use the hidden CREATETXG property to get an absolute
+ * ordering of snapshots.
+ */
+ lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
+ rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
+
+ /*
+ * Both lcreate and rcreate being 0 means we don't have
+ * properties and we should compare full name.
+ */
+ if (lcreate == 0 && rcreate == 0)
+ ret = strcmp(lat + 1, rat + 1);
+ else if (lcreate < rcreate)
+ ret = -1;
+ else if (lcreate > rcreate)
+ ret = 1;
+ }
+ }
+
+ if (lat != NULL)
+ *lat = '@';
+ if (rat != NULL)
+ *rat = '@';
+
+ return (ret);
+}
+
+/*
+ * Sort datasets by specified columns.
+ *
+ * o Numeric types sort in ascending order.
+ * o String types sort in alphabetical order.
+ * o Types inappropriate for a row sort that row to the literal
+ * bottom, regardless of the specified ordering.
+ *
+ * If no sort columns are specified, or two datasets compare equally
+ * across all specified columns, they are sorted alphabetically by name
+ * with snapshots grouped under their parents.
+ */
+static int
+zfs_sort(const void *larg, const void *rarg, void *data)
+{
+ zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
+ zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
+ zfs_sort_column_t *sc = (zfs_sort_column_t *)data;
+ zfs_sort_column_t *psc;
+
+ for (psc = sc; psc != NULL; psc = psc->sc_next) {
+ char lbuf[ZFS_MAXPROPLEN], rbuf[ZFS_MAXPROPLEN];
+ char *lstr, *rstr;
+ uint64_t lnum, rnum;
+ boolean_t lvalid, rvalid;
+ int ret = 0;
+
+ /*
+ * We group the checks below the generic code. If 'lstr' and
+ * 'rstr' are non-NULL, then we do a string based comparison.
+ * Otherwise, we compare 'lnum' and 'rnum'.
+ */
+ lstr = rstr = NULL;
+ if (psc->sc_prop == ZPROP_INVAL) {
+ nvlist_t *luser, *ruser;
+ nvlist_t *lval, *rval;
+
+ luser = zfs_get_user_props(l);
+ ruser = zfs_get_user_props(r);
+
+ lvalid = (nvlist_lookup_nvlist(luser,
+ psc->sc_user_prop, &lval) == 0);
+ rvalid = (nvlist_lookup_nvlist(ruser,
+ psc->sc_user_prop, &rval) == 0);
+
+ if (lvalid)
+ verify(nvlist_lookup_string(lval,
+ ZPROP_VALUE, &lstr) == 0);
+ if (rvalid)
+ verify(nvlist_lookup_string(rval,
+ ZPROP_VALUE, &rstr) == 0);
+ } else if (psc->sc_prop == ZFS_PROP_NAME) {
+ lvalid = rvalid = B_TRUE;
+
+ (void) strlcpy(lbuf, zfs_get_name(l), sizeof (lbuf));
+ (void) strlcpy(rbuf, zfs_get_name(r), sizeof (rbuf));
+
+ lstr = lbuf;
+ rstr = rbuf;
+ } else if (zfs_prop_is_string(psc->sc_prop)) {
+ lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf,
+ sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0);
+ rvalid = (zfs_prop_get(r, psc->sc_prop, rbuf,
+ sizeof (rbuf), NULL, NULL, 0, B_TRUE) == 0);
+
+ lstr = lbuf;
+ rstr = rbuf;
+ } else {
+ lvalid = zfs_prop_valid_for_type(psc->sc_prop,
+ zfs_get_type(l));
+ rvalid = zfs_prop_valid_for_type(psc->sc_prop,
+ zfs_get_type(r));
+
+ if (lvalid)
+ (void) zfs_prop_get_numeric(l, psc->sc_prop,
+ &lnum, NULL, NULL, 0);
+ if (rvalid)
+ (void) zfs_prop_get_numeric(r, psc->sc_prop,
+ &rnum, NULL, NULL, 0);
+ }
+
+ if (!lvalid && !rvalid)
+ continue;
+ else if (!lvalid)
+ return (1);
+ else if (!rvalid)
+ return (-1);
+
+ if (lstr)
+ ret = strcmp(lstr, rstr);
+ else if (lnum < rnum)
+ ret = -1;
+ else if (lnum > rnum)
+ ret = 1;
+
+ if (ret != 0) {
+ if (psc->sc_reverse == B_TRUE)
+ ret = (ret < 0) ? 1 : -1;
+ return (ret);
+ }
+ }
+
+ return (zfs_compare(larg, rarg, NULL));
+}
+
+int
+zfs_for_each(int argc, char **argv, int flags, zfs_type_t types,
+ zfs_sort_column_t *sortcol, zprop_list_t **proplist, int limit,
+ zfs_iter_f callback, void *data)
+{
+ callback_data_t cb = {0};
+ int ret = 0;
+ zfs_node_t *node;
+ uu_avl_walk_t *walk;
+
+ avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t),
+ offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT);
+
+ if (avl_pool == NULL)
+ nomem();
+
+ cb.cb_sortcol = sortcol;
+ cb.cb_flags = flags;
+ cb.cb_proplist = proplist;
+ cb.cb_types = types;
+ cb.cb_depth_limit = limit;
+ /*
+ * If cb_proplist is provided then in the zfs_handles created we
+ * retain only those properties listed in cb_proplist and sortcol.
+ * The rest are pruned. So, the caller should make sure that no other
+ * properties other than those listed in cb_proplist/sortcol are
+ * accessed.
+ *
+ * If cb_proplist is NULL then we retain all the properties. We
+ * always retain the zoned property, which some other properties
+ * need (userquota & friends), and the createtxg property, which
+ * we need to sort snapshots.
+ */
+ if (cb.cb_proplist && *cb.cb_proplist) {
+ zprop_list_t *p = *cb.cb_proplist;
+
+ while (p) {
+ if (p->pl_prop >= ZFS_PROP_TYPE &&
+ p->pl_prop < ZFS_NUM_PROPS) {
+ cb.cb_props_table[p->pl_prop] = B_TRUE;
+ }
+ p = p->pl_next;
+ }
+
+ while (sortcol) {
+ if (sortcol->sc_prop >= ZFS_PROP_TYPE &&
+ sortcol->sc_prop < ZFS_NUM_PROPS) {
+ cb.cb_props_table[sortcol->sc_prop] = B_TRUE;
+ }
+ sortcol = sortcol->sc_next;
+ }
+
+ cb.cb_props_table[ZFS_PROP_ZONED] = B_TRUE;
+ cb.cb_props_table[ZFS_PROP_CREATETXG] = B_TRUE;
+ } else {
+ (void) memset(cb.cb_props_table, B_TRUE,
+ sizeof (cb.cb_props_table));
+ }
+
+ if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
+ nomem();
+
+ if (argc == 0) {
+ /*
+ * If given no arguments, iterate over all datasets.
+ */
+ cb.cb_flags |= ZFS_ITER_RECURSE;
+ ret = zfs_iter_root(g_zfs, zfs_callback, &cb);
+ } else {
+ int i;
+ zfs_handle_t *zhp;
+ zfs_type_t argtype;
+
+ /*
+ * If we're recursive, then we always allow filesystems as
+ * arguments. If we also are interested in snapshots or
+ * bookmarks, then we can take volumes as well.
+ */
+ argtype = types;
+ if (flags & ZFS_ITER_RECURSE) {
+ argtype |= ZFS_TYPE_FILESYSTEM;
+ if (types & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK))
+ argtype |= ZFS_TYPE_VOLUME;
+ }
+
+ for (i = 0; i < argc; i++) {
+ if (flags & ZFS_ITER_ARGS_CAN_BE_PATHS) {
+ zhp = zfs_path_to_zhandle(g_zfs, argv[i],
+ argtype);
+ } else {
+ zhp = zfs_open(g_zfs, argv[i], argtype);
+ }
+ if (zhp != NULL)
+ ret |= zfs_callback(zhp, &cb);
+ else
+ ret = 1;
+ }
+ }
+
+ /*
+ * At this point we've got our AVL tree full of zfs handles, so iterate
+ * over each one and execute the real user callback.
+ */
+ for (node = uu_avl_first(cb.cb_avl); node != NULL;
+ node = uu_avl_next(cb.cb_avl, node))
+ ret |= callback(node->zn_handle, data);
+
+ /*
+ * Finally, clean up the AVL tree.
+ */
+ if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
+ nomem();
+
+ while ((node = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_remove(cb.cb_avl, node);
+ zfs_close(node->zn_handle);
+ free(node);
+ }
+
+ uu_avl_walk_end(walk);
+ uu_avl_destroy(cb.cb_avl);
+ uu_avl_pool_destroy(avl_pool);
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.h b/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.h
new file mode 100644
index 000000000000..b89b466ce6fe
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.h
@@ -0,0 +1,62 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef ZFS_ITER_H
+#define ZFS_ITER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct zfs_sort_column {
+ struct zfs_sort_column *sc_next;
+ struct zfs_sort_column *sc_last;
+ zfs_prop_t sc_prop;
+ char *sc_user_prop;
+ boolean_t sc_reverse;
+} zfs_sort_column_t;
+
+#define ZFS_ITER_RECURSE (1 << 0)
+#define ZFS_ITER_ARGS_CAN_BE_PATHS (1 << 1)
+#define ZFS_ITER_PROP_LISTSNAPS (1 << 2)
+#define ZFS_ITER_DEPTH_LIMIT (1 << 3)
+#define ZFS_ITER_RECVD_PROPS (1 << 4)
+#define ZFS_ITER_SIMPLE (1 << 5)
+#define ZFS_ITER_LITERAL_PROPS (1 << 6)
+
+int zfs_for_each(int, char **, int options, zfs_type_t,
+ zfs_sort_column_t *, zprop_list_t **, int, zfs_iter_f, void *);
+int zfs_add_sort_column(zfs_sort_column_t **, const char *, boolean_t);
+void zfs_free_sort_columns(zfs_sort_column_t *);
+boolean_t zfs_sort_only_by_name(const zfs_sort_column_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZFS_ITER_H */
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
new file mode 100644
index 000000000000..3f389d1a51ff
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
@@ -0,0 +1,7579 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
+ * Copyright 2012 Milan Jurik. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
+ * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright (c) 2019 Datto Inc.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <libuutil.h>
+#include <libnvpair.h>
+#include <locale.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <zone.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <sys/debug.h>
+#include <sys/list.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fs/zfs.h>
+#include <sys/types.h>
+#include <time.h>
+#include <err.h>
+#include <jail.h>
+
+#include <libzfs.h>
+#include <libzfs_core.h>
+#include <zfs_prop.h>
+#include <zfs_deleg.h>
+#include <libuutil.h>
+#ifdef illumos
+#include <aclutils.h>
+#include <directory.h>
+#include <idmap.h>
+#include <libshare.h>
+#endif
+
+#include "zfs_iter.h"
+#include "zfs_util.h"
+#include "zfs_comutil.h"
+
+libzfs_handle_t *g_zfs;
+
+static FILE *mnttab_file;
+static char history_str[HIS_MAX_RECORD_LEN];
+static boolean_t log_history = B_TRUE;
+
+static int zfs_do_clone(int argc, char **argv);
+static int zfs_do_create(int argc, char **argv);
+static int zfs_do_destroy(int argc, char **argv);
+static int zfs_do_get(int argc, char **argv);
+static int zfs_do_inherit(int argc, char **argv);
+static int zfs_do_list(int argc, char **argv);
+static int zfs_do_mount(int argc, char **argv);
+static int zfs_do_rename(int argc, char **argv);
+static int zfs_do_rollback(int argc, char **argv);
+static int zfs_do_set(int argc, char **argv);
+static int zfs_do_upgrade(int argc, char **argv);
+static int zfs_do_snapshot(int argc, char **argv);
+static int zfs_do_unmount(int argc, char **argv);
+static int zfs_do_share(int argc, char **argv);
+static int zfs_do_unshare(int argc, char **argv);
+static int zfs_do_send(int argc, char **argv);
+static int zfs_do_receive(int argc, char **argv);
+static int zfs_do_promote(int argc, char **argv);
+static int zfs_do_userspace(int argc, char **argv);
+static int zfs_do_allow(int argc, char **argv);
+static int zfs_do_unallow(int argc, char **argv);
+static int zfs_do_hold(int argc, char **argv);
+static int zfs_do_holds(int argc, char **argv);
+static int zfs_do_release(int argc, char **argv);
+static int zfs_do_diff(int argc, char **argv);
+static int zfs_do_jail(int argc, char **argv);
+static int zfs_do_unjail(int argc, char **argv);
+static int zfs_do_bookmark(int argc, char **argv);
+static int zfs_do_remap(int argc, char **argv);
+static int zfs_do_channel_program(int argc, char **argv);
+
+/*
+ * Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
+ */
+
+#ifdef DEBUG
+const char *
+_umem_debug_init(void)
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+#endif
+
+typedef enum {
+ HELP_CLONE,
+ HELP_CREATE,
+ HELP_DESTROY,
+ HELP_GET,
+ HELP_INHERIT,
+ HELP_UPGRADE,
+ HELP_JAIL,
+ HELP_UNJAIL,
+ HELP_LIST,
+ HELP_MOUNT,
+ HELP_PROMOTE,
+ HELP_RECEIVE,
+ HELP_RENAME,
+ HELP_ROLLBACK,
+ HELP_SEND,
+ HELP_SET,
+ HELP_SHARE,
+ HELP_SNAPSHOT,
+ HELP_UNMOUNT,
+ HELP_UNSHARE,
+ HELP_ALLOW,
+ HELP_UNALLOW,
+ HELP_USERSPACE,
+ HELP_GROUPSPACE,
+ HELP_HOLD,
+ HELP_HOLDS,
+ HELP_RELEASE,
+ HELP_DIFF,
+ HELP_REMAP,
+ HELP_BOOKMARK,
+ HELP_CHANNEL_PROGRAM,
+} zfs_help_t;
+
+typedef struct zfs_command {
+ const char *name;
+ int (*func)(int argc, char **argv);
+ zfs_help_t usage;
+} zfs_command_t;
+
+/*
+ * Master command table. Each ZFS command has a name, associated function, and
+ * usage message. The usage messages need to be internationalized, so we have
+ * to have a function to return the usage message based on a command index.
+ *
+ * These commands are organized according to how they are displayed in the usage
+ * message. An empty command (one with a NULL name) indicates an empty line in
+ * the generic usage message.
+ */
+static zfs_command_t command_table[] = {
+ { "create", zfs_do_create, HELP_CREATE },
+ { "destroy", zfs_do_destroy, HELP_DESTROY },
+ { NULL },
+ { "snapshot", zfs_do_snapshot, HELP_SNAPSHOT },
+ { "rollback", zfs_do_rollback, HELP_ROLLBACK },
+ { "clone", zfs_do_clone, HELP_CLONE },
+ { "promote", zfs_do_promote, HELP_PROMOTE },
+ { "rename", zfs_do_rename, HELP_RENAME },
+ { "bookmark", zfs_do_bookmark, HELP_BOOKMARK },
+ { "program", zfs_do_channel_program, HELP_CHANNEL_PROGRAM },
+ { NULL },
+ { "list", zfs_do_list, HELP_LIST },
+ { NULL },
+ { "set", zfs_do_set, HELP_SET },
+ { "get", zfs_do_get, HELP_GET },
+ { "inherit", zfs_do_inherit, HELP_INHERIT },
+ { "upgrade", zfs_do_upgrade, HELP_UPGRADE },
+ { "userspace", zfs_do_userspace, HELP_USERSPACE },
+ { "groupspace", zfs_do_userspace, HELP_GROUPSPACE },
+ { NULL },
+ { "mount", zfs_do_mount, HELP_MOUNT },
+ { "unmount", zfs_do_unmount, HELP_UNMOUNT },
+ { "share", zfs_do_share, HELP_SHARE },
+ { "unshare", zfs_do_unshare, HELP_UNSHARE },
+ { NULL },
+ { "send", zfs_do_send, HELP_SEND },
+ { "receive", zfs_do_receive, HELP_RECEIVE },
+ { NULL },
+ { "allow", zfs_do_allow, HELP_ALLOW },
+ { NULL },
+ { "unallow", zfs_do_unallow, HELP_UNALLOW },
+ { NULL },
+ { "hold", zfs_do_hold, HELP_HOLD },
+ { "holds", zfs_do_holds, HELP_HOLDS },
+ { "release", zfs_do_release, HELP_RELEASE },
+ { "diff", zfs_do_diff, HELP_DIFF },
+ { NULL },
+ { "jail", zfs_do_jail, HELP_JAIL },
+ { "unjail", zfs_do_unjail, HELP_UNJAIL },
+ { "remap", zfs_do_remap, HELP_REMAP },
+};
+
+#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
+
+zfs_command_t *current_command;
+
+static const char *
+get_usage(zfs_help_t idx)
+{
+ switch (idx) {
+ case HELP_CLONE:
+ return (gettext("\tclone [-p] [-o property=value] ... "
+ "<snapshot> <filesystem|volume>\n"));
+ case HELP_CREATE:
+ return (gettext("\tcreate [-pu] [-o property=value] ... "
+ "<filesystem>\n"
+ "\tcreate [-ps] [-b blocksize] [-o property=value] ... "
+ "-V <size> <volume>\n"));
+ case HELP_DESTROY:
+ return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
+ "\tdestroy [-dnpRrv] "
+ "<filesystem|volume>@<snap>[%<snap>][,...]\n"
+ "\tdestroy <filesystem|volume>#<bookmark>\n"));
+ case HELP_GET:
+ return (gettext("\tget [-rHp] [-d max] "
+ "[-o \"all\" | field[,...]]\n"
+ "\t [-t type[,...]] [-s source[,...]]\n"
+ "\t <\"all\" | property[,...]> "
+ "[filesystem|volume|snapshot|bookmark] ...\n"));
+ case HELP_INHERIT:
+ return (gettext("\tinherit [-rS] <property> "
+ "<filesystem|volume|snapshot> ...\n"));
+ case HELP_UPGRADE:
+ return (gettext("\tupgrade [-v]\n"
+ "\tupgrade [-r] [-V version] <-a | filesystem ...>\n"));
+ case HELP_JAIL:
+ return (gettext("\tjail <jailid|jailname> <filesystem>\n"));
+ case HELP_UNJAIL:
+ return (gettext("\tunjail <jailid|jailname> <filesystem>\n"));
+ case HELP_LIST:
+ return (gettext("\tlist [-Hp] [-r|-d max] [-o property[,...]] "
+ "[-s property]...\n\t [-S property]... [-t type[,...]] "
+ "[filesystem|volume|snapshot] ...\n"));
+ case HELP_MOUNT:
+ return (gettext("\tmount\n"
+ "\tmount [-vO] [-o opts] <-a | filesystem>\n"));
+ case HELP_PROMOTE:
+ return (gettext("\tpromote <clone-filesystem>\n"));
+ case HELP_RECEIVE:
+ return (gettext("\treceive|recv [-vnsFu] <filesystem|volume|"
+ "snapshot>\n"
+ "\treceive|recv [-vnsFu] [-o origin=<snapshot>] [-d | -e] "
+ "<filesystem>\n"
+ "\treceive|recv -A <filesystem|volume>\n"));
+ case HELP_RENAME:
+ return (gettext("\trename [-f] <filesystem|volume|snapshot> "
+ "<filesystem|volume|snapshot>\n"
+ "\trename [-f] -p <filesystem|volume> <filesystem|volume>\n"
+ "\trename -r <snapshot> <snapshot>\n"
+ "\trename <bookmark> <bookmark>\n"
+ "\trename -u [-p] <filesystem> <filesystem>"));
+ case HELP_ROLLBACK:
+ return (gettext("\trollback [-rRf] <snapshot>\n"));
+ case HELP_SEND:
+ return (gettext("\tsend [-DnPpRvLec] [-[iI] snapshot] "
+ "<snapshot>\n"
+ "\tsend [-LPcenv] [-i snapshot|bookmark] "
+ "<filesystem|volume|snapshot>\n"
+ "\tsend [-nvPe] -t <receive_resume_token>\n"));
+ case HELP_SET:
+ return (gettext("\tset <property=value> ... "
+ "<filesystem|volume|snapshot> ...\n"));
+ case HELP_SHARE:
+ return (gettext("\tshare <-a | filesystem>\n"));
+ case HELP_SNAPSHOT:
+ return (gettext("\tsnapshot|snap [-r] [-o property=value] ... "
+ "<filesystem|volume>@<snap> ...\n"));
+ case HELP_UNMOUNT:
+ return (gettext("\tunmount|umount [-f] "
+ "<-a | filesystem|mountpoint>\n"));
+ case HELP_UNSHARE:
+ return (gettext("\tunshare "
+ "<-a | filesystem|mountpoint>\n"));
+ case HELP_ALLOW:
+ return (gettext("\tallow <filesystem|volume>\n"
+ "\tallow [-ldug] "
+ "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n"
+ "\t <filesystem|volume>\n"
+ "\tallow [-ld] -e <perm|@setname>[,...] "
+ "<filesystem|volume>\n"
+ "\tallow -c <perm|@setname>[,...] <filesystem|volume>\n"
+ "\tallow -s @setname <perm|@setname>[,...] "
+ "<filesystem|volume>\n"));
+ case HELP_UNALLOW:
+ return (gettext("\tunallow [-rldug] "
+ "<\"everyone\"|user|group>[,...]\n"
+ "\t [<perm|@setname>[,...]] <filesystem|volume>\n"
+ "\tunallow [-rld] -e [<perm|@setname>[,...]] "
+ "<filesystem|volume>\n"
+ "\tunallow [-r] -c [<perm|@setname>[,...]] "
+ "<filesystem|volume>\n"
+ "\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
+ "<filesystem|volume>\n"));
+ case HELP_USERSPACE:
+ return (gettext("\tuserspace [-Hinp] [-o field[,...]] "
+ "[-s field] ...\n"
+ "\t [-S field] ... [-t type[,...]] "
+ "<filesystem|snapshot>\n"));
+ case HELP_GROUPSPACE:
+ return (gettext("\tgroupspace [-Hinp] [-o field[,...]] "
+ "[-s field] ...\n"
+ "\t [-S field] ... [-t type[,...]] "
+ "<filesystem|snapshot>\n"));
+ case HELP_HOLD:
+ return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
+ case HELP_HOLDS:
+ return (gettext("\tholds [-Hp] [-r|-d depth] "
+ "<filesystem|volume|snapshot> ...\n"));
+ case HELP_RELEASE:
+ return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
+ case HELP_DIFF:
+ return (gettext("\tdiff [-FHt] <snapshot> "
+ "[snapshot|filesystem]\n"));
+ case HELP_REMAP:
+ return (gettext("\tremap <filesystem | volume>\n"));
+ case HELP_BOOKMARK:
+ return (gettext("\tbookmark <snapshot> <bookmark>\n"));
+ case HELP_CHANNEL_PROGRAM:
+ return (gettext("\tprogram [-jn] [-t <instruction limit>] "
+ "[-m <memory limit (b)>] <pool> <program file> "
+ "[lua args...]\n"));
+ }
+
+ abort();
+ /* NOTREACHED */
+}
+
+void
+nomem(void)
+{
+ (void) fprintf(stderr, gettext("internal error: out of memory\n"));
+ exit(1);
+}
+
+/*
+ * Utility function to guarantee malloc() success.
+ */
+
+void *
+safe_malloc(size_t size)
+{
+ void *data;
+
+ if ((data = calloc(1, size)) == NULL)
+ nomem();
+
+ return (data);
+}
+
+void *
+safe_realloc(void *data, size_t size)
+{
+ void *newp;
+ if ((newp = realloc(data, size)) == NULL) {
+ free(data);
+ nomem();
+ }
+
+ return (newp);
+}
+
+static char *
+safe_strdup(char *str)
+{
+ char *dupstr = strdup(str);
+
+ if (dupstr == NULL)
+ nomem();
+
+ return (dupstr);
+}
+
+/*
+ * Callback routine that will print out information for each of
+ * the properties.
+ */
+static int
+usage_prop_cb(int prop, void *cb)
+{
+ FILE *fp = cb;
+
+ (void) fprintf(fp, "\t%-15s ", zfs_prop_to_name(prop));
+
+ if (zfs_prop_readonly(prop))
+ (void) fprintf(fp, " NO ");
+ else
+ (void) fprintf(fp, "YES ");
+
+ if (zfs_prop_inheritable(prop))
+ (void) fprintf(fp, " YES ");
+ else
+ (void) fprintf(fp, " NO ");
+
+ if (zfs_prop_values(prop) == NULL)
+ (void) fprintf(fp, "-\n");
+ else
+ (void) fprintf(fp, "%s\n", zfs_prop_values(prop));
+
+ return (ZPROP_CONT);
+}
+
+/*
+ * Display usage message. If we're inside a command, display only the usage for
+ * that command. Otherwise, iterate over the entire command table and display
+ * a complete usage message.
+ */
+static void
+usage(boolean_t requested)
+{
+ int i;
+ boolean_t show_properties = B_FALSE;
+ FILE *fp = requested ? stdout : stderr;
+
+ if (current_command == NULL) {
+
+ (void) fprintf(fp, gettext("usage: zfs command args ...\n"));
+ (void) fprintf(fp,
+ gettext("where 'command' is one of the following:\n\n"));
+
+ for (i = 0; i < NCOMMAND; i++) {
+ if (command_table[i].name == NULL)
+ (void) fprintf(fp, "\n");
+ else
+ (void) fprintf(fp, "%s",
+ get_usage(command_table[i].usage));
+ }
+
+ (void) fprintf(fp, gettext("\nEach dataset is of the form: "
+ "pool/[dataset/]*dataset[@name]\n"));
+ } else {
+ (void) fprintf(fp, gettext("usage:\n"));
+ (void) fprintf(fp, "%s", get_usage(current_command->usage));
+ }
+
+ if (current_command != NULL &&
+ (strcmp(current_command->name, "set") == 0 ||
+ strcmp(current_command->name, "get") == 0 ||
+ strcmp(current_command->name, "inherit") == 0 ||
+ strcmp(current_command->name, "list") == 0))
+ show_properties = B_TRUE;
+
+ if (show_properties) {
+ (void) fprintf(fp,
+ gettext("\nThe following properties are supported:\n"));
+
+ (void) fprintf(fp, "\n\t%-14s %s %s %s\n\n",
+ "PROPERTY", "EDIT", "INHERIT", "VALUES");
+
+ /* Iterate over all properties */
+ (void) zprop_iter(usage_prop_cb, fp, B_FALSE, B_TRUE,
+ ZFS_TYPE_DATASET);
+
+ (void) fprintf(fp, "\t%-15s ", "userused@...");
+ (void) fprintf(fp, " NO NO <size>\n");
+ (void) fprintf(fp, "\t%-15s ", "groupused@...");
+ (void) fprintf(fp, " NO NO <size>\n");
+ (void) fprintf(fp, "\t%-15s ", "userquota@...");
+ (void) fprintf(fp, "YES NO <size> | none\n");
+ (void) fprintf(fp, "\t%-15s ", "groupquota@...");
+ (void) fprintf(fp, "YES NO <size> | none\n");
+ (void) fprintf(fp, "\t%-15s ", "written@<snap>");
+ (void) fprintf(fp, " NO NO <size>\n");
+
+ (void) fprintf(fp, gettext("\nSizes are specified in bytes "
+ "with standard units such as K, M, G, etc.\n"));
+ (void) fprintf(fp, gettext("\nUser-defined properties can "
+ "be specified by using a name containing a colon (:).\n"));
+ (void) fprintf(fp, gettext("\nThe {user|group}{used|quota}@ "
+ "properties must be appended with\n"
+ "a user or group specifier of one of these forms:\n"
+ " POSIX name (eg: \"matt\")\n"
+ " POSIX id (eg: \"126829\")\n"
+ " SMB name@domain (eg: \"matt@sun\")\n"
+ " SMB SID (eg: \"S-1-234-567-89\")\n"));
+ } else {
+ (void) fprintf(fp,
+ gettext("\nFor the property list, run: %s\n"),
+ "zfs set|get");
+ (void) fprintf(fp,
+ gettext("\nFor the delegated permission list, run: %s\n"),
+ "zfs allow|unallow");
+ }
+
+ /*
+ * See comments at end of main().
+ */
+ if (getenv("ZFS_ABORT") != NULL) {
+ (void) printf("dumping core by request\n");
+ abort();
+ }
+
+ exit(requested ? 0 : 2);
+}
+
+/*
+ * Take a property=value argument string and add it to the given nvlist.
+ * Modifies the argument inplace.
+ */
+static int
+parseprop(nvlist_t *props, char *propname)
+{
+ char *propval, *strval;
+
+ if ((propval = strchr(propname, '=')) == NULL) {
+ (void) fprintf(stderr, gettext("missing "
+ "'=' for property=value argument\n"));
+ return (-1);
+ }
+ *propval = '\0';
+ propval++;
+ if (nvlist_lookup_string(props, propname, &strval) == 0) {
+ (void) fprintf(stderr, gettext("property '%s' "
+ "specified multiple times\n"), propname);
+ return (-1);
+ }
+ if (nvlist_add_string(props, propname, propval) != 0)
+ nomem();
+ return (0);
+}
+
+static int
+parse_depth(char *opt, int *flags)
+{
+ char *tmp;
+ int depth;
+
+ depth = (int)strtol(opt, &tmp, 0);
+ if (*tmp) {
+ (void) fprintf(stderr,
+ gettext("%s is not an integer\n"), opt);
+ usage(B_FALSE);
+ }
+ if (depth < 0) {
+ (void) fprintf(stderr,
+ gettext("Depth can not be negative.\n"));
+ usage(B_FALSE);
+ }
+ *flags |= (ZFS_ITER_DEPTH_LIMIT|ZFS_ITER_RECURSE);
+ return (depth);
+}
+
+#define PROGRESS_DELAY 2 /* seconds */
+
+static char *pt_reverse = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+static time_t pt_begin;
+static char *pt_header = NULL;
+static boolean_t pt_shown;
+
+static void
+start_progress_timer(void)
+{
+ pt_begin = time(NULL) + PROGRESS_DELAY;
+ pt_shown = B_FALSE;
+}
+
+static void
+set_progress_header(char *header)
+{
+ assert(pt_header == NULL);
+ pt_header = safe_strdup(header);
+ if (pt_shown) {
+ (void) printf("%s: ", header);
+ (void) fflush(stdout);
+ }
+}
+
+static void
+update_progress(char *update)
+{
+ if (!pt_shown && time(NULL) > pt_begin) {
+ int len = strlen(update);
+
+ (void) printf("%s: %s%*.*s", pt_header, update, len, len,
+ pt_reverse);
+ (void) fflush(stdout);
+ pt_shown = B_TRUE;
+ } else if (pt_shown) {
+ int len = strlen(update);
+
+ (void) printf("%s%*.*s", update, len, len, pt_reverse);
+ (void) fflush(stdout);
+ }
+}
+
+static void
+finish_progress(char *done)
+{
+ if (pt_shown) {
+ (void) printf("%s\n", done);
+ (void) fflush(stdout);
+ }
+ free(pt_header);
+ pt_header = NULL;
+}
+
+/*
+ * Check if the dataset is mountable and should be automatically mounted.
+ */
+static boolean_t
+should_auto_mount(zfs_handle_t *zhp)
+{
+ if (!zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, zfs_get_type(zhp)))
+ return (B_FALSE);
+ return (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON);
+}
+
+/*
+ * zfs clone [-p] [-o prop=value] ... <snap> <fs | vol>
+ *
+ * Given an existing dataset, create a writable copy whose initial contents
+ * are the same as the source. The newly created dataset maintains a
+ * dependency on the original; the original cannot be destroyed so long as
+ * the clone exists.
+ *
+ * The '-p' flag creates all the non-existing ancestors of the target first.
+ */
+static int
+zfs_do_clone(int argc, char **argv)
+{
+ zfs_handle_t *zhp = NULL;
+ boolean_t parents = B_FALSE;
+ nvlist_t *props;
+ int ret = 0;
+ int c;
+
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+
+ /* check options */
+ while ((c = getopt(argc, argv, "o:p")) != -1) {
+ switch (c) {
+ case 'o':
+ if (parseprop(props, optarg) != 0)
+ return (1);
+ break;
+ case 'p':
+ parents = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ goto usage;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing source dataset "
+ "argument\n"));
+ goto usage;
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing target dataset "
+ "argument\n"));
+ goto usage;
+ }
+ if (argc > 2) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ goto usage;
+ }
+
+ /* open the source dataset */
+ if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
+ return (1);
+
+ if (parents && zfs_name_valid(argv[1], ZFS_TYPE_FILESYSTEM |
+ ZFS_TYPE_VOLUME)) {
+ /*
+ * Now create the ancestors of the target dataset. If the
+ * target already exists and '-p' option was used we should not
+ * complain.
+ */
+ if (zfs_dataset_exists(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM |
+ ZFS_TYPE_VOLUME))
+ return (0);
+ if (zfs_create_ancestors(g_zfs, argv[1]) != 0)
+ return (1);
+ }
+
+ /* pass to libzfs */
+ ret = zfs_clone(zhp, argv[1], props);
+
+ /* create the mountpoint if necessary */
+ if (ret == 0) {
+ zfs_handle_t *clone;
+
+ clone = zfs_open(g_zfs, argv[1], ZFS_TYPE_DATASET);
+ if (clone != NULL) {
+ /*
+ * If the user doesn't want the dataset
+ * automatically mounted, then skip the mount/share
+ * step.
+ */
+ if (should_auto_mount(clone)) {
+ if ((ret = zfs_mount(clone, NULL, 0)) != 0) {
+ (void) fprintf(stderr, gettext("clone "
+ "successfully created, "
+ "but not mounted\n"));
+ } else if ((ret = zfs_share(clone)) != 0) {
+ (void) fprintf(stderr, gettext("clone "
+ "successfully created, "
+ "but not shared\n"));
+ }
+ }
+ zfs_close(clone);
+ }
+ }
+
+ zfs_close(zhp);
+ nvlist_free(props);
+
+ return (!!ret);
+
+usage:
+ if (zhp)
+ zfs_close(zhp);
+ nvlist_free(props);
+ usage(B_FALSE);
+ return (-1);
+}
+
+/*
+ * zfs create [-pu] [-o prop=value] ... fs
+ * zfs create [-ps] [-b blocksize] [-o prop=value] ... -V vol size
+ *
+ * Create a new dataset. This command can be used to create filesystems
+ * and volumes. Snapshot creation is handled by 'zfs snapshot'.
+ * For volumes, the user must specify a size to be used.
+ *
+ * The '-s' flag applies only to volumes, and indicates that we should not try
+ * to set the reservation for this volume. By default we set a reservation
+ * equal to the size for any volume. For pools with SPA_VERSION >=
+ * SPA_VERSION_REFRESERVATION, we set a refreservation instead.
+ *
+ * The '-p' flag creates all the non-existing ancestors of the target first.
+ *
+ * The '-u' flag prevents mounting of newly created file system.
+ */
+static int
+zfs_do_create(int argc, char **argv)
+{
+ zfs_type_t type = ZFS_TYPE_FILESYSTEM;
+ zfs_handle_t *zhp = NULL;
+ uint64_t volsize = 0;
+ int c;
+ boolean_t noreserve = B_FALSE;
+ boolean_t bflag = B_FALSE;
+ boolean_t parents = B_FALSE;
+ boolean_t nomount = B_FALSE;
+ int ret = 1;
+ nvlist_t *props;
+ uint64_t intval;
+
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+
+ /* check options */
+ while ((c = getopt(argc, argv, ":V:b:so:pu")) != -1) {
+ switch (c) {
+ case 'V':
+ type = ZFS_TYPE_VOLUME;
+ if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
+ (void) fprintf(stderr, gettext("bad volume "
+ "size '%s': %s\n"), optarg,
+ libzfs_error_description(g_zfs));
+ goto error;
+ }
+
+ if (nvlist_add_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE), intval) != 0)
+ nomem();
+ volsize = intval;
+ break;
+ case 'p':
+ parents = B_TRUE;
+ break;
+ case 'b':
+ bflag = B_TRUE;
+ if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
+ (void) fprintf(stderr, gettext("bad volume "
+ "block size '%s': %s\n"), optarg,
+ libzfs_error_description(g_zfs));
+ goto error;
+ }
+
+ if (nvlist_add_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ intval) != 0)
+ nomem();
+ break;
+ case 'o':
+ if (parseprop(props, optarg) != 0)
+ goto error;
+ break;
+ case 's':
+ noreserve = B_TRUE;
+ break;
+ case 'u':
+ nomount = B_TRUE;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing size "
+ "argument\n"));
+ goto badusage;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ goto badusage;
+ }
+ }
+
+ if ((bflag || noreserve) && type != ZFS_TYPE_VOLUME) {
+ (void) fprintf(stderr, gettext("'-s' and '-b' can only be "
+ "used when creating a volume\n"));
+ goto badusage;
+ }
+ if (nomount && type != ZFS_TYPE_FILESYSTEM) {
+ (void) fprintf(stderr, gettext("'-u' can only be "
+ "used when creating a file system\n"));
+ goto badusage;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc == 0) {
+ (void) fprintf(stderr, gettext("missing %s argument\n"),
+ zfs_type_to_name(type));
+ goto badusage;
+ }
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ goto badusage;
+ }
+
+ if (type == ZFS_TYPE_VOLUME && !noreserve) {
+ zpool_handle_t *zpool_handle;
+ nvlist_t *real_props = NULL;
+ uint64_t spa_version;
+ char *p;
+ zfs_prop_t resv_prop;
+ char *strval;
+ char msg[1024];
+
+ if ((p = strchr(argv[0], '/')) != NULL)
+ *p = '\0';
+ zpool_handle = zpool_open(g_zfs, argv[0]);
+ if (p != NULL)
+ *p = '/';
+ if (zpool_handle == NULL)
+ goto error;
+ spa_version = zpool_get_prop_int(zpool_handle,
+ ZPOOL_PROP_VERSION, NULL);
+ if (spa_version >= SPA_VERSION_REFRESERVATION)
+ resv_prop = ZFS_PROP_REFRESERVATION;
+ else
+ resv_prop = ZFS_PROP_RESERVATION;
+
+ (void) snprintf(msg, sizeof (msg),
+ gettext("cannot create '%s'"), argv[0]);
+ if (props && (real_props = zfs_valid_proplist(g_zfs, type,
+ props, 0, NULL, zpool_handle, msg)) == NULL) {
+ zpool_close(zpool_handle);
+ goto error;
+ }
+ zpool_close(zpool_handle);
+
+ volsize = zvol_volsize_to_reservation(volsize, real_props);
+ nvlist_free(real_props);
+
+ if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
+ &strval) != 0) {
+ if (nvlist_add_uint64(props,
+ zfs_prop_to_name(resv_prop), volsize) != 0) {
+ nvlist_free(props);
+ nomem();
+ }
+ }
+ }
+
+ if (parents && zfs_name_valid(argv[0], type)) {
+ /*
+ * Now create the ancestors of target dataset. If the target
+ * already exists and '-p' option was used we should not
+ * complain.
+ */
+ if (zfs_dataset_exists(g_zfs, argv[0], type)) {
+ ret = 0;
+ goto error;
+ }
+ if (zfs_create_ancestors(g_zfs, argv[0]) != 0)
+ goto error;
+ }
+
+ /* pass to libzfs */
+ if (zfs_create(g_zfs, argv[0], type, props) != 0)
+ goto error;
+
+ if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
+ goto error;
+
+ ret = 0;
+
+ /*
+ * Mount and/or share the new filesystem as appropriate. We provide a
+ * verbose error message to let the user know that their filesystem was
+ * in fact created, even if we failed to mount or share it.
+ * If the user doesn't want the dataset automatically mounted,
+ * then skip the mount/share step altogether.
+ */
+ if (!nomount && should_auto_mount(zhp)) {
+ if (zfs_mount(zhp, NULL, 0) != 0) {
+ (void) fprintf(stderr, gettext("filesystem "
+ "successfully created, but not mounted\n"));
+ ret = 1;
+ } else if (zfs_share(zhp) != 0) {
+ (void) fprintf(stderr, gettext("filesystem "
+ "successfully created, but not shared\n"));
+ ret = 1;
+ }
+ }
+
+error:
+ if (zhp)
+ zfs_close(zhp);
+ nvlist_free(props);
+ return (ret);
+badusage:
+ nvlist_free(props);
+ usage(B_FALSE);
+ return (2);
+}
+
+/*
+ * zfs destroy [-rRf] <fs, vol>
+ * zfs destroy [-rRd] <snap>
+ *
+ * -r Recursively destroy all children
+ * -R Recursively destroy all dependents, including clones
+ * -f Force unmounting of any dependents
+ * -d If we can't destroy now, mark for deferred destruction
+ *
+ * Destroys the given dataset. By default, it will unmount any filesystems,
+ * and refuse to destroy a dataset that has any dependents. A dependent can
+ * either be a child, or a clone of a child.
+ */
+typedef struct destroy_cbdata {
+ boolean_t cb_first;
+ boolean_t cb_force;
+ boolean_t cb_recurse;
+ boolean_t cb_error;
+ boolean_t cb_doclones;
+ zfs_handle_t *cb_target;
+ boolean_t cb_defer_destroy;
+ boolean_t cb_verbose;
+ boolean_t cb_parsable;
+ boolean_t cb_dryrun;
+ nvlist_t *cb_nvl;
+ nvlist_t *cb_batchedsnaps;
+
+ /* first snap in contiguous run */
+ char *cb_firstsnap;
+ /* previous snap in contiguous run */
+ char *cb_prevsnap;
+ int64_t cb_snapused;
+ char *cb_snapspec;
+ char *cb_bookmark;
+} destroy_cbdata_t;
+
+/*
+ * Check for any dependents based on the '-r' or '-R' flags.
+ */
+static int
+destroy_check_dependent(zfs_handle_t *zhp, void *data)
+{
+ destroy_cbdata_t *cbp = data;
+ const char *tname = zfs_get_name(cbp->cb_target);
+ const char *name = zfs_get_name(zhp);
+
+ if (strncmp(tname, name, strlen(tname)) == 0 &&
+ (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) {
+ /*
+ * This is a direct descendant, not a clone somewhere else in
+ * the hierarchy.
+ */
+ if (cbp->cb_recurse)
+ goto out;
+
+ if (cbp->cb_first) {
+ (void) fprintf(stderr, gettext("cannot destroy '%s': "
+ "%s has children\n"),
+ zfs_get_name(cbp->cb_target),
+ zfs_type_to_name(zfs_get_type(cbp->cb_target)));
+ (void) fprintf(stderr, gettext("use '-r' to destroy "
+ "the following datasets:\n"));
+ cbp->cb_first = B_FALSE;
+ cbp->cb_error = B_TRUE;
+ }
+
+ (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
+ } else {
+ /*
+ * This is a clone. We only want to report this if the '-r'
+ * wasn't specified, or the target is a snapshot.
+ */
+ if (!cbp->cb_recurse &&
+ zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT)
+ goto out;
+
+ if (cbp->cb_first) {
+ (void) fprintf(stderr, gettext("cannot destroy '%s': "
+ "%s has dependent clones\n"),
+ zfs_get_name(cbp->cb_target),
+ zfs_type_to_name(zfs_get_type(cbp->cb_target)));
+ (void) fprintf(stderr, gettext("use '-R' to destroy "
+ "the following datasets:\n"));
+ cbp->cb_first = B_FALSE;
+ cbp->cb_error = B_TRUE;
+ cbp->cb_dryrun = B_TRUE;
+ }
+
+ (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
+ }
+
+out:
+ zfs_close(zhp);
+ return (0);
+}
+
+static int
+destroy_callback(zfs_handle_t *zhp, void *data)
+{
+ destroy_cbdata_t *cb = data;
+ const char *name = zfs_get_name(zhp);
+
+ if (cb->cb_verbose) {
+ if (cb->cb_parsable) {
+ (void) printf("destroy\t%s\n", name);
+ } else if (cb->cb_dryrun) {
+ (void) printf(gettext("would destroy %s\n"),
+ name);
+ } else {
+ (void) printf(gettext("will destroy %s\n"),
+ name);
+ }
+ }
+
+ /*
+ * Ignore pools (which we've already flagged as an error before getting
+ * here).
+ */
+ if (strchr(zfs_get_name(zhp), '/') == NULL &&
+ zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
+ zfs_close(zhp);
+ return (0);
+ }
+ if (cb->cb_dryrun) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ /*
+ * We batch up all contiguous snapshots (even of different
+ * filesystems) and destroy them with one ioctl. We can't
+ * simply do all snap deletions and then all fs deletions,
+ * because we must delete a clone before its origin.
+ */
+ if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
+ fnvlist_add_boolean(cb->cb_batchedsnaps, name);
+ } else {
+ int error = zfs_destroy_snaps_nvl(g_zfs,
+ cb->cb_batchedsnaps, B_FALSE);
+ fnvlist_free(cb->cb_batchedsnaps);
+ cb->cb_batchedsnaps = fnvlist_alloc();
+
+ if (error != 0 ||
+ zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
+ zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
+ zfs_close(zhp);
+ return (-1);
+ }
+ }
+
+ zfs_close(zhp);
+ return (0);
+}
+
+static int
+destroy_print_cb(zfs_handle_t *zhp, void *arg)
+{
+ destroy_cbdata_t *cb = arg;
+ const char *name = zfs_get_name(zhp);
+ int err = 0;
+
+ if (nvlist_exists(cb->cb_nvl, name)) {
+ if (cb->cb_firstsnap == NULL)
+ cb->cb_firstsnap = strdup(name);
+ if (cb->cb_prevsnap != NULL)
+ free(cb->cb_prevsnap);
+ /* this snap continues the current range */
+ cb->cb_prevsnap = strdup(name);
+ if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
+ nomem();
+ if (cb->cb_verbose) {
+ if (cb->cb_parsable) {
+ (void) printf("destroy\t%s\n", name);
+ } else if (cb->cb_dryrun) {
+ (void) printf(gettext("would destroy %s\n"),
+ name);
+ } else {
+ (void) printf(gettext("will destroy %s\n"),
+ name);
+ }
+ }
+ } else if (cb->cb_firstsnap != NULL) {
+ /* end of this range */
+ uint64_t used = 0;
+ err = lzc_snaprange_space(cb->cb_firstsnap,
+ cb->cb_prevsnap, &used);
+ cb->cb_snapused += used;
+ free(cb->cb_firstsnap);
+ cb->cb_firstsnap = NULL;
+ free(cb->cb_prevsnap);
+ cb->cb_prevsnap = NULL;
+ }
+ zfs_close(zhp);
+ return (err);
+}
+
+static int
+destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
+{
+ int err = 0;
+ assert(cb->cb_firstsnap == NULL);
+ assert(cb->cb_prevsnap == NULL);
+ err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb, 0, 0);
+ if (cb->cb_firstsnap != NULL) {
+ uint64_t used = 0;
+ if (err == 0) {
+ err = lzc_snaprange_space(cb->cb_firstsnap,
+ cb->cb_prevsnap, &used);
+ }
+ cb->cb_snapused += used;
+ free(cb->cb_firstsnap);
+ cb->cb_firstsnap = NULL;
+ free(cb->cb_prevsnap);
+ cb->cb_prevsnap = NULL;
+ }
+ return (err);
+}
+
+static int
+snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
+{
+ destroy_cbdata_t *cb = arg;
+ int err = 0;
+
+ /* Check for clones. */
+ if (!cb->cb_doclones && !cb->cb_defer_destroy) {
+ cb->cb_target = zhp;
+ cb->cb_first = B_TRUE;
+ err = zfs_iter_dependents(zhp, B_TRUE,
+ destroy_check_dependent, cb);
+ }
+
+ if (err == 0) {
+ if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp)))
+ nomem();
+ }
+ zfs_close(zhp);
+ return (err);
+}
+
+static int
+gather_snapshots(zfs_handle_t *zhp, void *arg)
+{
+ destroy_cbdata_t *cb = arg;
+ int err = 0;
+
+ err = zfs_iter_snapspec(zhp, cb->cb_snapspec, snapshot_to_nvl_cb, cb);
+ if (err == ENOENT)
+ err = 0;
+ if (err != 0)
+ goto out;
+
+ if (cb->cb_verbose) {
+ err = destroy_print_snapshots(zhp, cb);
+ if (err != 0)
+ goto out;
+ }
+
+ if (cb->cb_recurse)
+ err = zfs_iter_filesystems(zhp, gather_snapshots, cb);
+
+out:
+ zfs_close(zhp);
+ return (err);
+}
+
+static int
+destroy_clones(destroy_cbdata_t *cb)
+{
+ nvpair_t *pair;
+ for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL);
+ pair != NULL;
+ pair = nvlist_next_nvpair(cb->cb_nvl, pair)) {
+ zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair),
+ ZFS_TYPE_SNAPSHOT);
+ if (zhp != NULL) {
+ boolean_t defer = cb->cb_defer_destroy;
+ int err = 0;
+
+ /*
+ * We can't defer destroy non-snapshots, so set it to
+ * false while destroying the clones.
+ */
+ cb->cb_defer_destroy = B_FALSE;
+ err = zfs_iter_dependents(zhp, B_FALSE,
+ destroy_callback, cb);
+ cb->cb_defer_destroy = defer;
+ zfs_close(zhp);
+ if (err != 0)
+ return (err);
+ }
+ }
+ return (0);
+}
+
+static int
+zfs_do_destroy(int argc, char **argv)
+{
+ destroy_cbdata_t cb = { 0 };
+ int rv = 0;
+ int err = 0;
+ int c;
+ zfs_handle_t *zhp = NULL;
+ char *at, *pound;
+ zfs_type_t type = ZFS_TYPE_DATASET;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "vpndfrR")) != -1) {
+ switch (c) {
+ case 'v':
+ cb.cb_verbose = B_TRUE;
+ break;
+ case 'p':
+ cb.cb_verbose = B_TRUE;
+ cb.cb_parsable = B_TRUE;
+ break;
+ case 'n':
+ cb.cb_dryrun = B_TRUE;
+ break;
+ case 'd':
+ cb.cb_defer_destroy = B_TRUE;
+ type = ZFS_TYPE_SNAPSHOT;
+ break;
+ case 'f':
+ cb.cb_force = B_TRUE;
+ break;
+ case 'r':
+ cb.cb_recurse = B_TRUE;
+ break;
+ case 'R':
+ cb.cb_recurse = B_TRUE;
+ cb.cb_doclones = B_TRUE;
+ break;
+ case '?':
+ default:
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc == 0) {
+ (void) fprintf(stderr, gettext("missing dataset argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ at = strchr(argv[0], '@');
+ pound = strchr(argv[0], '#');
+ if (at != NULL) {
+
+ /* Build the list of snaps to destroy in cb_nvl. */
+ cb.cb_nvl = fnvlist_alloc();
+
+ *at = '\0';
+ zhp = zfs_open(g_zfs, argv[0],
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ return (1);
+
+ cb.cb_snapspec = at + 1;
+ if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 ||
+ cb.cb_error) {
+ rv = 1;
+ goto out;
+ }
+
+ if (nvlist_empty(cb.cb_nvl)) {
+ (void) fprintf(stderr, gettext("could not find any "
+ "snapshots to destroy; check snapshot names.\n"));
+ rv = 1;
+ goto out;
+ }
+
+ if (cb.cb_verbose) {
+ char buf[16];
+ zfs_nicenum(cb.cb_snapused, buf, sizeof (buf));
+ if (cb.cb_parsable) {
+ (void) printf("reclaim\t%llu\n",
+ cb.cb_snapused);
+ } else if (cb.cb_dryrun) {
+ (void) printf(gettext("would reclaim %s\n"),
+ buf);
+ } else {
+ (void) printf(gettext("will reclaim %s\n"),
+ buf);
+ }
+ }
+
+ if (!cb.cb_dryrun) {
+ if (cb.cb_doclones) {
+ cb.cb_batchedsnaps = fnvlist_alloc();
+ err = destroy_clones(&cb);
+ if (err == 0) {
+ err = zfs_destroy_snaps_nvl(g_zfs,
+ cb.cb_batchedsnaps, B_FALSE);
+ }
+ if (err != 0) {
+ rv = 1;
+ goto out;
+ }
+ }
+ if (err == 0) {
+ err = zfs_destroy_snaps_nvl(g_zfs, cb.cb_nvl,
+ cb.cb_defer_destroy);
+ }
+ }
+
+ if (err != 0)
+ rv = 1;
+ } else if (pound != NULL) {
+ int err;
+ nvlist_t *nvl;
+
+ if (cb.cb_dryrun) {
+ (void) fprintf(stderr,
+ "dryrun is not supported with bookmark\n");
+ return (-1);
+ }
+
+ if (cb.cb_defer_destroy) {
+ (void) fprintf(stderr,
+ "defer destroy is not supported with bookmark\n");
+ return (-1);
+ }
+
+ if (cb.cb_recurse) {
+ (void) fprintf(stderr,
+ "recursive is not supported with bookmark\n");
+ return (-1);
+ }
+
+ if (!zfs_bookmark_exists(argv[0])) {
+ (void) fprintf(stderr, gettext("bookmark '%s' "
+ "does not exist.\n"), argv[0]);
+ return (1);
+ }
+
+ nvl = fnvlist_alloc();
+ fnvlist_add_boolean(nvl, argv[0]);
+
+ err = lzc_destroy_bookmarks(nvl, NULL);
+ if (err != 0) {
+ (void) zfs_standard_error(g_zfs, err,
+ "cannot destroy bookmark");
+ }
+
+ nvlist_free(cb.cb_nvl);
+
+ return (err);
+ } else {
+ /* Open the given dataset */
+ if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
+ return (1);
+
+ cb.cb_target = zhp;
+
+ /*
+ * Perform an explicit check for pools before going any further.
+ */
+ if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
+ zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
+ (void) fprintf(stderr, gettext("cannot destroy '%s': "
+ "operation does not apply to pools\n"),
+ zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use 'zfs destroy -r "
+ "%s' to destroy all datasets in the pool\n"),
+ zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use 'zpool destroy %s' "
+ "to destroy the pool itself\n"), zfs_get_name(zhp));
+ rv = 1;
+ goto out;
+ }
+
+ /*
+ * Check for any dependents and/or clones.
+ */
+ cb.cb_first = B_TRUE;
+ if (!cb.cb_doclones &&
+ zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
+ &cb) != 0) {
+ rv = 1;
+ goto out;
+ }
+
+ if (cb.cb_error) {
+ rv = 1;
+ goto out;
+ }
+
+ cb.cb_batchedsnaps = fnvlist_alloc();
+ if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
+ &cb) != 0) {
+ rv = 1;
+ goto out;
+ }
+
+ /*
+ * Do the real thing. The callback will close the
+ * handle regardless of whether it succeeds or not.
+ */
+ err = destroy_callback(zhp, &cb);
+ zhp = NULL;
+ if (err == 0) {
+ err = zfs_destroy_snaps_nvl(g_zfs,
+ cb.cb_batchedsnaps, cb.cb_defer_destroy);
+ }
+ if (err != 0)
+ rv = 1;
+ }
+
+out:
+ fnvlist_free(cb.cb_batchedsnaps);
+ fnvlist_free(cb.cb_nvl);
+ if (zhp != NULL)
+ zfs_close(zhp);
+ return (rv);
+}
+
+static boolean_t
+is_recvd_column(zprop_get_cbdata_t *cbp)
+{
+ int i;
+ zfs_get_column_t col;
+
+ for (i = 0; i < ZFS_GET_NCOLS &&
+ (col = cbp->cb_columns[i]) != GET_COL_NONE; i++)
+ if (col == GET_COL_RECVD)
+ return (B_TRUE);
+ return (B_FALSE);
+}
+
+/*
+ * zfs get [-rHp] [-o all | field[,field]...] [-s source[,source]...]
+ * < all | property[,property]... > < fs | snap | vol > ...
+ *
+ * -r recurse over any child datasets
+ * -H scripted mode. Headers are stripped, and fields are separated
+ * by tabs instead of spaces.
+ * -o Set of fields to display. One of "name,property,value,
+ * received,source". Default is "name,property,value,source".
+ * "all" is an alias for all five.
+ * -s Set of sources to allow. One of
+ * "local,default,inherited,received,temporary,none". Default is
+ * all six.
+ * -p Display values in parsable (literal) format.
+ *
+ * Prints properties for the given datasets. The user can control which
+ * columns to display as well as which property types to allow.
+ */
+
+/*
+ * Invoked to display the properties for a single dataset.
+ */
+static int
+get_callback(zfs_handle_t *zhp, void *data)
+{
+ char buf[ZFS_MAXPROPLEN];
+ char rbuf[ZFS_MAXPROPLEN];
+ zprop_source_t sourcetype;
+ char source[ZFS_MAX_DATASET_NAME_LEN];
+ zprop_get_cbdata_t *cbp = data;
+ nvlist_t *user_props = zfs_get_user_props(zhp);
+ zprop_list_t *pl = cbp->cb_proplist;
+ nvlist_t *propval;
+ char *strval;
+ char *sourceval;
+ boolean_t received = is_recvd_column(cbp);
+
+ for (; pl != NULL; pl = pl->pl_next) {
+ char *recvdval = NULL;
+ /*
+ * Skip the special fake placeholder. This will also skip over
+ * the name property when 'all' is specified.
+ */
+ if (pl->pl_prop == ZFS_PROP_NAME &&
+ pl == cbp->cb_proplist)
+ continue;
+
+ if (pl->pl_prop != ZPROP_INVAL) {
+ if (zfs_prop_get(zhp, pl->pl_prop, buf,
+ sizeof (buf), &sourcetype, source,
+ sizeof (source),
+ cbp->cb_literal) != 0) {
+ if (pl->pl_all)
+ continue;
+ if (!zfs_prop_valid_for_type(pl->pl_prop,
+ ZFS_TYPE_DATASET)) {
+ (void) fprintf(stderr,
+ gettext("No such property '%s'\n"),
+ zfs_prop_to_name(pl->pl_prop));
+ continue;
+ }
+ sourcetype = ZPROP_SRC_NONE;
+ (void) strlcpy(buf, "-", sizeof (buf));
+ }
+
+ if (received && (zfs_prop_get_recvd(zhp,
+ zfs_prop_to_name(pl->pl_prop), rbuf, sizeof (rbuf),
+ cbp->cb_literal) == 0))
+ recvdval = rbuf;
+
+ zprop_print_one_property(zfs_get_name(zhp), cbp,
+ zfs_prop_to_name(pl->pl_prop),
+ buf, sourcetype, source, recvdval);
+ } else if (zfs_prop_userquota(pl->pl_user_prop)) {
+ sourcetype = ZPROP_SRC_LOCAL;
+
+ if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
+ buf, sizeof (buf), cbp->cb_literal) != 0) {
+ sourcetype = ZPROP_SRC_NONE;
+ (void) strlcpy(buf, "-", sizeof (buf));
+ }
+
+ zprop_print_one_property(zfs_get_name(zhp), cbp,
+ pl->pl_user_prop, buf, sourcetype, source, NULL);
+ } else if (zfs_prop_written(pl->pl_user_prop)) {
+ sourcetype = ZPROP_SRC_LOCAL;
+
+ if (zfs_prop_get_written(zhp, pl->pl_user_prop,
+ buf, sizeof (buf), cbp->cb_literal) != 0) {
+ sourcetype = ZPROP_SRC_NONE;
+ (void) strlcpy(buf, "-", sizeof (buf));
+ }
+
+ zprop_print_one_property(zfs_get_name(zhp), cbp,
+ pl->pl_user_prop, buf, sourcetype, source, NULL);
+ } else {
+ if (nvlist_lookup_nvlist(user_props,
+ pl->pl_user_prop, &propval) != 0) {
+ if (pl->pl_all)
+ continue;
+ sourcetype = ZPROP_SRC_NONE;
+ strval = "-";
+ } else {
+ verify(nvlist_lookup_string(propval,
+ ZPROP_VALUE, &strval) == 0);
+ verify(nvlist_lookup_string(propval,
+ ZPROP_SOURCE, &sourceval) == 0);
+
+ if (strcmp(sourceval,
+ zfs_get_name(zhp)) == 0) {
+ sourcetype = ZPROP_SRC_LOCAL;
+ } else if (strcmp(sourceval,
+ ZPROP_SOURCE_VAL_RECVD) == 0) {
+ sourcetype = ZPROP_SRC_RECEIVED;
+ } else {
+ sourcetype = ZPROP_SRC_INHERITED;
+ (void) strlcpy(source,
+ sourceval, sizeof (source));
+ }
+ }
+
+ if (received && (zfs_prop_get_recvd(zhp,
+ pl->pl_user_prop, rbuf, sizeof (rbuf),
+ cbp->cb_literal) == 0))
+ recvdval = rbuf;
+
+ zprop_print_one_property(zfs_get_name(zhp), cbp,
+ pl->pl_user_prop, strval, sourcetype,
+ source, recvdval);
+ }
+ }
+
+ return (0);
+}
+
+static int
+zfs_do_get(int argc, char **argv)
+{
+ zprop_get_cbdata_t cb = { 0 };
+ int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
+ int types = ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK;
+ char *value, *fields;
+ int ret = 0;
+ int limit = 0;
+ zprop_list_t fake_name = { 0 };
+
+ /*
+ * Set up default columns and sources.
+ */
+ cb.cb_sources = ZPROP_SRC_ALL;
+ cb.cb_columns[0] = GET_COL_NAME;
+ cb.cb_columns[1] = GET_COL_PROPERTY;
+ cb.cb_columns[2] = GET_COL_VALUE;
+ cb.cb_columns[3] = GET_COL_SOURCE;
+ cb.cb_type = ZFS_TYPE_DATASET;
+
+ /* check options */
+ while ((c = getopt(argc, argv, ":d:o:s:rt:Hp")) != -1) {
+ switch (c) {
+ case 'p':
+ cb.cb_literal = B_TRUE;
+ break;
+ case 'd':
+ limit = parse_depth(optarg, &flags);
+ break;
+ case 'r':
+ flags |= ZFS_ITER_RECURSE;
+ break;
+ case 'H':
+ cb.cb_scripted = B_TRUE;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case 'o':
+ /*
+ * Process the set of columns to display. We zero out
+ * the structure to give us a blank slate.
+ */
+ bzero(&cb.cb_columns, sizeof (cb.cb_columns));
+ i = 0;
+ while (*optarg != '\0') {
+ static char *col_subopts[] =
+ { "name", "property", "value", "received",
+ "source", "all", NULL };
+
+ if (i == ZFS_GET_NCOLS) {
+ (void) fprintf(stderr, gettext("too "
+ "many fields given to -o "
+ "option\n"));
+ usage(B_FALSE);
+ }
+
+ switch (getsubopt(&optarg, col_subopts,
+ &value)) {
+ case 0:
+ cb.cb_columns[i++] = GET_COL_NAME;
+ break;
+ case 1:
+ cb.cb_columns[i++] = GET_COL_PROPERTY;
+ break;
+ case 2:
+ cb.cb_columns[i++] = GET_COL_VALUE;
+ break;
+ case 3:
+ cb.cb_columns[i++] = GET_COL_RECVD;
+ flags |= ZFS_ITER_RECVD_PROPS;
+ break;
+ case 4:
+ cb.cb_columns[i++] = GET_COL_SOURCE;
+ break;
+ case 5:
+ if (i > 0) {
+ (void) fprintf(stderr,
+ gettext("\"all\" conflicts "
+ "with specific fields "
+ "given to -o option\n"));
+ usage(B_FALSE);
+ }
+ cb.cb_columns[0] = GET_COL_NAME;
+ cb.cb_columns[1] = GET_COL_PROPERTY;
+ cb.cb_columns[2] = GET_COL_VALUE;
+ cb.cb_columns[3] = GET_COL_RECVD;
+ cb.cb_columns[4] = GET_COL_SOURCE;
+ flags |= ZFS_ITER_RECVD_PROPS;
+ i = ZFS_GET_NCOLS;
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("invalid column name "
+ "'%s'\n"), suboptarg);
+ usage(B_FALSE);
+ }
+ }
+ break;
+
+ case 's':
+ cb.cb_sources = 0;
+ while (*optarg != '\0') {
+ static char *source_subopts[] = {
+ "local", "default", "inherited",
+ "received", "temporary", "none",
+ NULL };
+
+ switch (getsubopt(&optarg, source_subopts,
+ &value)) {
+ case 0:
+ cb.cb_sources |= ZPROP_SRC_LOCAL;
+ break;
+ case 1:
+ cb.cb_sources |= ZPROP_SRC_DEFAULT;
+ break;
+ case 2:
+ cb.cb_sources |= ZPROP_SRC_INHERITED;
+ break;
+ case 3:
+ cb.cb_sources |= ZPROP_SRC_RECEIVED;
+ break;
+ case 4:
+ cb.cb_sources |= ZPROP_SRC_TEMPORARY;
+ break;
+ case 5:
+ cb.cb_sources |= ZPROP_SRC_NONE;
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("invalid source "
+ "'%s'\n"), suboptarg);
+ usage(B_FALSE);
+ }
+ }
+ break;
+
+ case 't':
+ types = 0;
+ flags &= ~ZFS_ITER_PROP_LISTSNAPS;
+ while (*optarg != '\0') {
+ static char *type_subopts[] = { "filesystem",
+ "volume", "snapshot", "bookmark",
+ "all", NULL };
+
+ switch (getsubopt(&optarg, type_subopts,
+ &value)) {
+ case 0:
+ types |= ZFS_TYPE_FILESYSTEM;
+ break;
+ case 1:
+ types |= ZFS_TYPE_VOLUME;
+ break;
+ case 2:
+ types |= ZFS_TYPE_SNAPSHOT;
+ break;
+ case 3:
+ types |= ZFS_TYPE_BOOKMARK;
+ break;
+ case 4:
+ types = ZFS_TYPE_DATASET |
+ ZFS_TYPE_BOOKMARK;
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ gettext("invalid type '%s'\n"),
+ suboptarg);
+ usage(B_FALSE);
+ }
+ }
+ break;
+
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing property "
+ "argument\n"));
+ usage(B_FALSE);
+ }
+
+ fields = argv[0];
+
+ if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
+ != 0)
+ usage(B_FALSE);
+
+ argc--;
+ argv++;
+
+ /*
+ * As part of zfs_expand_proplist(), we keep track of the maximum column
+ * width for each property. For the 'NAME' (and 'SOURCE') columns, we
+ * need to know the maximum name length. However, the user likely did
+ * not specify 'name' as one of the properties to fetch, so we need to
+ * make sure we always include at least this property for
+ * print_get_headers() to work properly.
+ */
+ if (cb.cb_proplist != NULL) {
+ fake_name.pl_prop = ZFS_PROP_NAME;
+ fake_name.pl_width = strlen(gettext("NAME"));
+ fake_name.pl_next = cb.cb_proplist;
+ cb.cb_proplist = &fake_name;
+ }
+
+ cb.cb_first = B_TRUE;
+
+ /* run for each object */
+ ret = zfs_for_each(argc, argv, flags, types, NULL,
+ &cb.cb_proplist, limit, get_callback, &cb);
+
+ if (cb.cb_proplist == &fake_name)
+ zprop_free_list(fake_name.pl_next);
+ else
+ zprop_free_list(cb.cb_proplist);
+
+ return (ret);
+}
+
+/*
+ * inherit [-rS] <property> <fs|vol> ...
+ *
+ * -r Recurse over all children
+ * -S Revert to received value, if any
+ *
+ * For each dataset specified on the command line, inherit the given property
+ * from its parent. Inheriting a property at the pool level will cause it to
+ * use the default value. The '-r' flag will recurse over all children, and is
+ * useful for setting a property on a hierarchy-wide basis, regardless of any
+ * local modifications for each dataset.
+ */
+
+typedef struct inherit_cbdata {
+ const char *cb_propname;
+ boolean_t cb_received;
+} inherit_cbdata_t;
+
+static int
+inherit_recurse_cb(zfs_handle_t *zhp, void *data)
+{
+ inherit_cbdata_t *cb = data;
+ zfs_prop_t prop = zfs_name_to_prop(cb->cb_propname);
+
+ /*
+ * If we're doing it recursively, then ignore properties that
+ * are not valid for this type of dataset.
+ */
+ if (prop != ZPROP_INVAL &&
+ !zfs_prop_valid_for_type(prop, zfs_get_type(zhp)))
+ return (0);
+
+ return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
+}
+
+static int
+inherit_cb(zfs_handle_t *zhp, void *data)
+{
+ inherit_cbdata_t *cb = data;
+
+ return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
+}
+
+static int
+zfs_do_inherit(int argc, char **argv)
+{
+ int c;
+ zfs_prop_t prop;
+ inherit_cbdata_t cb = { 0 };
+ char *propname;
+ int ret = 0;
+ int flags = 0;
+ boolean_t received = B_FALSE;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "rS")) != -1) {
+ switch (c) {
+ case 'r':
+ flags |= ZFS_ITER_RECURSE;
+ break;
+ case 'S':
+ received = B_TRUE;
+ break;
+ case '?':
+ default:
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing property argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing dataset argument\n"));
+ usage(B_FALSE);
+ }
+
+ propname = argv[0];
+ argc--;
+ argv++;
+
+ if ((prop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
+ if (zfs_prop_readonly(prop)) {
+ (void) fprintf(stderr, gettext(
+ "%s property is read-only\n"),
+ propname);
+ return (1);
+ }
+ if (!zfs_prop_inheritable(prop) && !received) {
+ (void) fprintf(stderr, gettext("'%s' property cannot "
+ "be inherited\n"), propname);
+ if (prop == ZFS_PROP_QUOTA ||
+ prop == ZFS_PROP_RESERVATION ||
+ prop == ZFS_PROP_REFQUOTA ||
+ prop == ZFS_PROP_REFRESERVATION) {
+ (void) fprintf(stderr, gettext("use 'zfs set "
+ "%s=none' to clear\n"), propname);
+ (void) fprintf(stderr, gettext("use 'zfs "
+ "inherit -S %s' to revert to received "
+ "value\n"), propname);
+ }
+ return (1);
+ }
+ if (received && (prop == ZFS_PROP_VOLSIZE ||
+ prop == ZFS_PROP_VERSION)) {
+ (void) fprintf(stderr, gettext("'%s' property cannot "
+ "be reverted to a received value\n"), propname);
+ return (1);
+ }
+ } else if (!zfs_prop_user(propname)) {
+ (void) fprintf(stderr, gettext("invalid property '%s'\n"),
+ propname);
+ usage(B_FALSE);
+ }
+
+ cb.cb_propname = propname;
+ cb.cb_received = received;
+
+ if (flags & ZFS_ITER_RECURSE) {
+ ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
+ NULL, NULL, 0, inherit_recurse_cb, &cb);
+ } else {
+ ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
+ NULL, NULL, 0, inherit_cb, &cb);
+ }
+
+ return (ret);
+}
+
+typedef struct upgrade_cbdata {
+ uint64_t cb_numupgraded;
+ uint64_t cb_numsamegraded;
+ uint64_t cb_numfailed;
+ uint64_t cb_version;
+ boolean_t cb_newer;
+ boolean_t cb_foundone;
+ char cb_lastfs[ZFS_MAX_DATASET_NAME_LEN];
+} upgrade_cbdata_t;
+
+static int
+same_pool(zfs_handle_t *zhp, const char *name)
+{
+ int len1 = strcspn(name, "/@");
+ const char *zhname = zfs_get_name(zhp);
+ int len2 = strcspn(zhname, "/@");
+
+ if (len1 != len2)
+ return (B_FALSE);
+ return (strncmp(name, zhname, len1) == 0);
+}
+
+static int
+upgrade_list_callback(zfs_handle_t *zhp, void *data)
+{
+ upgrade_cbdata_t *cb = data;
+ int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+
+ /* list if it's old/new */
+ if ((!cb->cb_newer && version < ZPL_VERSION) ||
+ (cb->cb_newer && version > ZPL_VERSION)) {
+ char *str;
+ if (cb->cb_newer) {
+ str = gettext("The following filesystems are "
+ "formatted using a newer software version and\n"
+ "cannot be accessed on the current system.\n\n");
+ } else {
+ str = gettext("The following filesystems are "
+ "out of date, and can be upgraded. After being\n"
+ "upgraded, these filesystems (and any 'zfs send' "
+ "streams generated from\n"
+ "subsequent snapshots) will no longer be "
+ "accessible by older software versions.\n\n");
+ }
+
+ if (!cb->cb_foundone) {
+ (void) puts(str);
+ (void) printf(gettext("VER FILESYSTEM\n"));
+ (void) printf(gettext("--- ------------\n"));
+ cb->cb_foundone = B_TRUE;
+ }
+
+ (void) printf("%2u %s\n", version, zfs_get_name(zhp));
+ }
+
+ return (0);
+}
+
+static int
+upgrade_set_callback(zfs_handle_t *zhp, void *data)
+{
+ upgrade_cbdata_t *cb = data;
+ int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+ int needed_spa_version;
+ int spa_version;
+
+ if (zfs_spa_version(zhp, &spa_version) < 0)
+ return (-1);
+
+ needed_spa_version = zfs_spa_version_map(cb->cb_version);
+
+ if (needed_spa_version < 0)
+ return (-1);
+
+ if (spa_version < needed_spa_version) {
+ /* can't upgrade */
+ (void) printf(gettext("%s: can not be "
+ "upgraded; the pool version needs to first "
+ "be upgraded\nto version %d\n\n"),
+ zfs_get_name(zhp), needed_spa_version);
+ cb->cb_numfailed++;
+ return (0);
+ }
+
+ /* upgrade */
+ if (version < cb->cb_version) {
+ char verstr[16];
+ (void) snprintf(verstr, sizeof (verstr),
+ "%llu", cb->cb_version);
+ if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
+ /*
+ * If they did "zfs upgrade -a", then we could
+ * be doing ioctls to different pools. We need
+ * to log this history once to each pool, and bypass
+ * the normal history logging that happens in main().
+ */
+ (void) zpool_log_history(g_zfs, history_str);
+ log_history = B_FALSE;
+ }
+ if (zfs_prop_set(zhp, "version", verstr) == 0)
+ cb->cb_numupgraded++;
+ else
+ cb->cb_numfailed++;
+ (void) strcpy(cb->cb_lastfs, zfs_get_name(zhp));
+ } else if (version > cb->cb_version) {
+ /* can't downgrade */
+ (void) printf(gettext("%s: can not be downgraded; "
+ "it is already at version %u\n"),
+ zfs_get_name(zhp), version);
+ cb->cb_numfailed++;
+ } else {
+ cb->cb_numsamegraded++;
+ }
+ return (0);
+}
+
+/*
+ * zfs upgrade
+ * zfs upgrade -v
+ * zfs upgrade [-r] [-V <version>] <-a | filesystem>
+ */
+static int
+zfs_do_upgrade(int argc, char **argv)
+{
+ boolean_t all = B_FALSE;
+ boolean_t showversions = B_FALSE;
+ int ret = 0;
+ upgrade_cbdata_t cb = { 0 };
+ int c;
+ int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "rvV:a")) != -1) {
+ switch (c) {
+ case 'r':
+ flags |= ZFS_ITER_RECURSE;
+ break;
+ case 'v':
+ showversions = B_TRUE;
+ break;
+ case 'V':
+ if (zfs_prop_string_to_index(ZFS_PROP_VERSION,
+ optarg, &cb.cb_version) != 0) {
+ (void) fprintf(stderr,
+ gettext("invalid version %s\n"), optarg);
+ usage(B_FALSE);
+ }
+ break;
+ case 'a':
+ all = B_TRUE;
+ break;
+ case '?':
+ default:
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if ((!all && !argc) && ((flags & ZFS_ITER_RECURSE) | cb.cb_version))
+ usage(B_FALSE);
+ if (showversions && (flags & ZFS_ITER_RECURSE || all ||
+ cb.cb_version || argc))
+ usage(B_FALSE);
+ if ((all || argc) && (showversions))
+ usage(B_FALSE);
+ if (all && argc)
+ usage(B_FALSE);
+
+ if (showversions) {
+ /* Show info on available versions. */
+ (void) printf(gettext("The following filesystem versions are "
+ "supported:\n\n"));
+ (void) printf(gettext("VER DESCRIPTION\n"));
+ (void) printf("--- -----------------------------------------"
+ "---------------\n");
+ (void) printf(gettext(" 1 Initial ZFS filesystem version\n"));
+ (void) printf(gettext(" 2 Enhanced directory entries\n"));
+ (void) printf(gettext(" 3 Case insensitive and filesystem "
+ "user identifier (FUID)\n"));
+ (void) printf(gettext(" 4 userquota, groupquota "
+ "properties\n"));
+ (void) printf(gettext(" 5 System attributes\n"));
+ (void) printf(gettext("\nFor more information on a particular "
+ "version, including supported releases,\n"));
+ (void) printf("see the ZFS Administration Guide.\n\n");
+ ret = 0;
+ } else if (argc || all) {
+ /* Upgrade filesystems */
+ if (cb.cb_version == 0)
+ cb.cb_version = ZPL_VERSION;
+ ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_FILESYSTEM,
+ NULL, NULL, 0, upgrade_set_callback, &cb);
+ (void) printf(gettext("%llu filesystems upgraded\n"),
+ cb.cb_numupgraded);
+ if (cb.cb_numsamegraded) {
+ (void) printf(gettext("%llu filesystems already at "
+ "this version\n"),
+ cb.cb_numsamegraded);
+ }
+ if (cb.cb_numfailed != 0)
+ ret = 1;
+ } else {
+ /* List old-version filesystems */
+ boolean_t found;
+ (void) printf(gettext("This system is currently running "
+ "ZFS filesystem version %llu.\n\n"), ZPL_VERSION);
+
+ flags |= ZFS_ITER_RECURSE;
+ ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
+ NULL, NULL, 0, upgrade_list_callback, &cb);
+
+ found = cb.cb_foundone;
+ cb.cb_foundone = B_FALSE;
+ cb.cb_newer = B_TRUE;
+
+ ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
+ NULL, NULL, 0, upgrade_list_callback, &cb);
+
+ if (!cb.cb_foundone && !found) {
+ (void) printf(gettext("All filesystems are "
+ "formatted with the current version.\n"));
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * zfs userspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
+ * [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
+ * zfs groupspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
+ * [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
+ *
+ * -H Scripted mode; elide headers and separate columns by tabs.
+ * -i Translate SID to POSIX ID.
+ * -n Print numeric ID instead of user/group name.
+ * -o Control which fields to display.
+ * -p Use exact (parsable) numeric output.
+ * -s Specify sort columns, descending order.
+ * -S Specify sort columns, ascending order.
+ * -t Control which object types to display.
+ *
+ * Displays space consumed by, and quotas on, each user in the specified
+ * filesystem or snapshot.
+ */
+
+/* us_field_types, us_field_hdr and us_field_names should be kept in sync */
+enum us_field_types {
+ USFIELD_TYPE,
+ USFIELD_NAME,
+ USFIELD_USED,
+ USFIELD_QUOTA
+};
+static char *us_field_hdr[] = { "TYPE", "NAME", "USED", "QUOTA" };
+static char *us_field_names[] = { "type", "name", "used", "quota" };
+#define USFIELD_LAST (sizeof (us_field_names) / sizeof (char *))
+
+#define USTYPE_PSX_GRP (1 << 0)
+#define USTYPE_PSX_USR (1 << 1)
+#define USTYPE_SMB_GRP (1 << 2)
+#define USTYPE_SMB_USR (1 << 3)
+#define USTYPE_ALL \
+ (USTYPE_PSX_GRP | USTYPE_PSX_USR | USTYPE_SMB_GRP | USTYPE_SMB_USR)
+
+static int us_type_bits[] = {
+ USTYPE_PSX_GRP,
+ USTYPE_PSX_USR,
+ USTYPE_SMB_GRP,
+ USTYPE_SMB_USR,
+ USTYPE_ALL
+};
+static char *us_type_names[] = { "posixgroup", "posixuser", "smbgroup",
+ "smbuser", "all" };
+
+typedef struct us_node {
+ nvlist_t *usn_nvl;
+ uu_avl_node_t usn_avlnode;
+ uu_list_node_t usn_listnode;
+} us_node_t;
+
+typedef struct us_cbdata {
+ nvlist_t **cb_nvlp;
+ uu_avl_pool_t *cb_avl_pool;
+ uu_avl_t *cb_avl;
+ boolean_t cb_numname;
+ boolean_t cb_nicenum;
+ boolean_t cb_sid2posix;
+ zfs_userquota_prop_t cb_prop;
+ zfs_sort_column_t *cb_sortcol;
+ size_t cb_width[USFIELD_LAST];
+} us_cbdata_t;
+
+static boolean_t us_populated = B_FALSE;
+
+typedef struct {
+ zfs_sort_column_t *si_sortcol;
+ boolean_t si_numname;
+} us_sort_info_t;
+
+static int
+us_field_index(char *field)
+{
+ int i;
+
+ for (i = 0; i < USFIELD_LAST; i++) {
+ if (strcmp(field, us_field_names[i]) == 0)
+ return (i);
+ }
+
+ return (-1);
+}
+
+static int
+us_compare(const void *larg, const void *rarg, void *unused)
+{
+ const us_node_t *l = larg;
+ const us_node_t *r = rarg;
+ us_sort_info_t *si = (us_sort_info_t *)unused;
+ zfs_sort_column_t *sortcol = si->si_sortcol;
+ boolean_t numname = si->si_numname;
+ nvlist_t *lnvl = l->usn_nvl;
+ nvlist_t *rnvl = r->usn_nvl;
+ int rc = 0;
+ boolean_t lvb, rvb;
+
+ for (; sortcol != NULL; sortcol = sortcol->sc_next) {
+ char *lvstr = "";
+ char *rvstr = "";
+ uint32_t lv32 = 0;
+ uint32_t rv32 = 0;
+ uint64_t lv64 = 0;
+ uint64_t rv64 = 0;
+ zfs_prop_t prop = sortcol->sc_prop;
+ const char *propname = NULL;
+ boolean_t reverse = sortcol->sc_reverse;
+
+ switch (prop) {
+ case ZFS_PROP_TYPE:
+ propname = "type";
+ (void) nvlist_lookup_uint32(lnvl, propname, &lv32);
+ (void) nvlist_lookup_uint32(rnvl, propname, &rv32);
+ if (rv32 != lv32)
+ rc = (rv32 < lv32) ? 1 : -1;
+ break;
+ case ZFS_PROP_NAME:
+ propname = "name";
+ if (numname) {
+compare_nums:
+ (void) nvlist_lookup_uint64(lnvl, propname,
+ &lv64);
+ (void) nvlist_lookup_uint64(rnvl, propname,
+ &rv64);
+ if (rv64 != lv64)
+ rc = (rv64 < lv64) ? 1 : -1;
+ } else {
+ if ((nvlist_lookup_string(lnvl, propname,
+ &lvstr) == ENOENT) ||
+ (nvlist_lookup_string(rnvl, propname,
+ &rvstr) == ENOENT)) {
+ goto compare_nums;
+ }
+ rc = strcmp(lvstr, rvstr);
+ }
+ break;
+ case ZFS_PROP_USED:
+ case ZFS_PROP_QUOTA:
+ if (!us_populated)
+ break;
+ if (prop == ZFS_PROP_USED)
+ propname = "used";
+ else
+ propname = "quota";
+ (void) nvlist_lookup_uint64(lnvl, propname, &lv64);
+ (void) nvlist_lookup_uint64(rnvl, propname, &rv64);
+ if (rv64 != lv64)
+ rc = (rv64 < lv64) ? 1 : -1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (rc != 0) {
+ if (rc < 0)
+ return (reverse ? 1 : -1);
+ else
+ return (reverse ? -1 : 1);
+ }
+ }
+
+ /*
+ * If entries still seem to be the same, check if they are of the same
+ * type (smbentity is added only if we are doing SID to POSIX ID
+ * translation where we can have duplicate type/name combinations).
+ */
+ if (nvlist_lookup_boolean_value(lnvl, "smbentity", &lvb) == 0 &&
+ nvlist_lookup_boolean_value(rnvl, "smbentity", &rvb) == 0 &&
+ lvb != rvb)
+ return (lvb < rvb ? -1 : 1);
+
+ return (0);
+}
+
+static inline const char *
+us_type2str(unsigned field_type)
+{
+ switch (field_type) {
+ case USTYPE_PSX_USR:
+ return ("POSIX User");
+ case USTYPE_PSX_GRP:
+ return ("POSIX Group");
+ case USTYPE_SMB_USR:
+ return ("SMB User");
+ case USTYPE_SMB_GRP:
+ return ("SMB Group");
+ default:
+ return ("Undefined");
+ }
+}
+
+static int
+userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
+{
+ us_cbdata_t *cb = (us_cbdata_t *)arg;
+ zfs_userquota_prop_t prop = cb->cb_prop;
+ char *name = NULL;
+ char *propname;
+ char sizebuf[32];
+ us_node_t *node;
+ uu_avl_pool_t *avl_pool = cb->cb_avl_pool;
+ uu_avl_t *avl = cb->cb_avl;
+ uu_avl_index_t idx;
+ nvlist_t *props;
+ us_node_t *n;
+ zfs_sort_column_t *sortcol = cb->cb_sortcol;
+ unsigned type = 0;
+ const char *typestr;
+ size_t namelen;
+ size_t typelen;
+ size_t sizelen;
+ int typeidx, nameidx, sizeidx;
+ us_sort_info_t sortinfo = { sortcol, cb->cb_numname };
+ boolean_t smbentity = B_FALSE;
+
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+ node = safe_malloc(sizeof (us_node_t));
+ uu_avl_node_init(node, &node->usn_avlnode, avl_pool);
+ node->usn_nvl = props;
+
+ if (domain != NULL && domain[0] != '\0') {
+ /* SMB */
+ char sid[MAXNAMELEN + 32];
+ uid_t id;
+#ifdef illumos
+ int err;
+ int flag = IDMAP_REQ_FLG_USE_CACHE;
+#endif
+
+ smbentity = B_TRUE;
+
+ (void) snprintf(sid, sizeof (sid), "%s-%u", domain, rid);
+
+ if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
+ type = USTYPE_SMB_GRP;
+#ifdef illumos
+ err = sid_to_id(sid, B_FALSE, &id);
+#endif
+ } else {
+ type = USTYPE_SMB_USR;
+#ifdef illumos
+ err = sid_to_id(sid, B_TRUE, &id);
+#endif
+ }
+
+#ifdef illumos
+ if (err == 0) {
+ rid = id;
+ if (!cb->cb_sid2posix) {
+ if (type == USTYPE_SMB_USR) {
+ (void) idmap_getwinnamebyuid(rid, flag,
+ &name, NULL);
+ } else {
+ (void) idmap_getwinnamebygid(rid, flag,
+ &name, NULL);
+ }
+ if (name == NULL)
+ name = sid;
+ }
+ }
+#endif
+ }
+
+ if (cb->cb_sid2posix || domain == NULL || domain[0] == '\0') {
+ /* POSIX or -i */
+ if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
+ type = USTYPE_PSX_GRP;
+ if (!cb->cb_numname) {
+ struct group *g;
+
+ if ((g = getgrgid(rid)) != NULL)
+ name = g->gr_name;
+ }
+ } else {
+ type = USTYPE_PSX_USR;
+ if (!cb->cb_numname) {
+ struct passwd *p;
+
+ if ((p = getpwuid(rid)) != NULL)
+ name = p->pw_name;
+ }
+ }
+ }
+
+ /*
+ * Make sure that the type/name combination is unique when doing
+ * SID to POSIX ID translation (hence changing the type from SMB to
+ * POSIX).
+ */
+ if (cb->cb_sid2posix &&
+ nvlist_add_boolean_value(props, "smbentity", smbentity) != 0)
+ nomem();
+
+ /* Calculate/update width of TYPE field */
+ typestr = us_type2str(type);
+ typelen = strlen(gettext(typestr));
+ typeidx = us_field_index("type");
+ if (typelen > cb->cb_width[typeidx])
+ cb->cb_width[typeidx] = typelen;
+ if (nvlist_add_uint32(props, "type", type) != 0)
+ nomem();
+
+ /* Calculate/update width of NAME field */
+ if ((cb->cb_numname && cb->cb_sid2posix) || name == NULL) {
+ if (nvlist_add_uint64(props, "name", rid) != 0)
+ nomem();
+ namelen = snprintf(NULL, 0, "%u", rid);
+ } else {
+ if (nvlist_add_string(props, "name", name) != 0)
+ nomem();
+ namelen = strlen(name);
+ }
+ nameidx = us_field_index("name");
+ if (namelen > cb->cb_width[nameidx])
+ cb->cb_width[nameidx] = namelen;
+
+ /*
+ * Check if this type/name combination is in the list and update it;
+ * otherwise add new node to the list.
+ */
+ if ((n = uu_avl_find(avl, node, &sortinfo, &idx)) == NULL) {
+ uu_avl_insert(avl, node, idx);
+ } else {
+ nvlist_free(props);
+ free(node);
+ node = n;
+ props = node->usn_nvl;
+ }
+
+ /* Calculate/update width of USED/QUOTA fields */
+ if (cb->cb_nicenum)
+ zfs_nicenum(space, sizebuf, sizeof (sizebuf));
+ else
+ (void) snprintf(sizebuf, sizeof (sizebuf), "%llu", space);
+ sizelen = strlen(sizebuf);
+ if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED) {
+ propname = "used";
+ if (!nvlist_exists(props, "quota"))
+ (void) nvlist_add_uint64(props, "quota", 0);
+ } else {
+ propname = "quota";
+ if (!nvlist_exists(props, "used"))
+ (void) nvlist_add_uint64(props, "used", 0);
+ }
+ sizeidx = us_field_index(propname);
+ if (sizelen > cb->cb_width[sizeidx])
+ cb->cb_width[sizeidx] = sizelen;
+
+ if (nvlist_add_uint64(props, propname, space) != 0)
+ nomem();
+
+ return (0);
+}
+
+static void
+print_us_node(boolean_t scripted, boolean_t parsable, int *fields, int types,
+ size_t *width, us_node_t *node)
+{
+ nvlist_t *nvl = node->usn_nvl;
+ char valstr[MAXNAMELEN];
+ boolean_t first = B_TRUE;
+ int cfield = 0;
+ int field;
+ uint32_t ustype;
+
+ /* Check type */
+ (void) nvlist_lookup_uint32(nvl, "type", &ustype);
+ if (!(ustype & types))
+ return;
+
+ while ((field = fields[cfield]) != USFIELD_LAST) {
+ nvpair_t *nvp = NULL;
+ data_type_t type;
+ uint32_t val32;
+ uint64_t val64;
+ char *strval = NULL;
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ if (strcmp(nvpair_name(nvp),
+ us_field_names[field]) == 0)
+ break;
+ }
+
+ type = nvpair_type(nvp);
+ switch (type) {
+ case DATA_TYPE_UINT32:
+ (void) nvpair_value_uint32(nvp, &val32);
+ break;
+ case DATA_TYPE_UINT64:
+ (void) nvpair_value_uint64(nvp, &val64);
+ break;
+ case DATA_TYPE_STRING:
+ (void) nvpair_value_string(nvp, &strval);
+ break;
+ default:
+ (void) fprintf(stderr, "invalid data type\n");
+ }
+
+ switch (field) {
+ case USFIELD_TYPE:
+ strval = (char *)us_type2str(val32);
+ break;
+ case USFIELD_NAME:
+ if (type == DATA_TYPE_UINT64) {
+ (void) sprintf(valstr, "%llu", val64);
+ strval = valstr;
+ }
+ break;
+ case USFIELD_USED:
+ case USFIELD_QUOTA:
+ if (type == DATA_TYPE_UINT64) {
+ if (parsable) {
+ (void) sprintf(valstr, "%llu", val64);
+ } else {
+ zfs_nicenum(val64, valstr,
+ sizeof (valstr));
+ }
+ if (field == USFIELD_QUOTA &&
+ strcmp(valstr, "0") == 0)
+ strval = "none";
+ else
+ strval = valstr;
+ }
+ break;
+ }
+
+ if (!first) {
+ if (scripted)
+ (void) printf("\t");
+ else
+ (void) printf(" ");
+ }
+ if (scripted)
+ (void) printf("%s", strval);
+ else if (field == USFIELD_TYPE || field == USFIELD_NAME)
+ (void) printf("%-*s", width[field], strval);
+ else
+ (void) printf("%*s", width[field], strval);
+
+ first = B_FALSE;
+ cfield++;
+ }
+
+ (void) printf("\n");
+}
+
+static void
+print_us(boolean_t scripted, boolean_t parsable, int *fields, int types,
+ size_t *width, boolean_t rmnode, uu_avl_t *avl)
+{
+ us_node_t *node;
+ const char *col;
+ int cfield = 0;
+ int field;
+
+ if (!scripted) {
+ boolean_t first = B_TRUE;
+
+ while ((field = fields[cfield]) != USFIELD_LAST) {
+ col = gettext(us_field_hdr[field]);
+ if (field == USFIELD_TYPE || field == USFIELD_NAME) {
+ (void) printf(first ? "%-*s" : " %-*s",
+ width[field], col);
+ } else {
+ (void) printf(first ? "%*s" : " %*s",
+ width[field], col);
+ }
+ first = B_FALSE;
+ cfield++;
+ }
+ (void) printf("\n");
+ }
+
+ for (node = uu_avl_first(avl); node; node = uu_avl_next(avl, node)) {
+ print_us_node(scripted, parsable, fields, types, width, node);
+ if (rmnode)
+ nvlist_free(node->usn_nvl);
+ }
+}
+
+static int
+zfs_do_userspace(int argc, char **argv)
+{
+ zfs_handle_t *zhp;
+ zfs_userquota_prop_t p;
+
+ uu_avl_pool_t *avl_pool;
+ uu_avl_t *avl_tree;
+ uu_avl_walk_t *walk;
+ char *delim;
+ char deffields[] = "type,name,used,quota";
+ char *ofield = NULL;
+ char *tfield = NULL;
+ int cfield = 0;
+ int fields[256];
+ int i;
+ boolean_t scripted = B_FALSE;
+ boolean_t prtnum = B_FALSE;
+ boolean_t parsable = B_FALSE;
+ boolean_t sid2posix = B_FALSE;
+ int ret = 0;
+ int c;
+ zfs_sort_column_t *sortcol = NULL;
+ int types = USTYPE_PSX_USR | USTYPE_SMB_USR;
+ us_cbdata_t cb;
+ us_node_t *node;
+ us_node_t *rmnode;
+ uu_list_pool_t *listpool;
+ uu_list_t *list;
+ uu_avl_index_t idx = 0;
+ uu_list_index_t idx2 = 0;
+
+ if (argc < 2)
+ usage(B_FALSE);
+
+ if (strcmp(argv[0], "groupspace") == 0)
+ /* Toggle default group types */
+ types = USTYPE_PSX_GRP | USTYPE_SMB_GRP;
+
+ while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) {
+ switch (c) {
+ case 'n':
+ prtnum = B_TRUE;
+ break;
+ case 'H':
+ scripted = B_TRUE;
+ break;
+ case 'p':
+ parsable = B_TRUE;
+ break;
+ case 'o':
+ ofield = optarg;
+ break;
+ case 's':
+ case 'S':
+ if (zfs_add_sort_column(&sortcol, optarg,
+ c == 's' ? B_FALSE : B_TRUE) != 0) {
+ (void) fprintf(stderr,
+ gettext("invalid field '%s'\n"), optarg);
+ usage(B_FALSE);
+ }
+ break;
+ case 't':
+ tfield = optarg;
+ break;
+ case 'i':
+ sid2posix = B_TRUE;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing dataset name\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ /* Use default output fields if not specified using -o */
+ if (ofield == NULL)
+ ofield = deffields;
+ do {
+ if ((delim = strchr(ofield, ',')) != NULL)
+ *delim = '\0';
+ if ((fields[cfield++] = us_field_index(ofield)) == -1) {
+ (void) fprintf(stderr, gettext("invalid type '%s' "
+ "for -o option\n"), ofield);
+ return (-1);
+ }
+ if (delim != NULL)
+ ofield = delim + 1;
+ } while (delim != NULL);
+ fields[cfield] = USFIELD_LAST;
+
+ /* Override output types (-t option) */
+ if (tfield != NULL) {
+ types = 0;
+
+ do {
+ boolean_t found = B_FALSE;
+
+ if ((delim = strchr(tfield, ',')) != NULL)
+ *delim = '\0';
+ for (i = 0; i < sizeof (us_type_bits) / sizeof (int);
+ i++) {
+ if (strcmp(tfield, us_type_names[i]) == 0) {
+ found = B_TRUE;
+ types |= us_type_bits[i];
+ break;
+ }
+ }
+ if (!found) {
+ (void) fprintf(stderr, gettext("invalid type "
+ "'%s' for -t option\n"), tfield);
+ return (-1);
+ }
+ if (delim != NULL)
+ tfield = delim + 1;
+ } while (delim != NULL);
+ }
+
+ if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
+ return (1);
+
+ if ((avl_pool = uu_avl_pool_create("us_avl_pool", sizeof (us_node_t),
+ offsetof(us_node_t, usn_avlnode), us_compare, UU_DEFAULT)) == NULL)
+ nomem();
+ if ((avl_tree = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
+ nomem();
+
+ /* Always add default sorting columns */
+ (void) zfs_add_sort_column(&sortcol, "type", B_FALSE);
+ (void) zfs_add_sort_column(&sortcol, "name", B_FALSE);
+
+ cb.cb_sortcol = sortcol;
+ cb.cb_numname = prtnum;
+ cb.cb_nicenum = !parsable;
+ cb.cb_avl_pool = avl_pool;
+ cb.cb_avl = avl_tree;
+ cb.cb_sid2posix = sid2posix;
+
+ for (i = 0; i < USFIELD_LAST; i++)
+ cb.cb_width[i] = strlen(gettext(us_field_hdr[i]));
+
+ for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
+ if (((p == ZFS_PROP_USERUSED || p == ZFS_PROP_USERQUOTA) &&
+ !(types & (USTYPE_PSX_USR | USTYPE_SMB_USR))) ||
+ ((p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA) &&
+ !(types & (USTYPE_PSX_GRP | USTYPE_SMB_GRP))))
+ continue;
+ cb.cb_prop = p;
+ if ((ret = zfs_userspace(zhp, p, userspace_cb, &cb)) != 0)
+ return (ret);
+ }
+
+ /* Sort the list */
+ if ((node = uu_avl_first(avl_tree)) == NULL)
+ return (0);
+
+ us_populated = B_TRUE;
+
+ listpool = uu_list_pool_create("tmplist", sizeof (us_node_t),
+ offsetof(us_node_t, usn_listnode), NULL, UU_DEFAULT);
+ list = uu_list_create(listpool, NULL, UU_DEFAULT);
+ uu_list_node_init(node, &node->usn_listnode, listpool);
+
+ while (node != NULL) {
+ rmnode = node;
+ node = uu_avl_next(avl_tree, node);
+ uu_avl_remove(avl_tree, rmnode);
+ if (uu_list_find(list, rmnode, NULL, &idx2) == NULL)
+ uu_list_insert(list, rmnode, idx2);
+ }
+
+ for (node = uu_list_first(list); node != NULL;
+ node = uu_list_next(list, node)) {
+ us_sort_info_t sortinfo = { sortcol, cb.cb_numname };
+
+ if (uu_avl_find(avl_tree, node, &sortinfo, &idx) == NULL)
+ uu_avl_insert(avl_tree, node, idx);
+ }
+
+ uu_list_destroy(list);
+ uu_list_pool_destroy(listpool);
+
+ /* Print and free node nvlist memory */
+ print_us(scripted, parsable, fields, types, cb.cb_width, B_TRUE,
+ cb.cb_avl);
+
+ zfs_free_sort_columns(sortcol);
+
+ /* Clean up the AVL tree */
+ if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
+ nomem();
+
+ while ((node = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_remove(cb.cb_avl, node);
+ free(node);
+ }
+
+ uu_avl_walk_end(walk);
+ uu_avl_destroy(avl_tree);
+ uu_avl_pool_destroy(avl_pool);
+
+ return (ret);
+}
+
+/*
+ * list [-Hp][-r|-d max] [-o property[,...]] [-s property] ... [-S property] ...
+ * [-t type[,...]] [filesystem|volume|snapshot] ...
+ *
+ * -H Scripted mode; elide headers and separate columns by tabs.
+ * -p Display values in parsable (literal) format.
+ * -r Recurse over all children.
+ * -d Limit recursion by depth.
+ * -o Control which fields to display.
+ * -s Specify sort columns, descending order.
+ * -S Specify sort columns, ascending order.
+ * -t Control which object types to display.
+ *
+ * When given no arguments, list all filesystems in the system.
+ * Otherwise, list the specified datasets, optionally recursing down them if
+ * '-r' is specified.
+ */
+typedef struct list_cbdata {
+ boolean_t cb_first;
+ boolean_t cb_literal;
+ boolean_t cb_scripted;
+ zprop_list_t *cb_proplist;
+} list_cbdata_t;
+
+/*
+ * Given a list of columns to display, output appropriate headers for each one.
+ */
+static void
+print_header(list_cbdata_t *cb)
+{
+ zprop_list_t *pl = cb->cb_proplist;
+ char headerbuf[ZFS_MAXPROPLEN];
+ const char *header;
+ int i;
+ boolean_t first = B_TRUE;
+ boolean_t right_justify;
+
+ for (; pl != NULL; pl = pl->pl_next) {
+ if (!first) {
+ (void) printf(" ");
+ } else {
+ first = B_FALSE;
+ }
+
+ right_justify = B_FALSE;
+ if (pl->pl_prop != ZPROP_INVAL) {
+ header = zfs_prop_column_name(pl->pl_prop);
+ right_justify = zfs_prop_align_right(pl->pl_prop);
+ } else {
+ for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
+ headerbuf[i] = toupper(pl->pl_user_prop[i]);
+ headerbuf[i] = '\0';
+ header = headerbuf;
+ }
+
+ if (pl->pl_next == NULL && !right_justify)
+ (void) printf("%s", header);
+ else if (right_justify)
+ (void) printf("%*s", pl->pl_width, header);
+ else
+ (void) printf("%-*s", pl->pl_width, header);
+ }
+
+ (void) printf("\n");
+}
+
+/*
+ * Given a dataset and a list of fields, print out all the properties according
+ * to the described layout.
+ */
+static void
+print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
+{
+ zprop_list_t *pl = cb->cb_proplist;
+ boolean_t first = B_TRUE;
+ char property[ZFS_MAXPROPLEN];
+ nvlist_t *userprops = zfs_get_user_props(zhp);
+ nvlist_t *propval;
+ char *propstr;
+ boolean_t right_justify;
+
+ for (; pl != NULL; pl = pl->pl_next) {
+ if (!first) {
+ if (cb->cb_scripted)
+ (void) printf("\t");
+ else
+ (void) printf(" ");
+ } else {
+ first = B_FALSE;
+ }
+
+ if (pl->pl_prop == ZFS_PROP_NAME) {
+ (void) strlcpy(property, zfs_get_name(zhp),
+ sizeof (property));
+ propstr = property;
+ right_justify = zfs_prop_align_right(pl->pl_prop);
+ } else if (pl->pl_prop != ZPROP_INVAL) {
+ if (zfs_prop_get(zhp, pl->pl_prop, property,
+ sizeof (property), NULL, NULL, 0,
+ cb->cb_literal) != 0)
+ propstr = "-";
+ else
+ propstr = property;
+ right_justify = zfs_prop_align_right(pl->pl_prop);
+ } else if (zfs_prop_userquota(pl->pl_user_prop)) {
+ if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
+ property, sizeof (property), cb->cb_literal) != 0)
+ propstr = "-";
+ else
+ propstr = property;
+ right_justify = B_TRUE;
+ } else if (zfs_prop_written(pl->pl_user_prop)) {
+ if (zfs_prop_get_written(zhp, pl->pl_user_prop,
+ property, sizeof (property), cb->cb_literal) != 0)
+ propstr = "-";
+ else
+ propstr = property;
+ right_justify = B_TRUE;
+ } else {
+ if (nvlist_lookup_nvlist(userprops,
+ pl->pl_user_prop, &propval) != 0)
+ propstr = "-";
+ else
+ verify(nvlist_lookup_string(propval,
+ ZPROP_VALUE, &propstr) == 0);
+ right_justify = B_FALSE;
+ }
+
+ /*
+ * If this is being called in scripted mode, or if this is the
+ * last column and it is left-justified, don't include a width
+ * format specifier.
+ */
+ if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
+ (void) printf("%s", propstr);
+ else if (right_justify)
+ (void) printf("%*s", pl->pl_width, propstr);
+ else
+ (void) printf("%-*s", pl->pl_width, propstr);
+ }
+
+ (void) printf("\n");
+}
+
+/*
+ * Generic callback function to list a dataset or snapshot.
+ */
+static int
+list_callback(zfs_handle_t *zhp, void *data)
+{
+ list_cbdata_t *cbp = data;
+
+ if (cbp->cb_first) {
+ if (!cbp->cb_scripted)
+ print_header(cbp);
+ cbp->cb_first = B_FALSE;
+ }
+
+ print_dataset(zhp, cbp);
+
+ return (0);
+}
+
+static int
+zfs_do_list(int argc, char **argv)
+{
+ int c;
+ static char default_fields[] =
+ "name,used,available,referenced,mountpoint";
+ int types = ZFS_TYPE_DATASET;
+ boolean_t types_specified = B_FALSE;
+ char *fields = NULL;
+ list_cbdata_t cb = { 0 };
+ char *value;
+ int limit = 0;
+ int ret = 0;
+ zfs_sort_column_t *sortcol = NULL;
+ int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "HS:d:o:prs:t:")) != -1) {
+ switch (c) {
+ case 'o':
+ fields = optarg;
+ break;
+ case 'p':
+ cb.cb_literal = B_TRUE;
+ flags |= ZFS_ITER_LITERAL_PROPS;
+ break;
+ case 'd':
+ limit = parse_depth(optarg, &flags);
+ break;
+ case 'r':
+ flags |= ZFS_ITER_RECURSE;
+ break;
+ case 'H':
+ cb.cb_scripted = B_TRUE;
+ break;
+ case 's':
+ if (zfs_add_sort_column(&sortcol, optarg,
+ B_FALSE) != 0) {
+ (void) fprintf(stderr,
+ gettext("invalid property '%s'\n"), optarg);
+ usage(B_FALSE);
+ }
+ break;
+ case 'S':
+ if (zfs_add_sort_column(&sortcol, optarg,
+ B_TRUE) != 0) {
+ (void) fprintf(stderr,
+ gettext("invalid property '%s'\n"), optarg);
+ usage(B_FALSE);
+ }
+ break;
+ case 't':
+ types = 0;
+ types_specified = B_TRUE;
+ flags &= ~ZFS_ITER_PROP_LISTSNAPS;
+ while (*optarg != '\0') {
+ static char *type_subopts[] = { "filesystem",
+ "volume", "snapshot", "snap", "bookmark",
+ "all", NULL };
+
+ switch (getsubopt(&optarg, type_subopts,
+ &value)) {
+ case 0:
+ types |= ZFS_TYPE_FILESYSTEM;
+ break;
+ case 1:
+ types |= ZFS_TYPE_VOLUME;
+ break;
+ case 2:
+ case 3:
+ types |= ZFS_TYPE_SNAPSHOT;
+ break;
+ case 4:
+ types |= ZFS_TYPE_BOOKMARK;
+ break;
+ case 5:
+ types = ZFS_TYPE_DATASET |
+ ZFS_TYPE_BOOKMARK;
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("invalid type '%s'\n"),
+ suboptarg);
+ usage(B_FALSE);
+ }
+ }
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (fields == NULL)
+ fields = default_fields;
+
+ /*
+ * If we are only going to list snapshot names and sort by name,
+ * then we can use faster version.
+ */
+ if (strcmp(fields, "name") == 0 && zfs_sort_only_by_name(sortcol))
+ flags |= ZFS_ITER_SIMPLE;
+
+ /*
+ * If "-o space" and no types were specified, don't display snapshots.
+ */
+ if (strcmp(fields, "space") == 0 && types_specified == B_FALSE)
+ types &= ~ZFS_TYPE_SNAPSHOT;
+
+ /*
+ * If the user specifies '-o all', the zprop_get_list() doesn't
+ * normally include the name of the dataset. For 'zfs list', we always
+ * want this property to be first.
+ */
+ if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
+ != 0)
+ usage(B_FALSE);
+
+ cb.cb_first = B_TRUE;
+
+ ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
+ limit, list_callback, &cb);
+
+ zprop_free_list(cb.cb_proplist);
+ zfs_free_sort_columns(sortcol);
+
+ if (ret == 0 && cb.cb_first && !cb.cb_scripted)
+ (void) printf(gettext("no datasets available\n"));
+
+ return (ret);
+}
+
+/*
+ * zfs rename [-f] <fs | snap | vol> <fs | snap | vol>
+ * zfs rename [-f] -p <fs | vol> <fs | vol>
+ * zfs rename -r <snap> <snap>
+ * zfs rename <bmark> <bmark>
+ * zfs rename -u [-p] <fs> <fs>
+ *
+ * Renames the given dataset to another of the same type.
+ *
+ * The '-p' flag creates all the non-existing ancestors of the target first.
+ */
+/* ARGSUSED */
+static int
+zfs_do_rename(int argc, char **argv)
+{
+ zfs_handle_t *zhp;
+ renameflags_t flags = { 0 };
+ int c;
+ int ret = 0;
+ int types;
+ boolean_t parents = B_FALSE;
+ boolean_t bookmarks = B_FALSE;
+ char *snapshot = NULL;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "fpru")) != -1) {
+ switch (c) {
+ case 'p':
+ parents = B_TRUE;
+ break;
+ case 'r':
+ flags.recurse = B_TRUE;
+ break;
+ case 'u':
+ flags.nounmount = B_TRUE;
+ break;
+ case 'f':
+ flags.forceunmount = B_TRUE;
+ break;
+ case '?':
+ default:
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing source dataset "
+ "argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing target dataset "
+ "argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 2) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ if (flags.recurse && parents) {
+ (void) fprintf(stderr, gettext("-p and -r options are mutually "
+ "exclusive\n"));
+ usage(B_FALSE);
+ }
+
+ if (flags.recurse && strchr(argv[0], '@') == NULL) {
+ (void) fprintf(stderr, gettext("source dataset for recursive "
+ "rename must be a snapshot\n"));
+ usage(B_FALSE);
+ }
+
+ if (flags.nounmount && parents) {
+ (void) fprintf(stderr, gettext("-u and -p options are mutually "
+ "exclusive\n"));
+ usage(B_FALSE);
+ }
+
+ if (strchr(argv[0], '#') != NULL)
+ bookmarks = B_TRUE;
+
+ if (bookmarks && (flags.nounmount || flags.recurse ||
+ flags.forceunmount || parents)) {
+ (void) fprintf(stderr, gettext("options are not supported "
+ "for renaming bookmarks\n"));
+ usage(B_FALSE);
+ }
+
+ if (flags.nounmount)
+ types = ZFS_TYPE_FILESYSTEM;
+ else if (parents)
+ types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
+ else if (bookmarks)
+ types = ZFS_TYPE_BOOKMARK;
+ else
+ types = ZFS_TYPE_DATASET;
+
+ if (flags.recurse) {
+ /*
+ * When we do recursive rename we are fine when the given
+ * snapshot for the given dataset doesn't exist - it can
+ * still exists below.
+ */
+
+ snapshot = strchr(argv[0], '@');
+ assert(snapshot != NULL);
+ *snapshot = '\0';
+ snapshot++;
+ }
+
+ if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL)
+ return (1);
+
+ /* If we were asked and the name looks good, try to create ancestors. */
+ if (parents && zfs_name_valid(argv[1], zfs_get_type(zhp)) &&
+ zfs_create_ancestors(g_zfs, argv[1]) != 0) {
+ zfs_close(zhp);
+ return (1);
+ }
+
+ ret = (zfs_rename(zhp, snapshot, argv[1], flags) != 0);
+
+ zfs_close(zhp);
+ return (ret);
+}
+
+/*
+ * zfs promote <fs>
+ *
+ * Promotes the given clone fs to be the parent
+ */
+/* ARGSUSED */
+static int
+zfs_do_promote(int argc, char **argv)
+{
+ zfs_handle_t *zhp;
+ int ret = 0;
+
+ /* check options */
+ if (argc > 1 && argv[1][0] == '-') {
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ argv[1][1]);
+ usage(B_FALSE);
+ }
+
+ /* check number of arguments */
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing clone filesystem"
+ " argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 2) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ return (1);
+
+ ret = (zfs_promote(zhp) != 0);
+
+
+ zfs_close(zhp);
+ return (ret);
+}
+
+/*
+ * zfs rollback [-rRf] <snapshot>
+ *
+ * -r Delete any intervening snapshots before doing rollback
+ * -R Delete any snapshots and their clones
+ * -f ignored for backwards compatability
+ *
+ * Given a filesystem, rollback to a specific snapshot, discarding any changes
+ * since then and making it the active dataset. If more recent snapshots exist,
+ * the command will complain unless the '-r' flag is given.
+ */
+typedef struct rollback_cbdata {
+ uint64_t cb_create;
+ uint8_t cb_younger_ds_printed;
+ boolean_t cb_first;
+ int cb_doclones;
+ char *cb_target;
+ int cb_error;
+ boolean_t cb_recurse;
+} rollback_cbdata_t;
+
+static int
+rollback_check_dependent(zfs_handle_t *zhp, void *data)
+{
+ rollback_cbdata_t *cbp = data;
+
+ if (cbp->cb_first && cbp->cb_recurse) {
+ (void) fprintf(stderr, gettext("cannot rollback to "
+ "'%s': clones of previous snapshots exist\n"),
+ cbp->cb_target);
+ (void) fprintf(stderr, gettext("use '-R' to "
+ "force deletion of the following clones and "
+ "dependents:\n"));
+ cbp->cb_first = 0;
+ cbp->cb_error = 1;
+ }
+
+ (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
+
+ zfs_close(zhp);
+ return (0);
+}
+
+/*
+ * Report some snapshots/bookmarks more recent than the one specified.
+ * Used when '-r' is not specified. We reuse this same callback for the
+ * snapshot dependents - if 'cb_dependent' is set, then this is a
+ * dependent and we should report it without checking the transaction group.
+ */
+static int
+rollback_check(zfs_handle_t *zhp, void *data)
+{
+ rollback_cbdata_t *cbp = data;
+ /*
+ * Max number of younger snapshots and/or bookmarks to display before
+ * we stop the iteration.
+ */
+ const uint8_t max_younger = 32;
+
+ if (cbp->cb_doclones) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
+ if (cbp->cb_first && !cbp->cb_recurse) {
+ (void) fprintf(stderr, gettext("cannot "
+ "rollback to '%s': more recent snapshots "
+ "or bookmarks exist\n"),
+ cbp->cb_target);
+ (void) fprintf(stderr, gettext("use '-r' to "
+ "force deletion of the following "
+ "snapshots and bookmarks:\n"));
+ cbp->cb_first = 0;
+ cbp->cb_error = 1;
+ }
+
+ if (cbp->cb_recurse) {
+ if (zfs_iter_dependents(zhp, B_TRUE,
+ rollback_check_dependent, cbp) != 0) {
+ zfs_close(zhp);
+ return (-1);
+ }
+ } else {
+ (void) fprintf(stderr, "%s\n",
+ zfs_get_name(zhp));
+ cbp->cb_younger_ds_printed++;
+ }
+ }
+ zfs_close(zhp);
+
+ if (cbp->cb_younger_ds_printed == max_younger) {
+ /*
+ * This non-recursive rollback is going to fail due to the
+ * presence of snapshots and/or bookmarks that are younger than
+ * the rollback target.
+ * We printed some of the offending objects, now we stop
+ * zfs_iter_snapshot/bookmark iteration so we can fail fast and
+ * avoid iterating over the rest of the younger objects
+ */
+ (void) fprintf(stderr, gettext("Output limited to %d "
+ "snapshots/bookmarks\n"), max_younger);
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+zfs_do_rollback(int argc, char **argv)
+{
+ int ret = 0;
+ int c;
+ boolean_t force = B_FALSE;
+ rollback_cbdata_t cb = { 0 };
+ zfs_handle_t *zhp, *snap;
+ char parentname[ZFS_MAX_DATASET_NAME_LEN];
+ char *delim;
+ uint64_t min_txg = 0;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "rRf")) != -1) {
+ switch (c) {
+ case 'r':
+ cb.cb_recurse = 1;
+ break;
+ case 'R':
+ cb.cb_recurse = 1;
+ cb.cb_doclones = 1;
+ break;
+ case 'f':
+ force = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing dataset argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ /* open the snapshot */
+ if ((snap = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
+ return (1);
+
+ /* open the parent dataset */
+ (void) strlcpy(parentname, argv[0], sizeof (parentname));
+ verify((delim = strrchr(parentname, '@')) != NULL);
+ *delim = '\0';
+ if ((zhp = zfs_open(g_zfs, parentname, ZFS_TYPE_DATASET)) == NULL) {
+ zfs_close(snap);
+ return (1);
+ }
+
+ /*
+ * Check for more recent snapshots and/or clones based on the presence
+ * of '-r' and '-R'.
+ */
+ cb.cb_target = argv[0];
+ cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
+ cb.cb_first = B_TRUE;
+ cb.cb_error = 0;
+
+ if (cb.cb_create > 0)
+ min_txg = cb.cb_create;
+
+ if ((ret = zfs_iter_snapshots(zhp, B_FALSE, rollback_check, &cb,
+ min_txg, 0)) != 0)
+ goto out;
+ if ((ret = zfs_iter_bookmarks(zhp, rollback_check, &cb)) != 0)
+ goto out;
+
+ if ((ret = cb.cb_error) != 0)
+ goto out;
+
+ /*
+ * Rollback parent to the given snapshot.
+ */
+ ret = zfs_rollback(zhp, snap, force);
+
+out:
+ zfs_close(snap);
+ zfs_close(zhp);
+
+ if (ret == 0)
+ return (0);
+ else
+ return (1);
+}
+
+/*
+ * zfs set property=value ... { fs | snap | vol } ...
+ *
+ * Sets the given properties for all datasets specified on the command line.
+ */
+
+static int
+set_callback(zfs_handle_t *zhp, void *data)
+{
+ nvlist_t *props = data;
+
+ if (zfs_prop_set_list(zhp, props) != 0) {
+ switch (libzfs_errno(g_zfs)) {
+ case EZFS_MOUNTFAILED:
+ (void) fprintf(stderr, gettext("property may be set "
+ "but unable to remount filesystem\n"));
+ break;
+ case EZFS_SHARENFSFAILED:
+ (void) fprintf(stderr, gettext("property may be set "
+ "but unable to reshare filesystem\n"));
+ break;
+ }
+ return (1);
+ }
+ return (0);
+}
+
+static int
+zfs_do_set(int argc, char **argv)
+{
+ nvlist_t *props = NULL;
+ int ds_start = -1; /* argv idx of first dataset arg */
+ int ret = 0;
+
+ /* check for options */
+ if (argc > 1 && argv[1][0] == '-') {
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ argv[1][1]);
+ usage(B_FALSE);
+ }
+
+ /* check number of arguments */
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing arguments\n"));
+ usage(B_FALSE);
+ }
+ if (argc < 3) {
+ if (strchr(argv[1], '=') == NULL) {
+ (void) fprintf(stderr, gettext("missing property=value "
+ "argument(s)\n"));
+ } else {
+ (void) fprintf(stderr, gettext("missing dataset "
+ "name(s)\n"));
+ }
+ usage(B_FALSE);
+ }
+
+ /* validate argument order: prop=val args followed by dataset args */
+ for (int i = 1; i < argc; i++) {
+ if (strchr(argv[i], '=') != NULL) {
+ if (ds_start > 0) {
+ /* out-of-order prop=val argument */
+ (void) fprintf(stderr, gettext("invalid "
+ "argument order\n"), i);
+ usage(B_FALSE);
+ }
+ } else if (ds_start < 0) {
+ ds_start = i;
+ }
+ }
+ if (ds_start < 0) {
+ (void) fprintf(stderr, gettext("missing dataset name(s)\n"));
+ usage(B_FALSE);
+ }
+
+ /* Populate a list of property settings */
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+ for (int i = 1; i < ds_start; i++) {
+ if ((ret = parseprop(props, argv[i])) != 0)
+ goto error;
+ }
+
+ ret = zfs_for_each(argc - ds_start, argv + ds_start, 0,
+ ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, props);
+
+error:
+ nvlist_free(props);
+ return (ret);
+}
+
+typedef struct snap_cbdata {
+ nvlist_t *sd_nvl;
+ boolean_t sd_recursive;
+ const char *sd_snapname;
+} snap_cbdata_t;
+
+static int
+zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
+{
+ snap_cbdata_t *sd = arg;
+ char *name;
+ int rv = 0;
+ int error;
+
+ if (sd->sd_recursive &&
+ zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) != 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
+ if (error == -1)
+ nomem();
+ fnvlist_add_boolean(sd->sd_nvl, name);
+ free(name);
+
+ if (sd->sd_recursive)
+ rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
+ zfs_close(zhp);
+ return (rv);
+}
+
+/*
+ * zfs snapshot [-r] [-o prop=value] ... <fs@snap>
+ *
+ * Creates a snapshot with the given name. While functionally equivalent to
+ * 'zfs create', it is a separate command to differentiate intent.
+ */
+static int
+zfs_do_snapshot(int argc, char **argv)
+{
+ int ret = 0;
+ int c;
+ nvlist_t *props;
+ snap_cbdata_t sd = { 0 };
+ boolean_t multiple_snaps = B_FALSE;
+
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+ if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+
+ /* check options */
+ while ((c = getopt(argc, argv, "ro:")) != -1) {
+ switch (c) {
+ case 'o':
+ if (parseprop(props, optarg) != 0)
+ return (1);
+ break;
+ case 'r':
+ sd.sd_recursive = B_TRUE;
+ multiple_snaps = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ goto usage;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing snapshot argument\n"));
+ goto usage;
+ }
+
+ if (argc > 1)
+ multiple_snaps = B_TRUE;
+ for (; argc > 0; argc--, argv++) {
+ char *atp;
+ zfs_handle_t *zhp;
+
+ atp = strchr(argv[0], '@');
+ if (atp == NULL)
+ goto usage;
+ *atp = '\0';
+ sd.sd_snapname = atp + 1;
+ zhp = zfs_open(g_zfs, argv[0],
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ goto usage;
+ if (zfs_snapshot_cb(zhp, &sd) != 0)
+ goto usage;
+ }
+
+ ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props);
+ nvlist_free(sd.sd_nvl);
+ nvlist_free(props);
+ if (ret != 0 && multiple_snaps)
+ (void) fprintf(stderr, gettext("no snapshots were created\n"));
+ return (ret != 0);
+
+usage:
+ nvlist_free(sd.sd_nvl);
+ nvlist_free(props);
+ usage(B_FALSE);
+ return (-1);
+}
+
+/*
+ * Send a backup stream to stdout.
+ */
+static int
+zfs_do_send(int argc, char **argv)
+{
+ char *fromname = NULL;
+ char *toname = NULL;
+ char *resume_token = NULL;
+ char *cp;
+ zfs_handle_t *zhp;
+ sendflags_t flags = { 0 };
+ int c, err;
+ nvlist_t *dbgnv = NULL;
+ boolean_t extraverbose = B_FALSE;
+
+ struct option long_options[] = {
+ {"replicate", no_argument, NULL, 'R'},
+ {"props", no_argument, NULL, 'p'},
+ {"parsable", no_argument, NULL, 'P'},
+ {"dedup", no_argument, NULL, 'D'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"dryrun", no_argument, NULL, 'n'},
+ {"large-block", no_argument, NULL, 'L'},
+ {"embed", no_argument, NULL, 'e'},
+ {"resume", required_argument, NULL, 't'},
+ {"compressed", no_argument, NULL, 'c'},
+ {0, 0, 0, 0}
+ };
+
+ /* check options */
+ while ((c = getopt_long(argc, argv, ":i:I:RbDpVvnPLet:c", long_options,
+ NULL)) != -1) {
+ switch (c) {
+ case 'i':
+ if (fromname)
+ usage(B_FALSE);
+ fromname = optarg;
+ break;
+ case 'I':
+ if (fromname)
+ usage(B_FALSE);
+ fromname = optarg;
+ flags.doall = B_TRUE;
+ break;
+ case 'R':
+ flags.replicate = B_TRUE;
+ break;
+ case 'p':
+ flags.props = B_TRUE;
+ break;
+ case 'P':
+ flags.parsable = B_TRUE;
+ flags.verbose = B_TRUE;
+ break;
+ case 'V':
+ flags.progress = B_TRUE;
+ flags.progressastitle = B_TRUE;
+ break;
+ case 'v':
+ if (flags.verbose)
+ extraverbose = B_TRUE;
+ flags.verbose = B_TRUE;
+ flags.progress = B_TRUE;
+ break;
+ case 'D':
+ flags.dedup = B_TRUE;
+ break;
+ case 'n':
+ flags.dryrun = B_TRUE;
+ break;
+ case 'L':
+ flags.largeblock = B_TRUE;
+ break;
+ case 'e':
+ flags.embed_data = B_TRUE;
+ break;
+ case 't':
+ resume_token = optarg;
+ break;
+ case 'c':
+ flags.compress = B_TRUE;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ /*FALLTHROUGH*/
+ default:
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (resume_token != NULL) {
+ if (fromname != NULL || flags.replicate || flags.props ||
+ flags.dedup) {
+ (void) fprintf(stderr,
+ gettext("invalid flags combined with -t\n"));
+ usage(B_FALSE);
+ }
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("no additional "
+ "arguments are permitted with -t\n"));
+ usage(B_FALSE);
+ }
+ } else {
+ if (argc < 1) {
+ (void) fprintf(stderr,
+ gettext("missing snapshot argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+ }
+
+ if (!flags.dryrun && isatty(STDOUT_FILENO)) {
+ (void) fprintf(stderr,
+ gettext("Error: Stream can not be written to a terminal.\n"
+ "You must redirect standard output.\n"));
+ return (1);
+ }
+
+ if (resume_token != NULL) {
+ return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
+ resume_token));
+ }
+
+ /*
+ * Special case sending a filesystem, or from a bookmark.
+ */
+ if (strchr(argv[0], '@') == NULL ||
+ (fromname && strchr(fromname, '#') != NULL)) {
+ char frombuf[ZFS_MAX_DATASET_NAME_LEN];
+
+ if (flags.replicate || flags.doall || flags.props ||
+ flags.dedup || (strchr(argv[0], '@') == NULL &&
+ (flags.dryrun || flags.verbose || flags.progress))) {
+ (void) fprintf(stderr, gettext("Error: "
+ "Unsupported flag with filesystem or bookmark.\n"));
+ return (1);
+ }
+
+ zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET);
+ if (zhp == NULL)
+ return (1);
+
+ if (fromname != NULL &&
+ (fromname[0] == '#' || fromname[0] == '@')) {
+ /*
+ * Incremental source name begins with # or @.
+ * Default to same fs as target.
+ */
+ (void) strncpy(frombuf, argv[0], sizeof (frombuf));
+ cp = strchr(frombuf, '@');
+ if (cp != NULL)
+ *cp = '\0';
+ (void) strlcat(frombuf, fromname, sizeof (frombuf));
+ fromname = frombuf;
+ }
+ err = zfs_send_one(zhp, fromname, STDOUT_FILENO, flags);
+ zfs_close(zhp);
+ return (err != 0);
+ }
+
+ cp = strchr(argv[0], '@');
+ *cp = '\0';
+ toname = cp + 1;
+ zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ return (1);
+
+ /*
+ * If they specified the full path to the snapshot, chop off
+ * everything except the short name of the snapshot, but special
+ * case if they specify the origin.
+ */
+ if (fromname && (cp = strchr(fromname, '@')) != NULL) {
+ char origin[ZFS_MAX_DATASET_NAME_LEN];
+ zprop_source_t src;
+
+ (void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
+ origin, sizeof (origin), &src, NULL, 0, B_FALSE);
+
+ if (strcmp(origin, fromname) == 0) {
+ fromname = NULL;
+ flags.fromorigin = B_TRUE;
+ } else {
+ *cp = '\0';
+ if (cp != fromname && strcmp(argv[0], fromname)) {
+ (void) fprintf(stderr,
+ gettext("incremental source must be "
+ "in same filesystem\n"));
+ usage(B_FALSE);
+ }
+ fromname = cp + 1;
+ if (strchr(fromname, '@') || strchr(fromname, '/')) {
+ (void) fprintf(stderr,
+ gettext("invalid incremental source\n"));
+ usage(B_FALSE);
+ }
+ }
+ }
+
+ if (flags.replicate && fromname == NULL)
+ flags.doall = B_TRUE;
+
+ err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO, NULL, 0,
+ extraverbose ? &dbgnv : NULL);
+
+ if (extraverbose && dbgnv != NULL) {
+ /*
+ * dump_nvlist prints to stdout, but that's been
+ * redirected to a file. Make it print to stderr
+ * instead.
+ */
+ (void) dup2(STDERR_FILENO, STDOUT_FILENO);
+ dump_nvlist(dbgnv, 0);
+ nvlist_free(dbgnv);
+ }
+ zfs_close(zhp);
+
+ return (err != 0);
+}
+
+/*
+ * Restore a backup stream from stdin.
+ */
+static int
+zfs_do_receive(int argc, char **argv)
+{
+ int c, err = 0;
+ recvflags_t flags = { 0 };
+ boolean_t abort_resumable = B_FALSE;
+
+ nvlist_t *props;
+ nvpair_t *nvp = NULL;
+
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+
+ /* check options */
+ while ((c = getopt(argc, argv, ":o:denuvFsA")) != -1) {
+ switch (c) {
+ case 'o':
+ if (parseprop(props, optarg) != 0)
+ return (1);
+ break;
+ case 'd':
+ flags.isprefix = B_TRUE;
+ break;
+ case 'e':
+ flags.isprefix = B_TRUE;
+ flags.istail = B_TRUE;
+ break;
+ case 'n':
+ flags.dryrun = B_TRUE;
+ break;
+ case 'u':
+ flags.nomount = B_TRUE;
+ break;
+ case 'v':
+ flags.verbose = B_TRUE;
+ break;
+ case 's':
+ flags.resumable = B_TRUE;
+ break;
+ case 'F':
+ flags.force = B_TRUE;
+ break;
+ case 'A':
+ abort_resumable = B_TRUE;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing snapshot argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ while ((nvp = nvlist_next_nvpair(props, nvp))) {
+ if (strcmp(nvpair_name(nvp), "origin") != 0) {
+ (void) fprintf(stderr, gettext("invalid option"));
+ usage(B_FALSE);
+ }
+ }
+
+ if (abort_resumable) {
+ if (flags.isprefix || flags.istail || flags.dryrun ||
+ flags.resumable || flags.nomount) {
+ (void) fprintf(stderr, gettext("invalid option"));
+ usage(B_FALSE);
+ }
+
+ char namebuf[ZFS_MAX_DATASET_NAME_LEN];
+ (void) snprintf(namebuf, sizeof (namebuf),
+ "%s/%%recv", argv[0]);
+
+ if (zfs_dataset_exists(g_zfs, namebuf,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) {
+ zfs_handle_t *zhp = zfs_open(g_zfs,
+ namebuf, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ return (1);
+ err = zfs_destroy(zhp, B_FALSE);
+ } else {
+ zfs_handle_t *zhp = zfs_open(g_zfs,
+ argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ usage(B_FALSE);
+ if (!zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) ||
+ zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+ NULL, 0, NULL, NULL, 0, B_TRUE) == -1) {
+ (void) fprintf(stderr,
+ gettext("'%s' does not have any "
+ "resumable receive state to abort\n"),
+ argv[0]);
+ return (1);
+ }
+ err = zfs_destroy(zhp, B_FALSE);
+ }
+
+ return (err != 0);
+ }
+
+ if (isatty(STDIN_FILENO)) {
+ (void) fprintf(stderr,
+ gettext("Error: Backup stream can not be read "
+ "from a terminal.\n"
+ "You must redirect standard input.\n"));
+ return (1);
+ }
+ err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL);
+
+ return (err != 0);
+}
+
+/*
+ * allow/unallow stuff
+ */
+/* copied from zfs/sys/dsl_deleg.h */
+#define ZFS_DELEG_PERM_CREATE "create"
+#define ZFS_DELEG_PERM_DESTROY "destroy"
+#define ZFS_DELEG_PERM_SNAPSHOT "snapshot"
+#define ZFS_DELEG_PERM_ROLLBACK "rollback"
+#define ZFS_DELEG_PERM_CLONE "clone"
+#define ZFS_DELEG_PERM_PROMOTE "promote"
+#define ZFS_DELEG_PERM_RENAME "rename"
+#define ZFS_DELEG_PERM_MOUNT "mount"
+#define ZFS_DELEG_PERM_SHARE "share"
+#define ZFS_DELEG_PERM_SEND "send"
+#define ZFS_DELEG_PERM_RECEIVE "receive"
+#define ZFS_DELEG_PERM_ALLOW "allow"
+#define ZFS_DELEG_PERM_USERPROP "userprop"
+#define ZFS_DELEG_PERM_VSCAN "vscan" /* ??? */
+#define ZFS_DELEG_PERM_USERQUOTA "userquota"
+#define ZFS_DELEG_PERM_GROUPQUOTA "groupquota"
+#define ZFS_DELEG_PERM_USERUSED "userused"
+#define ZFS_DELEG_PERM_GROUPUSED "groupused"
+#define ZFS_DELEG_PERM_HOLD "hold"
+#define ZFS_DELEG_PERM_RELEASE "release"
+#define ZFS_DELEG_PERM_DIFF "diff"
+#define ZFS_DELEG_PERM_BOOKMARK "bookmark"
+#define ZFS_DELEG_PERM_REMAP "remap"
+
+#define ZFS_NUM_DELEG_NOTES ZFS_DELEG_NOTE_NONE
+
+static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = {
+ { ZFS_DELEG_PERM_ALLOW, ZFS_DELEG_NOTE_ALLOW },
+ { ZFS_DELEG_PERM_CLONE, ZFS_DELEG_NOTE_CLONE },
+ { ZFS_DELEG_PERM_CREATE, ZFS_DELEG_NOTE_CREATE },
+ { ZFS_DELEG_PERM_DESTROY, ZFS_DELEG_NOTE_DESTROY },
+ { ZFS_DELEG_PERM_DIFF, ZFS_DELEG_NOTE_DIFF},
+ { ZFS_DELEG_PERM_HOLD, ZFS_DELEG_NOTE_HOLD },
+ { ZFS_DELEG_PERM_MOUNT, ZFS_DELEG_NOTE_MOUNT },
+ { ZFS_DELEG_PERM_PROMOTE, ZFS_DELEG_NOTE_PROMOTE },
+ { ZFS_DELEG_PERM_RECEIVE, ZFS_DELEG_NOTE_RECEIVE },
+ { ZFS_DELEG_PERM_RELEASE, ZFS_DELEG_NOTE_RELEASE },
+ { ZFS_DELEG_PERM_RENAME, ZFS_DELEG_NOTE_RENAME },
+ { ZFS_DELEG_PERM_ROLLBACK, ZFS_DELEG_NOTE_ROLLBACK },
+ { ZFS_DELEG_PERM_SEND, ZFS_DELEG_NOTE_SEND },
+ { ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE },
+ { ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT },
+ { ZFS_DELEG_PERM_BOOKMARK, ZFS_DELEG_NOTE_BOOKMARK },
+ { ZFS_DELEG_PERM_REMAP, ZFS_DELEG_NOTE_REMAP },
+
+ { ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA },
+ { ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED },
+ { ZFS_DELEG_PERM_USERPROP, ZFS_DELEG_NOTE_USERPROP },
+ { ZFS_DELEG_PERM_USERQUOTA, ZFS_DELEG_NOTE_USERQUOTA },
+ { ZFS_DELEG_PERM_USERUSED, ZFS_DELEG_NOTE_USERUSED },
+ { NULL, ZFS_DELEG_NOTE_NONE }
+};
+
+/* permission structure */
+typedef struct deleg_perm {
+ zfs_deleg_who_type_t dp_who_type;
+ const char *dp_name;
+ boolean_t dp_local;
+ boolean_t dp_descend;
+} deleg_perm_t;
+
+/* */
+typedef struct deleg_perm_node {
+ deleg_perm_t dpn_perm;
+
+ uu_avl_node_t dpn_avl_node;
+} deleg_perm_node_t;
+
+typedef struct fs_perm fs_perm_t;
+
+/* permissions set */
+typedef struct who_perm {
+ zfs_deleg_who_type_t who_type;
+ const char *who_name; /* id */
+ char who_ug_name[256]; /* user/group name */
+ fs_perm_t *who_fsperm; /* uplink */
+
+ uu_avl_t *who_deleg_perm_avl; /* permissions */
+} who_perm_t;
+
+/* */
+typedef struct who_perm_node {
+ who_perm_t who_perm;
+ uu_avl_node_t who_avl_node;
+} who_perm_node_t;
+
+typedef struct fs_perm_set fs_perm_set_t;
+/* fs permissions */
+struct fs_perm {
+ const char *fsp_name;
+
+ uu_avl_t *fsp_sc_avl; /* sets,create */
+ uu_avl_t *fsp_uge_avl; /* user,group,everyone */
+
+ fs_perm_set_t *fsp_set; /* uplink */
+};
+
+/* */
+typedef struct fs_perm_node {
+ fs_perm_t fspn_fsperm;
+ uu_avl_t *fspn_avl;
+
+ uu_list_node_t fspn_list_node;
+} fs_perm_node_t;
+
+/* top level structure */
+struct fs_perm_set {
+ uu_list_pool_t *fsps_list_pool;
+ uu_list_t *fsps_list; /* list of fs_perms */
+
+ uu_avl_pool_t *fsps_named_set_avl_pool;
+ uu_avl_pool_t *fsps_who_perm_avl_pool;
+ uu_avl_pool_t *fsps_deleg_perm_avl_pool;
+};
+
+static inline const char *
+deleg_perm_type(zfs_deleg_note_t note)
+{
+ /* subcommands */
+ switch (note) {
+ /* SUBCOMMANDS */
+ /* OTHER */
+ case ZFS_DELEG_NOTE_GROUPQUOTA:
+ case ZFS_DELEG_NOTE_GROUPUSED:
+ case ZFS_DELEG_NOTE_USERPROP:
+ case ZFS_DELEG_NOTE_USERQUOTA:
+ case ZFS_DELEG_NOTE_USERUSED:
+ /* other */
+ return (gettext("other"));
+ default:
+ return (gettext("subcommand"));
+ }
+}
+
+static int
+who_type2weight(zfs_deleg_who_type_t who_type)
+{
+ int res;
+ switch (who_type) {
+ case ZFS_DELEG_NAMED_SET_SETS:
+ case ZFS_DELEG_NAMED_SET:
+ res = 0;
+ break;
+ case ZFS_DELEG_CREATE_SETS:
+ case ZFS_DELEG_CREATE:
+ res = 1;
+ break;
+ case ZFS_DELEG_USER_SETS:
+ case ZFS_DELEG_USER:
+ res = 2;
+ break;
+ case ZFS_DELEG_GROUP_SETS:
+ case ZFS_DELEG_GROUP:
+ res = 3;
+ break;
+ case ZFS_DELEG_EVERYONE_SETS:
+ case ZFS_DELEG_EVERYONE:
+ res = 4;
+ break;
+ default:
+ res = -1;
+ }
+
+ return (res);
+}
+
+/* ARGSUSED */
+static int
+who_perm_compare(const void *larg, const void *rarg, void *unused)
+{
+ const who_perm_node_t *l = larg;
+ const who_perm_node_t *r = rarg;
+ zfs_deleg_who_type_t ltype = l->who_perm.who_type;
+ zfs_deleg_who_type_t rtype = r->who_perm.who_type;
+ int lweight = who_type2weight(ltype);
+ int rweight = who_type2weight(rtype);
+ int res = lweight - rweight;
+ if (res == 0)
+ res = strncmp(l->who_perm.who_name, r->who_perm.who_name,
+ ZFS_MAX_DELEG_NAME-1);
+
+ if (res == 0)
+ return (0);
+ if (res > 0)
+ return (1);
+ else
+ return (-1);
+}
+
+/* ARGSUSED */
+static int
+deleg_perm_compare(const void *larg, const void *rarg, void *unused)
+{
+ const deleg_perm_node_t *l = larg;
+ const deleg_perm_node_t *r = rarg;
+ int res = strncmp(l->dpn_perm.dp_name, r->dpn_perm.dp_name,
+ ZFS_MAX_DELEG_NAME-1);
+
+ if (res == 0)
+ return (0);
+
+ if (res > 0)
+ return (1);
+ else
+ return (-1);
+}
+
+static inline void
+fs_perm_set_init(fs_perm_set_t *fspset)
+{
+ bzero(fspset, sizeof (fs_perm_set_t));
+
+ if ((fspset->fsps_list_pool = uu_list_pool_create("fsps_list_pool",
+ sizeof (fs_perm_node_t), offsetof(fs_perm_node_t, fspn_list_node),
+ NULL, UU_DEFAULT)) == NULL)
+ nomem();
+ if ((fspset->fsps_list = uu_list_create(fspset->fsps_list_pool, NULL,
+ UU_DEFAULT)) == NULL)
+ nomem();
+
+ if ((fspset->fsps_named_set_avl_pool = uu_avl_pool_create(
+ "named_set_avl_pool", sizeof (who_perm_node_t), offsetof(
+ who_perm_node_t, who_avl_node), who_perm_compare,
+ UU_DEFAULT)) == NULL)
+ nomem();
+
+ if ((fspset->fsps_who_perm_avl_pool = uu_avl_pool_create(
+ "who_perm_avl_pool", sizeof (who_perm_node_t), offsetof(
+ who_perm_node_t, who_avl_node), who_perm_compare,
+ UU_DEFAULT)) == NULL)
+ nomem();
+
+ if ((fspset->fsps_deleg_perm_avl_pool = uu_avl_pool_create(
+ "deleg_perm_avl_pool", sizeof (deleg_perm_node_t), offsetof(
+ deleg_perm_node_t, dpn_avl_node), deleg_perm_compare, UU_DEFAULT))
+ == NULL)
+ nomem();
+}
+
+static inline void fs_perm_fini(fs_perm_t *);
+static inline void who_perm_fini(who_perm_t *);
+
+static inline void
+fs_perm_set_fini(fs_perm_set_t *fspset)
+{
+ fs_perm_node_t *node = uu_list_first(fspset->fsps_list);
+
+ while (node != NULL) {
+ fs_perm_node_t *next_node =
+ uu_list_next(fspset->fsps_list, node);
+ fs_perm_t *fsperm = &node->fspn_fsperm;
+ fs_perm_fini(fsperm);
+ uu_list_remove(fspset->fsps_list, node);
+ free(node);
+ node = next_node;
+ }
+
+ uu_avl_pool_destroy(fspset->fsps_named_set_avl_pool);
+ uu_avl_pool_destroy(fspset->fsps_who_perm_avl_pool);
+ uu_avl_pool_destroy(fspset->fsps_deleg_perm_avl_pool);
+}
+
+static inline void
+deleg_perm_init(deleg_perm_t *deleg_perm, zfs_deleg_who_type_t type,
+ const char *name)
+{
+ deleg_perm->dp_who_type = type;
+ deleg_perm->dp_name = name;
+}
+
+static inline void
+who_perm_init(who_perm_t *who_perm, fs_perm_t *fsperm,
+ zfs_deleg_who_type_t type, const char *name)
+{
+ uu_avl_pool_t *pool;
+ pool = fsperm->fsp_set->fsps_deleg_perm_avl_pool;
+
+ bzero(who_perm, sizeof (who_perm_t));
+
+ if ((who_perm->who_deleg_perm_avl = uu_avl_create(pool, NULL,
+ UU_DEFAULT)) == NULL)
+ nomem();
+
+ who_perm->who_type = type;
+ who_perm->who_name = name;
+ who_perm->who_fsperm = fsperm;
+}
+
+static inline void
+who_perm_fini(who_perm_t *who_perm)
+{
+ deleg_perm_node_t *node = uu_avl_first(who_perm->who_deleg_perm_avl);
+
+ while (node != NULL) {
+ deleg_perm_node_t *next_node =
+ uu_avl_next(who_perm->who_deleg_perm_avl, node);
+
+ uu_avl_remove(who_perm->who_deleg_perm_avl, node);
+ free(node);
+ node = next_node;
+ }
+
+ uu_avl_destroy(who_perm->who_deleg_perm_avl);
+}
+
+static inline void
+fs_perm_init(fs_perm_t *fsperm, fs_perm_set_t *fspset, const char *fsname)
+{
+ uu_avl_pool_t *nset_pool = fspset->fsps_named_set_avl_pool;
+ uu_avl_pool_t *who_pool = fspset->fsps_who_perm_avl_pool;
+
+ bzero(fsperm, sizeof (fs_perm_t));
+
+ if ((fsperm->fsp_sc_avl = uu_avl_create(nset_pool, NULL, UU_DEFAULT))
+ == NULL)
+ nomem();
+
+ if ((fsperm->fsp_uge_avl = uu_avl_create(who_pool, NULL, UU_DEFAULT))
+ == NULL)
+ nomem();
+
+ fsperm->fsp_set = fspset;
+ fsperm->fsp_name = fsname;
+}
+
+static inline void
+fs_perm_fini(fs_perm_t *fsperm)
+{
+ who_perm_node_t *node = uu_avl_first(fsperm->fsp_sc_avl);
+ while (node != NULL) {
+ who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_sc_avl,
+ node);
+ who_perm_t *who_perm = &node->who_perm;
+ who_perm_fini(who_perm);
+ uu_avl_remove(fsperm->fsp_sc_avl, node);
+ free(node);
+ node = next_node;
+ }
+
+ node = uu_avl_first(fsperm->fsp_uge_avl);
+ while (node != NULL) {
+ who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_uge_avl,
+ node);
+ who_perm_t *who_perm = &node->who_perm;
+ who_perm_fini(who_perm);
+ uu_avl_remove(fsperm->fsp_uge_avl, node);
+ free(node);
+ node = next_node;
+ }
+
+ uu_avl_destroy(fsperm->fsp_sc_avl);
+ uu_avl_destroy(fsperm->fsp_uge_avl);
+}
+
+static void
+set_deleg_perm_node(uu_avl_t *avl, deleg_perm_node_t *node,
+ zfs_deleg_who_type_t who_type, const char *name, char locality)
+{
+ uu_avl_index_t idx = 0;
+
+ deleg_perm_node_t *found_node = NULL;
+ deleg_perm_t *deleg_perm = &node->dpn_perm;
+
+ deleg_perm_init(deleg_perm, who_type, name);
+
+ if ((found_node = uu_avl_find(avl, node, NULL, &idx))
+ == NULL)
+ uu_avl_insert(avl, node, idx);
+ else {
+ node = found_node;
+ deleg_perm = &node->dpn_perm;
+ }
+
+
+ switch (locality) {
+ case ZFS_DELEG_LOCAL:
+ deleg_perm->dp_local = B_TRUE;
+ break;
+ case ZFS_DELEG_DESCENDENT:
+ deleg_perm->dp_descend = B_TRUE;
+ break;
+ case ZFS_DELEG_NA:
+ break;
+ default:
+ assert(B_FALSE); /* invalid locality */
+ }
+}
+
+static inline int
+parse_who_perm(who_perm_t *who_perm, nvlist_t *nvl, char locality)
+{
+ nvpair_t *nvp = NULL;
+ fs_perm_set_t *fspset = who_perm->who_fsperm->fsp_set;
+ uu_avl_t *avl = who_perm->who_deleg_perm_avl;
+ zfs_deleg_who_type_t who_type = who_perm->who_type;
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ const char *name = nvpair_name(nvp);
+ data_type_t type = nvpair_type(nvp);
+ uu_avl_pool_t *avl_pool = fspset->fsps_deleg_perm_avl_pool;
+ deleg_perm_node_t *node =
+ safe_malloc(sizeof (deleg_perm_node_t));
+
+ assert(type == DATA_TYPE_BOOLEAN);
+
+ uu_avl_node_init(node, &node->dpn_avl_node, avl_pool);
+ set_deleg_perm_node(avl, node, who_type, name, locality);
+ }
+
+ return (0);
+}
+
+static inline int
+parse_fs_perm(fs_perm_t *fsperm, nvlist_t *nvl)
+{
+ nvpair_t *nvp = NULL;
+ fs_perm_set_t *fspset = fsperm->fsp_set;
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ nvlist_t *nvl2 = NULL;
+ const char *name = nvpair_name(nvp);
+ uu_avl_t *avl = NULL;
+ uu_avl_pool_t *avl_pool = NULL;
+ zfs_deleg_who_type_t perm_type = name[0];
+ char perm_locality = name[1];
+ const char *perm_name = name + 3;
+ boolean_t is_set = B_TRUE;
+ who_perm_t *who_perm = NULL;
+
+ assert('$' == name[2]);
+
+ if (nvpair_value_nvlist(nvp, &nvl2) != 0)
+ return (-1);
+
+ switch (perm_type) {
+ case ZFS_DELEG_CREATE:
+ case ZFS_DELEG_CREATE_SETS:
+ case ZFS_DELEG_NAMED_SET:
+ case ZFS_DELEG_NAMED_SET_SETS:
+ avl_pool = fspset->fsps_named_set_avl_pool;
+ avl = fsperm->fsp_sc_avl;
+ break;
+ case ZFS_DELEG_USER:
+ case ZFS_DELEG_USER_SETS:
+ case ZFS_DELEG_GROUP:
+ case ZFS_DELEG_GROUP_SETS:
+ case ZFS_DELEG_EVERYONE:
+ case ZFS_DELEG_EVERYONE_SETS:
+ avl_pool = fspset->fsps_who_perm_avl_pool;
+ avl = fsperm->fsp_uge_avl;
+ break;
+
+ default:
+ assert(!"unhandled zfs_deleg_who_type_t");
+ }
+
+ if (is_set) {
+ who_perm_node_t *found_node = NULL;
+ who_perm_node_t *node = safe_malloc(
+ sizeof (who_perm_node_t));
+ who_perm = &node->who_perm;
+ uu_avl_index_t idx = 0;
+
+ uu_avl_node_init(node, &node->who_avl_node, avl_pool);
+ who_perm_init(who_perm, fsperm, perm_type, perm_name);
+
+ if ((found_node = uu_avl_find(avl, node, NULL, &idx))
+ == NULL) {
+ if (avl == fsperm->fsp_uge_avl) {
+ uid_t rid = 0;
+ struct passwd *p = NULL;
+ struct group *g = NULL;
+ const char *nice_name = NULL;
+
+ switch (perm_type) {
+ case ZFS_DELEG_USER_SETS:
+ case ZFS_DELEG_USER:
+ rid = atoi(perm_name);
+ p = getpwuid(rid);
+ if (p)
+ nice_name = p->pw_name;
+ break;
+ case ZFS_DELEG_GROUP_SETS:
+ case ZFS_DELEG_GROUP:
+ rid = atoi(perm_name);
+ g = getgrgid(rid);
+ if (g)
+ nice_name = g->gr_name;
+ break;
+
+ default:
+ break;
+ }
+
+ if (nice_name != NULL)
+ (void) strlcpy(
+ node->who_perm.who_ug_name,
+ nice_name, 256);
+ }
+
+ uu_avl_insert(avl, node, idx);
+ } else {
+ node = found_node;
+ who_perm = &node->who_perm;
+ }
+ }
+
+ (void) parse_who_perm(who_perm, nvl2, perm_locality);
+ }
+
+ return (0);
+}
+
+static inline int
+parse_fs_perm_set(fs_perm_set_t *fspset, nvlist_t *nvl)
+{
+ nvpair_t *nvp = NULL;
+ uu_avl_index_t idx = 0;
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ nvlist_t *nvl2 = NULL;
+ const char *fsname = nvpair_name(nvp);
+ data_type_t type = nvpair_type(nvp);
+ fs_perm_t *fsperm = NULL;
+ fs_perm_node_t *node = safe_malloc(sizeof (fs_perm_node_t));
+ if (node == NULL)
+ nomem();
+
+ fsperm = &node->fspn_fsperm;
+
+ assert(DATA_TYPE_NVLIST == type);
+
+ uu_list_node_init(node, &node->fspn_list_node,
+ fspset->fsps_list_pool);
+
+ idx = uu_list_numnodes(fspset->fsps_list);
+ fs_perm_init(fsperm, fspset, fsname);
+
+ if (nvpair_value_nvlist(nvp, &nvl2) != 0)
+ return (-1);
+
+ (void) parse_fs_perm(fsperm, nvl2);
+
+ uu_list_insert(fspset->fsps_list, node, idx);
+ }
+
+ return (0);
+}
+
+static inline const char *
+deleg_perm_comment(zfs_deleg_note_t note)
+{
+ const char *str = "";
+
+ /* subcommands */
+ switch (note) {
+ /* SUBCOMMANDS */
+ case ZFS_DELEG_NOTE_ALLOW:
+ str = gettext("Must also have the permission that is being"
+ "\n\t\t\t\tallowed");
+ break;
+ case ZFS_DELEG_NOTE_CLONE:
+ str = gettext("Must also have the 'create' ability and 'mount'"
+ "\n\t\t\t\tability in the origin file system");
+ break;
+ case ZFS_DELEG_NOTE_CREATE:
+ str = gettext("Must also have the 'mount' ability");
+ break;
+ case ZFS_DELEG_NOTE_DESTROY:
+ str = gettext("Must also have the 'mount' ability");
+ break;
+ case ZFS_DELEG_NOTE_DIFF:
+ str = gettext("Allows lookup of paths within a dataset;"
+ "\n\t\t\t\tgiven an object number. Ordinary users need this"
+ "\n\t\t\t\tin order to use zfs diff");
+ break;
+ case ZFS_DELEG_NOTE_HOLD:
+ str = gettext("Allows adding a user hold to a snapshot");
+ break;
+ case ZFS_DELEG_NOTE_MOUNT:
+ str = gettext("Allows mount/umount of ZFS datasets");
+ break;
+ case ZFS_DELEG_NOTE_PROMOTE:
+ str = gettext("Must also have the 'mount'\n\t\t\t\tand"
+ " 'promote' ability in the origin file system");
+ break;
+ case ZFS_DELEG_NOTE_RECEIVE:
+ str = gettext("Must also have the 'mount' and 'create'"
+ " ability");
+ break;
+ case ZFS_DELEG_NOTE_RELEASE:
+ str = gettext("Allows releasing a user hold which\n\t\t\t\t"
+ "might destroy the snapshot");
+ break;
+ case ZFS_DELEG_NOTE_RENAME:
+ str = gettext("Must also have the 'mount' and 'create'"
+ "\n\t\t\t\tability in the new parent");
+ break;
+ case ZFS_DELEG_NOTE_ROLLBACK:
+ str = gettext("");
+ break;
+ case ZFS_DELEG_NOTE_SEND:
+ str = gettext("");
+ break;
+ case ZFS_DELEG_NOTE_SHARE:
+ str = gettext("Allows sharing file systems over NFS or SMB"
+ "\n\t\t\t\tprotocols");
+ break;
+ case ZFS_DELEG_NOTE_SNAPSHOT:
+ str = gettext("");
+ break;
+/*
+ * case ZFS_DELEG_NOTE_VSCAN:
+ * str = gettext("");
+ * break;
+ */
+ /* OTHER */
+ case ZFS_DELEG_NOTE_GROUPQUOTA:
+ str = gettext("Allows accessing any groupquota@... property");
+ break;
+ case ZFS_DELEG_NOTE_GROUPUSED:
+ str = gettext("Allows reading any groupused@... property");
+ break;
+ case ZFS_DELEG_NOTE_USERPROP:
+ str = gettext("Allows changing any user property");
+ break;
+ case ZFS_DELEG_NOTE_USERQUOTA:
+ str = gettext("Allows accessing any userquota@... property");
+ break;
+ case ZFS_DELEG_NOTE_USERUSED:
+ str = gettext("Allows reading any userused@... property");
+ break;
+ /* other */
+ default:
+ str = "";
+ }
+
+ return (str);
+}
+
+struct allow_opts {
+ boolean_t local;
+ boolean_t descend;
+ boolean_t user;
+ boolean_t group;
+ boolean_t everyone;
+ boolean_t create;
+ boolean_t set;
+ boolean_t recursive; /* unallow only */
+ boolean_t prt_usage;
+
+ boolean_t prt_perms;
+ char *who;
+ char *perms;
+ const char *dataset;
+};
+
+static inline int
+prop_cmp(const void *a, const void *b)
+{
+ const char *str1 = *(const char **)a;
+ const char *str2 = *(const char **)b;
+ return (strcmp(str1, str2));
+}
+
+static void
+allow_usage(boolean_t un, boolean_t requested, const char *msg)
+{
+ const char *opt_desc[] = {
+ "-h", gettext("show this help message and exit"),
+ "-l", gettext("set permission locally"),
+ "-d", gettext("set permission for descents"),
+ "-u", gettext("set permission for user"),
+ "-g", gettext("set permission for group"),
+ "-e", gettext("set permission for everyone"),
+ "-c", gettext("set create time permission"),
+ "-s", gettext("define permission set"),
+ /* unallow only */
+ "-r", gettext("remove permissions recursively"),
+ };
+ size_t unallow_size = sizeof (opt_desc) / sizeof (char *);
+ size_t allow_size = unallow_size - 2;
+ const char *props[ZFS_NUM_PROPS];
+ int i;
+ size_t count = 0;
+ FILE *fp = requested ? stdout : stderr;
+ zprop_desc_t *pdtbl = zfs_prop_get_table();
+ const char *fmt = gettext("%-16s %-14s\t%s\n");
+
+ (void) fprintf(fp, gettext("Usage: %s\n"), get_usage(un ? HELP_UNALLOW :
+ HELP_ALLOW));
+ (void) fprintf(fp, gettext("Options:\n"));
+ for (i = 0; i < (un ? unallow_size : allow_size); i++) {
+ const char *opt = opt_desc[i++];
+ const char *optdsc = opt_desc[i];
+ (void) fprintf(fp, gettext(" %-10s %s\n"), opt, optdsc);
+ }
+
+ (void) fprintf(fp, gettext("\nThe following permissions are "
+ "supported:\n\n"));
+ (void) fprintf(fp, fmt, gettext("NAME"), gettext("TYPE"),
+ gettext("NOTES"));
+ for (i = 0; i < ZFS_NUM_DELEG_NOTES; i++) {
+ const char *perm_name = zfs_deleg_perm_tbl[i].z_perm;
+ zfs_deleg_note_t perm_note = zfs_deleg_perm_tbl[i].z_note;
+ const char *perm_type = deleg_perm_type(perm_note);
+ const char *perm_comment = deleg_perm_comment(perm_note);
+ (void) fprintf(fp, fmt, perm_name, perm_type, perm_comment);
+ }
+
+ for (i = 0; i < ZFS_NUM_PROPS; i++) {
+ zprop_desc_t *pd = &pdtbl[i];
+ if (pd->pd_visible != B_TRUE)
+ continue;
+
+ if (pd->pd_attr == PROP_READONLY)
+ continue;
+
+ props[count++] = pd->pd_name;
+ }
+ props[count] = NULL;
+
+ qsort(props, count, sizeof (char *), prop_cmp);
+
+ for (i = 0; i < count; i++)
+ (void) fprintf(fp, fmt, props[i], gettext("property"), "");
+
+ if (msg != NULL)
+ (void) fprintf(fp, gettext("\nzfs: error: %s"), msg);
+
+ exit(requested ? 0 : 2);
+}
+
+static inline const char *
+munge_args(int argc, char **argv, boolean_t un, size_t expected_argc,
+ char **permsp)
+{
+ if (un && argc == expected_argc - 1)
+ *permsp = NULL;
+ else if (argc == expected_argc)
+ *permsp = argv[argc - 2];
+ else
+ allow_usage(un, B_FALSE,
+ gettext("wrong number of parameters\n"));
+
+ return (argv[argc - 1]);
+}
+
+static void
+parse_allow_args(int argc, char **argv, boolean_t un, struct allow_opts *opts)
+{
+ int uge_sum = opts->user + opts->group + opts->everyone;
+ int csuge_sum = opts->create + opts->set + uge_sum;
+ int ldcsuge_sum = csuge_sum + opts->local + opts->descend;
+ int all_sum = un ? ldcsuge_sum + opts->recursive : ldcsuge_sum;
+
+ if (uge_sum > 1)
+ allow_usage(un, B_FALSE,
+ gettext("-u, -g, and -e are mutually exclusive\n"));
+
+ if (opts->prt_usage) {
+ if (argc == 0 && all_sum == 0)
+ allow_usage(un, B_TRUE, NULL);
+ else
+ usage(B_FALSE);
+ }
+
+ if (opts->set) {
+ if (csuge_sum > 1)
+ allow_usage(un, B_FALSE,
+ gettext("invalid options combined with -s\n"));
+
+ opts->dataset = munge_args(argc, argv, un, 3, &opts->perms);
+ if (argv[0][0] != '@')
+ allow_usage(un, B_FALSE,
+ gettext("invalid set name: missing '@' prefix\n"));
+ opts->who = argv[0];
+ } else if (opts->create) {
+ if (ldcsuge_sum > 1)
+ allow_usage(un, B_FALSE,
+ gettext("invalid options combined with -c\n"));
+ opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
+ } else if (opts->everyone) {
+ if (csuge_sum > 1)
+ allow_usage(un, B_FALSE,
+ gettext("invalid options combined with -e\n"));
+ opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
+ } else if (uge_sum == 0 && argc > 0 && strcmp(argv[0], "everyone")
+ == 0) {
+ opts->everyone = B_TRUE;
+ argc--;
+ argv++;
+ opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
+ } else if (argc == 1 && !un) {
+ opts->prt_perms = B_TRUE;
+ opts->dataset = argv[argc-1];
+ } else {
+ opts->dataset = munge_args(argc, argv, un, 3, &opts->perms);
+ opts->who = argv[0];
+ }
+
+ if (!opts->local && !opts->descend) {
+ opts->local = B_TRUE;
+ opts->descend = B_TRUE;
+ }
+}
+
+static void
+store_allow_perm(zfs_deleg_who_type_t type, boolean_t local, boolean_t descend,
+ const char *who, char *perms, nvlist_t *top_nvl)
+{
+ int i;
+ char ld[2] = { '\0', '\0' };
+ char who_buf[MAXNAMELEN + 32];
+ char base_type = '\0';
+ char set_type = '\0';
+ nvlist_t *base_nvl = NULL;
+ nvlist_t *set_nvl = NULL;
+ nvlist_t *nvl;
+
+ if (nvlist_alloc(&base_nvl, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+ if (nvlist_alloc(&set_nvl, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+
+ switch (type) {
+ case ZFS_DELEG_NAMED_SET_SETS:
+ case ZFS_DELEG_NAMED_SET:
+ set_type = ZFS_DELEG_NAMED_SET_SETS;
+ base_type = ZFS_DELEG_NAMED_SET;
+ ld[0] = ZFS_DELEG_NA;
+ break;
+ case ZFS_DELEG_CREATE_SETS:
+ case ZFS_DELEG_CREATE:
+ set_type = ZFS_DELEG_CREATE_SETS;
+ base_type = ZFS_DELEG_CREATE;
+ ld[0] = ZFS_DELEG_NA;
+ break;
+ case ZFS_DELEG_USER_SETS:
+ case ZFS_DELEG_USER:
+ set_type = ZFS_DELEG_USER_SETS;
+ base_type = ZFS_DELEG_USER;
+ if (local)
+ ld[0] = ZFS_DELEG_LOCAL;
+ if (descend)
+ ld[1] = ZFS_DELEG_DESCENDENT;
+ break;
+ case ZFS_DELEG_GROUP_SETS:
+ case ZFS_DELEG_GROUP:
+ set_type = ZFS_DELEG_GROUP_SETS;
+ base_type = ZFS_DELEG_GROUP;
+ if (local)
+ ld[0] = ZFS_DELEG_LOCAL;
+ if (descend)
+ ld[1] = ZFS_DELEG_DESCENDENT;
+ break;
+ case ZFS_DELEG_EVERYONE_SETS:
+ case ZFS_DELEG_EVERYONE:
+ set_type = ZFS_DELEG_EVERYONE_SETS;
+ base_type = ZFS_DELEG_EVERYONE;
+ if (local)
+ ld[0] = ZFS_DELEG_LOCAL;
+ if (descend)
+ ld[1] = ZFS_DELEG_DESCENDENT;
+ break;
+
+ default:
+ assert(set_type != '\0' && base_type != '\0');
+ }
+
+ if (perms != NULL) {
+ char *curr = perms;
+ char *end = curr + strlen(perms);
+
+ while (curr < end) {
+ char *delim = strchr(curr, ',');
+ if (delim == NULL)
+ delim = end;
+ else
+ *delim = '\0';
+
+ if (curr[0] == '@')
+ nvl = set_nvl;
+ else
+ nvl = base_nvl;
+
+ (void) nvlist_add_boolean(nvl, curr);
+ if (delim != end)
+ *delim = ',';
+ curr = delim + 1;
+ }
+
+ for (i = 0; i < 2; i++) {
+ char locality = ld[i];
+ if (locality == 0)
+ continue;
+
+ if (!nvlist_empty(base_nvl)) {
+ if (who != NULL)
+ (void) snprintf(who_buf,
+ sizeof (who_buf), "%c%c$%s",
+ base_type, locality, who);
+ else
+ (void) snprintf(who_buf,
+ sizeof (who_buf), "%c%c$",
+ base_type, locality);
+
+ (void) nvlist_add_nvlist(top_nvl, who_buf,
+ base_nvl);
+ }
+
+
+ if (!nvlist_empty(set_nvl)) {
+ if (who != NULL)
+ (void) snprintf(who_buf,
+ sizeof (who_buf), "%c%c$%s",
+ set_type, locality, who);
+ else
+ (void) snprintf(who_buf,
+ sizeof (who_buf), "%c%c$",
+ set_type, locality);
+
+ (void) nvlist_add_nvlist(top_nvl, who_buf,
+ set_nvl);
+ }
+ }
+ } else {
+ for (i = 0; i < 2; i++) {
+ char locality = ld[i];
+ if (locality == 0)
+ continue;
+
+ if (who != NULL)
+ (void) snprintf(who_buf, sizeof (who_buf),
+ "%c%c$%s", base_type, locality, who);
+ else
+ (void) snprintf(who_buf, sizeof (who_buf),
+ "%c%c$", base_type, locality);
+ (void) nvlist_add_boolean(top_nvl, who_buf);
+
+ if (who != NULL)
+ (void) snprintf(who_buf, sizeof (who_buf),
+ "%c%c$%s", set_type, locality, who);
+ else
+ (void) snprintf(who_buf, sizeof (who_buf),
+ "%c%c$", set_type, locality);
+ (void) nvlist_add_boolean(top_nvl, who_buf);
+ }
+ }
+}
+
+static int
+construct_fsacl_list(boolean_t un, struct allow_opts *opts, nvlist_t **nvlp)
+{
+ if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+
+ if (opts->set) {
+ store_allow_perm(ZFS_DELEG_NAMED_SET, opts->local,
+ opts->descend, opts->who, opts->perms, *nvlp);
+ } else if (opts->create) {
+ store_allow_perm(ZFS_DELEG_CREATE, opts->local,
+ opts->descend, NULL, opts->perms, *nvlp);
+ } else if (opts->everyone) {
+ store_allow_perm(ZFS_DELEG_EVERYONE, opts->local,
+ opts->descend, NULL, opts->perms, *nvlp);
+ } else {
+ char *curr = opts->who;
+ char *end = curr + strlen(curr);
+
+ while (curr < end) {
+ const char *who;
+ zfs_deleg_who_type_t who_type = ZFS_DELEG_WHO_UNKNOWN;
+ char *endch;
+ char *delim = strchr(curr, ',');
+ char errbuf[256];
+ char id[64];
+ struct passwd *p = NULL;
+ struct group *g = NULL;
+
+ uid_t rid;
+ if (delim == NULL)
+ delim = end;
+ else
+ *delim = '\0';
+
+ rid = (uid_t)strtol(curr, &endch, 0);
+ if (opts->user) {
+ who_type = ZFS_DELEG_USER;
+ if (*endch != '\0')
+ p = getpwnam(curr);
+ else
+ p = getpwuid(rid);
+
+ if (p != NULL)
+ rid = p->pw_uid;
+ else {
+ (void) snprintf(errbuf, 256, gettext(
+ "invalid user %s"), curr);
+ allow_usage(un, B_TRUE, errbuf);
+ }
+ } else if (opts->group) {
+ who_type = ZFS_DELEG_GROUP;
+ if (*endch != '\0')
+ g = getgrnam(curr);
+ else
+ g = getgrgid(rid);
+
+ if (g != NULL)
+ rid = g->gr_gid;
+ else {
+ (void) snprintf(errbuf, 256, gettext(
+ "invalid group %s"), curr);
+ allow_usage(un, B_TRUE, errbuf);
+ }
+ } else {
+ if (*endch != '\0') {
+ p = getpwnam(curr);
+ } else {
+ p = getpwuid(rid);
+ }
+
+ if (p == NULL) {
+ if (*endch != '\0') {
+ g = getgrnam(curr);
+ } else {
+ g = getgrgid(rid);
+ }
+ }
+
+ if (p != NULL) {
+ who_type = ZFS_DELEG_USER;
+ rid = p->pw_uid;
+ } else if (g != NULL) {
+ who_type = ZFS_DELEG_GROUP;
+ rid = g->gr_gid;
+ } else {
+ (void) snprintf(errbuf, 256, gettext(
+ "invalid user/group %s"), curr);
+ allow_usage(un, B_TRUE, errbuf);
+ }
+ }
+
+ (void) sprintf(id, "%u", rid);
+ who = id;
+
+ store_allow_perm(who_type, opts->local,
+ opts->descend, who, opts->perms, *nvlp);
+ curr = delim + 1;
+ }
+ }
+
+ return (0);
+}
+
+static void
+print_set_creat_perms(uu_avl_t *who_avl)
+{
+ const char *sc_title[] = {
+ gettext("Permission sets:\n"),
+ gettext("Create time permissions:\n"),
+ NULL
+ };
+ const char **title_ptr = sc_title;
+ who_perm_node_t *who_node = NULL;
+ int prev_weight = -1;
+
+ for (who_node = uu_avl_first(who_avl); who_node != NULL;
+ who_node = uu_avl_next(who_avl, who_node)) {
+ uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl;
+ zfs_deleg_who_type_t who_type = who_node->who_perm.who_type;
+ const char *who_name = who_node->who_perm.who_name;
+ int weight = who_type2weight(who_type);
+ boolean_t first = B_TRUE;
+ deleg_perm_node_t *deleg_node;
+
+ if (prev_weight != weight) {
+ (void) printf(*title_ptr++);
+ prev_weight = weight;
+ }
+
+ if (who_name == NULL || strnlen(who_name, 1) == 0)
+ (void) printf("\t");
+ else
+ (void) printf("\t%s ", who_name);
+
+ for (deleg_node = uu_avl_first(avl); deleg_node != NULL;
+ deleg_node = uu_avl_next(avl, deleg_node)) {
+ if (first) {
+ (void) printf("%s",
+ deleg_node->dpn_perm.dp_name);
+ first = B_FALSE;
+ } else
+ (void) printf(",%s",
+ deleg_node->dpn_perm.dp_name);
+ }
+
+ (void) printf("\n");
+ }
+}
+
+static void
+print_uge_deleg_perms(uu_avl_t *who_avl, boolean_t local, boolean_t descend,
+ const char *title)
+{
+ who_perm_node_t *who_node = NULL;
+ boolean_t prt_title = B_TRUE;
+ uu_avl_walk_t *walk;
+
+ if ((walk = uu_avl_walk_start(who_avl, UU_WALK_ROBUST)) == NULL)
+ nomem();
+
+ while ((who_node = uu_avl_walk_next(walk)) != NULL) {
+ const char *who_name = who_node->who_perm.who_name;
+ const char *nice_who_name = who_node->who_perm.who_ug_name;
+ uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl;
+ zfs_deleg_who_type_t who_type = who_node->who_perm.who_type;
+ char delim = ' ';
+ deleg_perm_node_t *deleg_node;
+ boolean_t prt_who = B_TRUE;
+
+ for (deleg_node = uu_avl_first(avl);
+ deleg_node != NULL;
+ deleg_node = uu_avl_next(avl, deleg_node)) {
+ if (local != deleg_node->dpn_perm.dp_local ||
+ descend != deleg_node->dpn_perm.dp_descend)
+ continue;
+
+ if (prt_who) {
+ const char *who = NULL;
+ if (prt_title) {
+ prt_title = B_FALSE;
+ (void) printf(title);
+ }
+
+ switch (who_type) {
+ case ZFS_DELEG_USER_SETS:
+ case ZFS_DELEG_USER:
+ who = gettext("user");
+ if (nice_who_name)
+ who_name = nice_who_name;
+ break;
+ case ZFS_DELEG_GROUP_SETS:
+ case ZFS_DELEG_GROUP:
+ who = gettext("group");
+ if (nice_who_name)
+ who_name = nice_who_name;
+ break;
+ case ZFS_DELEG_EVERYONE_SETS:
+ case ZFS_DELEG_EVERYONE:
+ who = gettext("everyone");
+ who_name = NULL;
+ break;
+
+ default:
+ assert(who != NULL);
+ }
+
+ prt_who = B_FALSE;
+ if (who_name == NULL)
+ (void) printf("\t%s", who);
+ else
+ (void) printf("\t%s %s", who, who_name);
+ }
+
+ (void) printf("%c%s", delim,
+ deleg_node->dpn_perm.dp_name);
+ delim = ',';
+ }
+
+ if (!prt_who)
+ (void) printf("\n");
+ }
+
+ uu_avl_walk_end(walk);
+}
+
+static void
+print_fs_perms(fs_perm_set_t *fspset)
+{
+ fs_perm_node_t *node = NULL;
+ char buf[MAXNAMELEN + 32];
+ const char *dsname = buf;
+
+ for (node = uu_list_first(fspset->fsps_list); node != NULL;
+ node = uu_list_next(fspset->fsps_list, node)) {
+ uu_avl_t *sc_avl = node->fspn_fsperm.fsp_sc_avl;
+ uu_avl_t *uge_avl = node->fspn_fsperm.fsp_uge_avl;
+ int left = 0;
+
+ (void) snprintf(buf, sizeof (buf),
+ gettext("---- Permissions on %s "),
+ node->fspn_fsperm.fsp_name);
+ (void) printf(dsname);
+ left = 70 - strlen(buf);
+ while (left-- > 0)
+ (void) printf("-");
+ (void) printf("\n");
+
+ print_set_creat_perms(sc_avl);
+ print_uge_deleg_perms(uge_avl, B_TRUE, B_FALSE,
+ gettext("Local permissions:\n"));
+ print_uge_deleg_perms(uge_avl, B_FALSE, B_TRUE,
+ gettext("Descendent permissions:\n"));
+ print_uge_deleg_perms(uge_avl, B_TRUE, B_TRUE,
+ gettext("Local+Descendent permissions:\n"));
+ }
+}
+
+static fs_perm_set_t fs_perm_set = { NULL, NULL, NULL, NULL };
+
+struct deleg_perms {
+ boolean_t un;
+ nvlist_t *nvl;
+};
+
+static int
+set_deleg_perms(zfs_handle_t *zhp, void *data)
+{
+ struct deleg_perms *perms = (struct deleg_perms *)data;
+ zfs_type_t zfs_type = zfs_get_type(zhp);
+
+ if (zfs_type != ZFS_TYPE_FILESYSTEM && zfs_type != ZFS_TYPE_VOLUME)
+ return (0);
+
+ return (zfs_set_fsacl(zhp, perms->un, perms->nvl));
+}
+
+static int
+zfs_do_allow_unallow_impl(int argc, char **argv, boolean_t un)
+{
+ zfs_handle_t *zhp;
+ nvlist_t *perm_nvl = NULL;
+ nvlist_t *update_perm_nvl = NULL;
+ int error = 1;
+ int c;
+ struct allow_opts opts = { 0 };
+
+ const char *optstr = un ? "ldugecsrh" : "ldugecsh";
+
+ /* check opts */
+ while ((c = getopt(argc, argv, optstr)) != -1) {
+ switch (c) {
+ case 'l':
+ opts.local = B_TRUE;
+ break;
+ case 'd':
+ opts.descend = B_TRUE;
+ break;
+ case 'u':
+ opts.user = B_TRUE;
+ break;
+ case 'g':
+ opts.group = B_TRUE;
+ break;
+ case 'e':
+ opts.everyone = B_TRUE;
+ break;
+ case 's':
+ opts.set = B_TRUE;
+ break;
+ case 'c':
+ opts.create = B_TRUE;
+ break;
+ case 'r':
+ opts.recursive = B_TRUE;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case 'h':
+ opts.prt_usage = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check arguments */
+ parse_allow_args(argc, argv, un, &opts);
+
+ /* try to open the dataset */
+ if ((zhp = zfs_open(g_zfs, opts.dataset, ZFS_TYPE_FILESYSTEM |
+ ZFS_TYPE_VOLUME)) == NULL) {
+ (void) fprintf(stderr, "Failed to open dataset: %s\n",
+ opts.dataset);
+ return (-1);
+ }
+
+ if (zfs_get_fsacl(zhp, &perm_nvl) != 0)
+ goto cleanup2;
+
+ fs_perm_set_init(&fs_perm_set);
+ if (parse_fs_perm_set(&fs_perm_set, perm_nvl) != 0) {
+ (void) fprintf(stderr, "Failed to parse fsacl permissions\n");
+ goto cleanup1;
+ }
+
+ if (opts.prt_perms)
+ print_fs_perms(&fs_perm_set);
+ else {
+ (void) construct_fsacl_list(un, &opts, &update_perm_nvl);
+ if (zfs_set_fsacl(zhp, un, update_perm_nvl) != 0)
+ goto cleanup0;
+
+ if (un && opts.recursive) {
+ struct deleg_perms data = { un, update_perm_nvl };
+ if (zfs_iter_filesystems(zhp, set_deleg_perms,
+ &data) != 0)
+ goto cleanup0;
+ }
+ }
+
+ error = 0;
+
+cleanup0:
+ nvlist_free(perm_nvl);
+ nvlist_free(update_perm_nvl);
+cleanup1:
+ fs_perm_set_fini(&fs_perm_set);
+cleanup2:
+ zfs_close(zhp);
+
+ return (error);
+}
+
+static int
+zfs_do_allow(int argc, char **argv)
+{
+ return (zfs_do_allow_unallow_impl(argc, argv, B_FALSE));
+}
+
+static int
+zfs_do_unallow(int argc, char **argv)
+{
+ return (zfs_do_allow_unallow_impl(argc, argv, B_TRUE));
+}
+
+static int
+zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
+{
+ int errors = 0;
+ int i;
+ const char *tag;
+ boolean_t recursive = B_FALSE;
+ const char *opts = holding ? "rt" : "r";
+ int c;
+
+ /* check options */
+ while ((c = getopt(argc, argv, opts)) != -1) {
+ switch (c) {
+ case 'r':
+ recursive = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 2)
+ usage(B_FALSE);
+
+ tag = argv[0];
+ --argc;
+ ++argv;
+
+ if (holding && tag[0] == '.') {
+ /* tags starting with '.' are reserved for libzfs */
+ (void) fprintf(stderr, gettext("tag may not start with '.'\n"));
+ usage(B_FALSE);
+ }
+
+ for (i = 0; i < argc; ++i) {
+ zfs_handle_t *zhp;
+ char parent[ZFS_MAX_DATASET_NAME_LEN];
+ const char *delim;
+ char *path = argv[i];
+
+ delim = strchr(path, '@');
+ if (delim == NULL) {
+ (void) fprintf(stderr,
+ gettext("'%s' is not a snapshot\n"), path);
+ ++errors;
+ continue;
+ }
+ (void) strncpy(parent, path, delim - path);
+ parent[delim - path] = '\0';
+
+ zhp = zfs_open(g_zfs, parent,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL) {
+ ++errors;
+ continue;
+ }
+ if (holding) {
+ if (zfs_hold(zhp, delim+1, tag, recursive, -1) != 0)
+ ++errors;
+ } else {
+ if (zfs_release(zhp, delim+1, tag, recursive) != 0)
+ ++errors;
+ }
+ zfs_close(zhp);
+ }
+
+ return (errors != 0);
+}
+
+/*
+ * zfs hold [-r] [-t] <tag> <snap> ...
+ *
+ * -r Recursively hold
+ *
+ * Apply a user-hold with the given tag to the list of snapshots.
+ */
+static int
+zfs_do_hold(int argc, char **argv)
+{
+ return (zfs_do_hold_rele_impl(argc, argv, B_TRUE));
+}
+
+/*
+ * zfs release [-r] <tag> <snap> ...
+ *
+ * -r Recursively release
+ *
+ * Release a user-hold with the given tag from the list of snapshots.
+ */
+static int
+zfs_do_release(int argc, char **argv)
+{
+ return (zfs_do_hold_rele_impl(argc, argv, B_FALSE));
+}
+
+typedef struct holds_cbdata {
+ boolean_t cb_recursive;
+ const char *cb_snapname;
+ nvlist_t **cb_nvlp;
+ size_t cb_max_namelen;
+ size_t cb_max_taglen;
+} holds_cbdata_t;
+
+#define STRFTIME_FMT_STR "%a %b %e %k:%M %Y"
+#define DATETIME_BUF_LEN (32)
+/*
+ *
+ */
+static void
+print_holds(boolean_t scripted, boolean_t literal, size_t nwidth,
+ size_t tagwidth, nvlist_t *nvl)
+{
+ int i;
+ nvpair_t *nvp = NULL;
+ char *hdr_cols[] = { "NAME", "TAG", "TIMESTAMP" };
+ const char *col;
+
+ if (!scripted) {
+ for (i = 0; i < 3; i++) {
+ col = gettext(hdr_cols[i]);
+ if (i < 2)
+ (void) printf("%-*s ", i ? tagwidth : nwidth,
+ col);
+ else
+ (void) printf("%s\n", col);
+ }
+ }
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ char *zname = nvpair_name(nvp);
+ nvlist_t *nvl2;
+ nvpair_t *nvp2 = NULL;
+ (void) nvpair_value_nvlist(nvp, &nvl2);
+ while ((nvp2 = nvlist_next_nvpair(nvl2, nvp2)) != NULL) {
+ char tsbuf[DATETIME_BUF_LEN];
+ char *tagname = nvpair_name(nvp2);
+ uint64_t val = 0;
+ time_t time;
+ struct tm t;
+
+ (void) nvpair_value_uint64(nvp2, &val);
+ if (literal)
+ snprintf(tsbuf, DATETIME_BUF_LEN, "%llu", val);
+ else {
+ time = (time_t)val;
+ (void) localtime_r(&time, &t);
+ (void) strftime(tsbuf, DATETIME_BUF_LEN,
+ gettext(STRFTIME_FMT_STR), &t);
+ }
+
+ if (scripted) {
+ (void) printf("%s\t%s\t%s\n", zname,
+ tagname, tsbuf);
+ } else {
+ (void) printf("%-*s %-*s %s\n", nwidth,
+ zname, tagwidth, tagname, tsbuf);
+ }
+ }
+ }
+}
+
+/*
+ * Generic callback function to list a dataset or snapshot.
+ */
+static int
+holds_callback(zfs_handle_t *zhp, void *data)
+{
+ holds_cbdata_t *cbp = data;
+ nvlist_t *top_nvl = *cbp->cb_nvlp;
+ nvlist_t *nvl = NULL;
+ nvpair_t *nvp = NULL;
+ const char *zname = zfs_get_name(zhp);
+ size_t znamelen = strlen(zname);
+
+ if (cbp->cb_recursive && cbp->cb_snapname != NULL) {
+ const char *snapname;
+ char *delim = strchr(zname, '@');
+ if (delim == NULL)
+ return (0);
+
+ snapname = delim + 1;
+ if (strcmp(cbp->cb_snapname, snapname))
+ return (0);
+ }
+
+ if (zfs_get_holds(zhp, &nvl) != 0)
+ return (-1);
+
+ if (znamelen > cbp->cb_max_namelen)
+ cbp->cb_max_namelen = znamelen;
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ const char *tag = nvpair_name(nvp);
+ size_t taglen = strlen(tag);
+ if (taglen > cbp->cb_max_taglen)
+ cbp->cb_max_taglen = taglen;
+ }
+
+ return (nvlist_add_nvlist(top_nvl, zname, nvl));
+}
+
+/*
+ * zfs holds [-Hp] [-r | -d max] <dataset|snap> ...
+ *
+ * -H Suppress header output
+ * -p Output literal values
+ * -r Recursively search for holds
+ * -d max Limit depth of recursive search
+ */
+static int
+zfs_do_holds(int argc, char **argv)
+{
+ int errors = 0;
+ int c;
+ int i;
+ boolean_t scripted = B_FALSE;
+ boolean_t literal = B_FALSE;
+ boolean_t recursive = B_FALSE;
+ const char *opts = "d:rHp";
+ nvlist_t *nvl;
+
+ int types = ZFS_TYPE_SNAPSHOT;
+ holds_cbdata_t cb = { 0 };
+
+ int limit = 0;
+ int ret = 0;
+ int flags = 0;
+
+ /* check options */
+ while ((c = getopt(argc, argv, opts)) != -1) {
+ switch (c) {
+ case 'd':
+ limit = parse_depth(optarg, &flags);
+ recursive = B_TRUE;
+ break;
+ case 'r':
+ recursive = B_TRUE;
+ break;
+ case 'H':
+ scripted = B_TRUE;
+ break;
+ case 'p':
+ literal = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ if (recursive) {
+ types |= ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
+ flags |= ZFS_ITER_RECURSE;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 1)
+ usage(B_FALSE);
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+
+ for (i = 0; i < argc; ++i) {
+ char *snapshot = argv[i];
+ const char *delim;
+ const char *snapname = NULL;
+
+ delim = strchr(snapshot, '@');
+ if (delim != NULL) {
+ snapname = delim + 1;
+ if (recursive)
+ snapshot[delim - snapshot] = '\0';
+ }
+
+ cb.cb_recursive = recursive;
+ cb.cb_snapname = snapname;
+ cb.cb_nvlp = &nvl;
+
+ /*
+ * 1. collect holds data, set format options
+ */
+ ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit,
+ holds_callback, &cb);
+ if (ret != 0)
+ ++errors;
+ }
+
+ /*
+ * 2. print holds data
+ */
+ print_holds(scripted, literal, cb.cb_max_namelen, cb.cb_max_taglen,
+ nvl);
+
+ if (nvlist_empty(nvl))
+ (void) printf(gettext("no datasets available\n"));
+
+ nvlist_free(nvl);
+
+ return (0 != errors);
+}
+
+#define CHECK_SPINNER 30
+#define SPINNER_TIME 3 /* seconds */
+#define MOUNT_TIME 1 /* seconds */
+
+typedef struct get_all_state {
+ boolean_t ga_verbose;
+ get_all_cb_t *ga_cbp;
+} get_all_state_t;
+
+static int
+get_one_dataset(zfs_handle_t *zhp, void *data)
+{
+ static char *spin[] = { "-", "\\", "|", "/" };
+ static int spinval = 0;
+ static int spincheck = 0;
+ static time_t last_spin_time = (time_t)0;
+ get_all_state_t *state = data;
+ zfs_type_t type = zfs_get_type(zhp);
+
+ if (state->ga_verbose) {
+ if (--spincheck < 0) {
+ time_t now = time(NULL);
+ if (last_spin_time + SPINNER_TIME < now) {
+ update_progress(spin[spinval++ % 4]);
+ last_spin_time = now;
+ }
+ spincheck = CHECK_SPINNER;
+ }
+ }
+
+ /*
+ * Interate over any nested datasets.
+ */
+ if (zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) {
+ zfs_close(zhp);
+ return (1);
+ }
+
+ /*
+ * Skip any datasets whose type does not match.
+ */
+ if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+ libzfs_add_handle(state->ga_cbp, zhp);
+ assert(state->ga_cbp->cb_used <= state->ga_cbp->cb_alloc);
+
+ return (0);
+}
+
+static void
+get_all_datasets(get_all_cb_t *cbp, boolean_t verbose)
+{
+ get_all_state_t state = {
+ .ga_verbose = verbose,
+ .ga_cbp = cbp
+ };
+
+ if (verbose)
+ set_progress_header(gettext("Reading ZFS config"));
+ (void) zfs_iter_root(g_zfs, get_one_dataset, &state);
+
+ if (verbose)
+ finish_progress(gettext("done."));
+}
+
+/*
+ * Generic callback for sharing or mounting filesystems. Because the code is so
+ * similar, we have a common function with an extra parameter to determine which
+ * mode we are using.
+ */
+typedef enum { OP_SHARE, OP_MOUNT } share_mount_op_t;
+
+typedef struct share_mount_state {
+ share_mount_op_t sm_op;
+ boolean_t sm_verbose;
+ int sm_flags;
+ char *sm_options;
+ char *sm_proto; /* only valid for OP_SHARE */
+ pthread_mutex_t sm_lock; /* protects the remaining fields */
+ uint_t sm_total; /* number of filesystems to process */
+ uint_t sm_done; /* number of filesystems processed */
+ int sm_status; /* -1 if any of the share/mount operations failed */
+} share_mount_state_t;
+
+/*
+ * Share or mount a dataset.
+ */
+static int
+share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
+ boolean_t explicit, const char *options)
+{
+ char mountpoint[ZFS_MAXPROPLEN];
+ char shareopts[ZFS_MAXPROPLEN];
+ char smbshareopts[ZFS_MAXPROPLEN];
+ const char *cmdname = op == OP_SHARE ? "share" : "mount";
+ struct mnttab mnt;
+ uint64_t zoned, canmount;
+ boolean_t shared_nfs, shared_smb;
+
+ assert(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM);
+
+ /*
+ * Check to make sure we can mount/share this dataset. If we
+ * are in the global zone and the filesystem is exported to a
+ * local zone, or if we are in a local zone and the
+ * filesystem is not exported, then it is an error.
+ */
+ zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
+
+ if (zoned && getzoneid() == GLOBAL_ZONEID) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "dataset is exported to a local zone\n"), cmdname,
+ zfs_get_name(zhp));
+ return (1);
+
+ } else if (!zoned && getzoneid() != GLOBAL_ZONEID) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "permission denied\n"), cmdname,
+ zfs_get_name(zhp));
+ return (1);
+ }
+
+ /*
+ * Ignore any filesystems which don't apply to us. This
+ * includes those with a legacy mountpoint, or those with
+ * legacy share options.
+ */
+ verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
+ sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
+ sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts,
+ sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0);
+
+ if (op == OP_SHARE && strcmp(shareopts, "off") == 0 &&
+ strcmp(smbshareopts, "off") == 0) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot share '%s': "
+ "legacy share\n"), zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("to "
+ "share this filesystem set "
+ "sharenfs property on\n"));
+ return (1);
+ }
+
+ /*
+ * We cannot share or mount legacy filesystems. If the
+ * shareopts is non-legacy but the mountpoint is legacy, we
+ * treat it as a legacy share.
+ */
+ if (strcmp(mountpoint, "legacy") == 0) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "legacy mountpoint\n"), cmdname, zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use %s(8) to "
+ "%s this filesystem\n"), cmdname, cmdname);
+ return (1);
+ }
+
+ if (strcmp(mountpoint, "none") == 0) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': no "
+ "mountpoint set\n"), cmdname, zfs_get_name(zhp));
+ return (1);
+ }
+
+ /*
+ * canmount explicit outcome
+ * on no pass through
+ * on yes pass through
+ * off no return 0
+ * off yes display error, return 1
+ * noauto no return 0
+ * noauto yes pass through
+ */
+ canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
+ if (canmount == ZFS_CANMOUNT_OFF) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "'canmount' property is set to 'off'\n"), cmdname,
+ zfs_get_name(zhp));
+ return (1);
+ } else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
+ return (0);
+ }
+
+ /*
+ * If this filesystem is inconsistent and has a receive resume
+ * token, we can not mount it.
+ */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
+ zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+ NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "Contains partially-completed state from "
+ "\"zfs receive -r\", which can be resumed with "
+ "\"zfs send -t\"\n"),
+ cmdname, zfs_get_name(zhp));
+ return (1);
+ }
+
+ /*
+ * At this point, we have verified that the mountpoint and/or
+ * shareopts are appropriate for auto management. If the
+ * filesystem is already mounted or shared, return (failing
+ * for explicit requests); otherwise mount or share the
+ * filesystem.
+ */
+ switch (op) {
+ case OP_SHARE:
+
+ shared_nfs = zfs_is_shared_nfs(zhp, NULL);
+ shared_smb = zfs_is_shared_smb(zhp, NULL);
+
+ if ((shared_nfs && shared_smb) ||
+ (shared_nfs && strcmp(shareopts, "on") == 0 &&
+ strcmp(smbshareopts, "off") == 0) ||
+ (shared_smb && strcmp(smbshareopts, "on") == 0 &&
+ strcmp(shareopts, "off") == 0)) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot share "
+ "'%s': filesystem already shared\n"),
+ zfs_get_name(zhp));
+ return (1);
+ }
+
+ if (!zfs_is_mounted(zhp, NULL) &&
+ zfs_mount(zhp, NULL, 0) != 0)
+ return (1);
+
+ if (protocol == NULL) {
+ if (zfs_shareall(zhp) != 0)
+ return (1);
+ } else if (strcmp(protocol, "nfs") == 0) {
+ if (zfs_share_nfs(zhp))
+ return (1);
+ } else if (strcmp(protocol, "smb") == 0) {
+ if (zfs_share_smb(zhp))
+ return (1);
+ } else {
+ (void) fprintf(stderr, gettext("cannot share "
+ "'%s': invalid share type '%s' "
+ "specified\n"),
+ zfs_get_name(zhp), protocol);
+ return (1);
+ }
+
+ break;
+
+ case OP_MOUNT:
+ if (options == NULL)
+ mnt.mnt_mntopts = "";
+ else
+ mnt.mnt_mntopts = (char *)options;
+
+ if (!hasmntopt(&mnt, MNTOPT_REMOUNT) &&
+ zfs_is_mounted(zhp, NULL)) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot mount "
+ "'%s': filesystem already mounted\n"),
+ zfs_get_name(zhp));
+ return (1);
+ }
+
+ if (zfs_mount(zhp, options, flags) != 0)
+ return (1);
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * Reports progress in the form "(current/total)". Not thread-safe.
+ */
+static void
+report_mount_progress(int current, int total)
+{
+ static time_t last_progress_time = 0;
+ time_t now = time(NULL);
+ char info[32];
+
+ /* display header if we're here for the first time */
+ if (current == 1) {
+ set_progress_header(gettext("Mounting ZFS filesystems"));
+ } else if (current != total && last_progress_time + MOUNT_TIME >= now) {
+ /* too soon to report again */
+ return;
+ }
+
+ last_progress_time = now;
+
+ (void) sprintf(info, "(%d/%d)", current, total);
+
+ if (current == total)
+ finish_progress(info);
+ else
+ update_progress(info);
+}
+
+/*
+ * zfs_foreach_mountpoint() callback that mounts or shares on filesystem and
+ * updates the progress meter
+ */
+static int
+share_mount_one_cb(zfs_handle_t *zhp, void *arg)
+{
+ share_mount_state_t *sms = arg;
+ int ret;
+
+ ret = share_mount_one(zhp, sms->sm_op, sms->sm_flags, sms->sm_proto,
+ B_FALSE, sms->sm_options);
+
+ pthread_mutex_lock(&sms->sm_lock);
+ if (ret != 0)
+ sms->sm_status = ret;
+ sms->sm_done++;
+ if (sms->sm_verbose)
+ report_mount_progress(sms->sm_done, sms->sm_total);
+ pthread_mutex_unlock(&sms->sm_lock);
+ return (ret);
+}
+
+static void
+append_options(char *mntopts, char *newopts)
+{
+ int len = strlen(mntopts);
+
+ /* original length plus new string to append plus 1 for the comma */
+ if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) {
+ (void) fprintf(stderr, gettext("the opts argument for "
+ "'%c' option is too long (more than %d chars)\n"),
+ "-o", MNT_LINE_MAX);
+ usage(B_FALSE);
+ }
+
+ if (*mntopts)
+ mntopts[len++] = ',';
+
+ (void) strcpy(&mntopts[len], newopts);
+}
+
+static int
+share_mount(int op, int argc, char **argv)
+{
+ int do_all = 0;
+ boolean_t verbose = B_FALSE;
+ int c, ret = 0;
+ char *options = NULL;
+ int flags = 0;
+
+ /* check options */
+ while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:O" : "a"))
+ != -1) {
+ switch (c) {
+ case 'a':
+ do_all = 1;
+ break;
+ case 'v':
+ verbose = B_TRUE;
+ break;
+ case 'o':
+ if (*optarg == '\0') {
+ (void) fprintf(stderr, gettext("empty mount "
+ "options (-o) specified\n"));
+ usage(B_FALSE);
+ }
+
+ if (options == NULL)
+ options = safe_malloc(MNT_LINE_MAX + 1);
+
+ /* option validation is done later */
+ append_options(options, optarg);
+ break;
+
+ case 'O':
+ warnx("no overlay mounts support on FreeBSD, ignoring");
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (do_all) {
+ char *protocol = NULL;
+
+ if (op == OP_SHARE && argc > 0) {
+ if (strcmp(argv[0], "nfs") != 0 &&
+ strcmp(argv[0], "smb") != 0) {
+ (void) fprintf(stderr, gettext("share type "
+ "must be 'nfs' or 'smb'\n"));
+ usage(B_FALSE);
+ }
+ protocol = argv[0];
+ argc--;
+ argv++;
+ }
+
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ start_progress_timer();
+ get_all_cb_t cb = { 0 };
+ get_all_datasets(&cb, verbose);
+
+ if (cb.cb_used == 0) {
+ if (options != NULL)
+ free(options);
+ return (0);
+ }
+
+#ifdef illumos
+ if (op == OP_SHARE) {
+ sa_init_selective_arg_t sharearg;
+ sharearg.zhandle_arr = cb.cb_handles;
+ sharearg.zhandle_len = cb.cb_used;
+ if ((ret = zfs_init_libshare_arg(g_zfs,
+ SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != SA_OK) {
+ (void) fprintf(stderr, gettext(
+ "Could not initialize libshare, %d"), ret);
+ return (ret);
+ }
+ }
+#endif
+ share_mount_state_t share_mount_state = { 0 };
+ share_mount_state.sm_op = op;
+ share_mount_state.sm_verbose = verbose;
+ share_mount_state.sm_flags = flags;
+ share_mount_state.sm_options = options;
+ share_mount_state.sm_proto = protocol;
+ share_mount_state.sm_total = cb.cb_used;
+ pthread_mutex_init(&share_mount_state.sm_lock, NULL);
+
+ /*
+ * libshare isn't mt-safe, so only do the operation in parallel
+ * if we're mounting.
+ */
+ zfs_foreach_mountpoint(g_zfs, cb.cb_handles, cb.cb_used,
+ share_mount_one_cb, &share_mount_state, op == OP_MOUNT);
+ ret = share_mount_state.sm_status;
+
+ for (int i = 0; i < cb.cb_used; i++)
+ zfs_close(cb.cb_handles[i]);
+ free(cb.cb_handles);
+ } else if (argc == 0) {
+ struct mnttab entry;
+
+ if ((op == OP_SHARE) || (options != NULL)) {
+ (void) fprintf(stderr, gettext("missing filesystem "
+ "argument (specify -a for all)\n"));
+ usage(B_FALSE);
+ }
+
+ /*
+ * When mount is given no arguments, go through /etc/mnttab and
+ * display any active ZFS mounts. We hide any snapshots, since
+ * they are controlled automatically.
+ */
+ rewind(mnttab_file);
+ while (getmntent(mnttab_file, &entry) == 0) {
+ if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 ||
+ strchr(entry.mnt_special, '@') != NULL)
+ continue;
+
+ (void) printf("%-30s %s\n", entry.mnt_special,
+ entry.mnt_mountp);
+ }
+
+ } else {
+ zfs_handle_t *zhp;
+
+ if (argc > 1) {
+ (void) fprintf(stderr,
+ gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ if ((zhp = zfs_open(g_zfs, argv[0],
+ ZFS_TYPE_FILESYSTEM)) == NULL) {
+ ret = 1;
+ } else {
+ ret = share_mount_one(zhp, op, flags, NULL, B_TRUE,
+ options);
+ zfs_close(zhp);
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * zfs mount -a [nfs]
+ * zfs mount filesystem
+ *
+ * Mount all filesystems, or mount the given filesystem.
+ */
+static int
+zfs_do_mount(int argc, char **argv)
+{
+ return (share_mount(OP_MOUNT, argc, argv));
+}
+
+/*
+ * zfs share -a [nfs | smb]
+ * zfs share filesystem
+ *
+ * Share all filesystems, or share the given filesystem.
+ */
+static int
+zfs_do_share(int argc, char **argv)
+{
+ return (share_mount(OP_SHARE, argc, argv));
+}
+
+typedef struct unshare_unmount_node {
+ zfs_handle_t *un_zhp;
+ char *un_mountp;
+ uu_avl_node_t un_avlnode;
+} unshare_unmount_node_t;
+
+/* ARGSUSED */
+static int
+unshare_unmount_compare(const void *larg, const void *rarg, void *unused)
+{
+ const unshare_unmount_node_t *l = larg;
+ const unshare_unmount_node_t *r = rarg;
+
+ return (strcmp(l->un_mountp, r->un_mountp));
+}
+
+/*
+ * Convenience routine used by zfs_do_umount() and manual_unmount(). Given an
+ * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem,
+ * and unmount it appropriately.
+ */
+static int
+unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual)
+{
+ zfs_handle_t *zhp;
+ int ret = 0;
+ struct stat64 statbuf;
+ struct extmnttab entry;
+ const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount";
+ ino_t path_inode;
+
+ /*
+ * Search for the path in /etc/mnttab. Rather than looking for the
+ * specific path, which can be fooled by non-standard paths (i.e. ".."
+ * or "//"), we stat() the path and search for the corresponding
+ * (major,minor) device pair.
+ */
+ if (stat64(path, &statbuf) != 0) {
+ (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
+ cmdname, path, strerror(errno));
+ return (1);
+ }
+ path_inode = statbuf.st_ino;
+
+ /*
+ * Search for the given (major,minor) pair in the mount table.
+ */
+#ifdef illumos
+ rewind(mnttab_file);
+ while ((ret = getextmntent(mnttab_file, &entry, 0)) == 0) {
+ if (entry.mnt_major == major(statbuf.st_dev) &&
+ entry.mnt_minor == minor(statbuf.st_dev))
+ break;
+ }
+#else
+ {
+ struct statfs sfs;
+
+ if (statfs(path, &sfs) != 0) {
+ (void) fprintf(stderr, "%s: %s\n", path,
+ strerror(errno));
+ ret = -1;
+ }
+ statfs2mnttab(&sfs, &entry);
+ }
+#endif
+ if (ret != 0) {
+ if (op == OP_SHARE) {
+ (void) fprintf(stderr, gettext("cannot %s '%s': not "
+ "currently mounted\n"), cmdname, path);
+ return (1);
+ }
+ (void) fprintf(stderr, gettext("warning: %s not in mnttab\n"),
+ path);
+ if ((ret = umount2(path, flags)) != 0)
+ (void) fprintf(stderr, gettext("%s: %s\n"), path,
+ strerror(errno));
+ return (ret != 0);
+ }
+
+ if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
+ (void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS "
+ "filesystem\n"), cmdname, path);
+ return (1);
+ }
+
+ if ((zhp = zfs_open(g_zfs, entry.mnt_special,
+ ZFS_TYPE_FILESYSTEM)) == NULL)
+ return (1);
+
+ ret = 1;
+ if (stat64(entry.mnt_mountp, &statbuf) != 0) {
+ (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
+ cmdname, path, strerror(errno));
+ goto out;
+ } else if (statbuf.st_ino != path_inode) {
+ (void) fprintf(stderr, gettext("cannot "
+ "%s '%s': not a mountpoint\n"), cmdname, path);
+ goto out;
+ }
+
+ if (op == OP_SHARE) {
+ char nfs_mnt_prop[ZFS_MAXPROPLEN];
+ char smbshare_prop[ZFS_MAXPROPLEN];
+
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, nfs_mnt_prop,
+ sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshare_prop,
+ sizeof (smbshare_prop), NULL, NULL, 0, B_FALSE) == 0);
+
+ if (strcmp(nfs_mnt_prop, "off") == 0 &&
+ strcmp(smbshare_prop, "off") == 0) {
+ (void) fprintf(stderr, gettext("cannot unshare "
+ "'%s': legacy share\n"), path);
+#ifdef illumos
+ (void) fprintf(stderr, gettext("use "
+ "unshare(1M) to unshare this filesystem\n"));
+#endif
+ } else if (!zfs_is_shared(zhp)) {
+ (void) fprintf(stderr, gettext("cannot unshare '%s': "
+ "not currently shared\n"), path);
+ } else {
+ ret = zfs_unshareall_bypath(zhp, path);
+ }
+ } else {
+ char mtpt_prop[ZFS_MAXPROPLEN];
+
+ verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mtpt_prop,
+ sizeof (mtpt_prop), NULL, NULL, 0, B_FALSE) == 0);
+
+ if (is_manual) {
+ ret = zfs_unmount(zhp, NULL, flags);
+ } else if (strcmp(mtpt_prop, "legacy") == 0) {
+ (void) fprintf(stderr, gettext("cannot unmount "
+ "'%s': legacy mountpoint\n"),
+ zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use umount(8) "
+ "to unmount this filesystem\n"));
+ } else {
+ ret = zfs_unmountall(zhp, flags);
+ }
+ }
+
+out:
+ zfs_close(zhp);
+
+ return (ret != 0);
+}
+
+/*
+ * Generic callback for unsharing or unmounting a filesystem.
+ */
+static int
+unshare_unmount(int op, int argc, char **argv)
+{
+ int do_all = 0;
+ int flags = 0;
+ int ret = 0;
+ int c;
+ zfs_handle_t *zhp;
+ char nfs_mnt_prop[ZFS_MAXPROPLEN];
+ char sharesmb[ZFS_MAXPROPLEN];
+
+ /* check options */
+ while ((c = getopt(argc, argv, op == OP_SHARE ? "a" : "af")) != -1) {
+ switch (c) {
+ case 'a':
+ do_all = 1;
+ break;
+ case 'f':
+ flags = MS_FORCE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (do_all) {
+ /*
+ * We could make use of zfs_for_each() to walk all datasets in
+ * the system, but this would be very inefficient, especially
+ * since we would have to linearly search /etc/mnttab for each
+ * one. Instead, do one pass through /etc/mnttab looking for
+ * zfs entries and call zfs_unmount() for each one.
+ *
+ * Things get a little tricky if the administrator has created
+ * mountpoints beneath other ZFS filesystems. In this case, we
+ * have to unmount the deepest filesystems first. To accomplish
+ * this, we place all the mountpoints in an AVL tree sorted by
+ * the special type (dataset name), and walk the result in
+ * reverse to make sure to get any snapshots first.
+ */
+ struct mnttab entry;
+ uu_avl_pool_t *pool;
+ uu_avl_t *tree = NULL;
+ unshare_unmount_node_t *node;
+ uu_avl_index_t idx;
+ uu_avl_walk_t *walk;
+
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ if (((pool = uu_avl_pool_create("unmount_pool",
+ sizeof (unshare_unmount_node_t),
+ offsetof(unshare_unmount_node_t, un_avlnode),
+ unshare_unmount_compare, UU_DEFAULT)) == NULL) ||
+ ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL))
+ nomem();
+
+ rewind(mnttab_file);
+ while (getmntent(mnttab_file, &entry) == 0) {
+
+ /* ignore non-ZFS entries */
+ if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
+ continue;
+
+ /* ignore snapshots */
+ if (strchr(entry.mnt_special, '@') != NULL)
+ continue;
+
+ if ((zhp = zfs_open(g_zfs, entry.mnt_special,
+ ZFS_TYPE_FILESYSTEM)) == NULL) {
+ ret = 1;
+ continue;
+ }
+
+ /*
+ * Ignore datasets that are excluded/restricted by
+ * parent pool name.
+ */
+ if (zpool_skip_pool(zfs_get_pool_name(zhp))) {
+ zfs_close(zhp);
+ continue;
+ }
+
+ switch (op) {
+ case OP_SHARE:
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
+ nfs_mnt_prop,
+ sizeof (nfs_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
+ if (strcmp(nfs_mnt_prop, "off") != 0)
+ break;
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
+ nfs_mnt_prop,
+ sizeof (nfs_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
+ if (strcmp(nfs_mnt_prop, "off") == 0)
+ continue;
+ break;
+ case OP_MOUNT:
+ /* Ignore legacy mounts */
+ verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
+ nfs_mnt_prop,
+ sizeof (nfs_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
+ if (strcmp(nfs_mnt_prop, "legacy") == 0)
+ continue;
+ /* Ignore canmount=noauto mounts */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
+ ZFS_CANMOUNT_NOAUTO)
+ continue;
+ default:
+ break;
+ }
+
+ node = safe_malloc(sizeof (unshare_unmount_node_t));
+ node->un_zhp = zhp;
+ node->un_mountp = safe_strdup(entry.mnt_mountp);
+
+ uu_avl_node_init(node, &node->un_avlnode, pool);
+
+ if (uu_avl_find(tree, node, NULL, &idx) == NULL) {
+ uu_avl_insert(tree, node, idx);
+ } else {
+ zfs_close(node->un_zhp);
+ free(node->un_mountp);
+ free(node);
+ }
+ }
+
+ /*
+ * Walk the AVL tree in reverse, unmounting each filesystem and
+ * removing it from the AVL tree in the process.
+ */
+ if ((walk = uu_avl_walk_start(tree,
+ UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL)
+ nomem();
+
+ while ((node = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_remove(tree, node);
+
+ switch (op) {
+ case OP_SHARE:
+ if (zfs_unshareall_bypath(node->un_zhp,
+ node->un_mountp) != 0)
+ ret = 1;
+ break;
+
+ case OP_MOUNT:
+ if (zfs_unmount(node->un_zhp,
+ node->un_mountp, flags) != 0)
+ ret = 1;
+ break;
+ }
+
+ zfs_close(node->un_zhp);
+ free(node->un_mountp);
+ free(node);
+ }
+
+ uu_avl_walk_end(walk);
+ uu_avl_destroy(tree);
+ uu_avl_pool_destroy(pool);
+
+ } else {
+ if (argc != 1) {
+ if (argc == 0)
+ (void) fprintf(stderr,
+ gettext("missing filesystem argument\n"));
+ else
+ (void) fprintf(stderr,
+ gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ /*
+ * We have an argument, but it may be a full path or a ZFS
+ * filesystem. Pass full paths off to unmount_path() (shared by
+ * manual_unmount), otherwise open the filesystem and pass to
+ * zfs_unmount().
+ */
+ if (argv[0][0] == '/')
+ return (unshare_unmount_path(op, argv[0],
+ flags, B_FALSE));
+
+ if ((zhp = zfs_open(g_zfs, argv[0],
+ ZFS_TYPE_FILESYSTEM)) == NULL)
+ return (1);
+
+ verify(zfs_prop_get(zhp, op == OP_SHARE ?
+ ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
+ nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL,
+ NULL, 0, B_FALSE) == 0);
+
+ switch (op) {
+ case OP_SHARE:
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
+ nfs_mnt_prop,
+ sizeof (nfs_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
+ sharesmb, sizeof (sharesmb), NULL, NULL,
+ 0, B_FALSE) == 0);
+
+ if (strcmp(nfs_mnt_prop, "off") == 0 &&
+ strcmp(sharesmb, "off") == 0) {
+ (void) fprintf(stderr, gettext("cannot "
+ "unshare '%s': legacy share\n"),
+ zfs_get_name(zhp));
+#ifdef illumos
+ (void) fprintf(stderr, gettext("use "
+ "unshare(1M) to unshare this "
+ "filesystem\n"));
+#endif
+ ret = 1;
+ } else if (!zfs_is_shared(zhp)) {
+ (void) fprintf(stderr, gettext("cannot "
+ "unshare '%s': not currently "
+ "shared\n"), zfs_get_name(zhp));
+ ret = 1;
+ } else if (zfs_unshareall(zhp) != 0) {
+ ret = 1;
+ }
+ break;
+
+ case OP_MOUNT:
+ if (strcmp(nfs_mnt_prop, "legacy") == 0) {
+ (void) fprintf(stderr, gettext("cannot "
+ "unmount '%s': legacy "
+ "mountpoint\n"), zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use "
+ "umount(8) to unmount this "
+ "filesystem\n"));
+ ret = 1;
+ } else if (!zfs_is_mounted(zhp, NULL)) {
+ (void) fprintf(stderr, gettext("cannot "
+ "unmount '%s': not currently "
+ "mounted\n"),
+ zfs_get_name(zhp));
+ ret = 1;
+ } else if (zfs_unmountall(zhp, flags) != 0) {
+ ret = 1;
+ }
+ break;
+ }
+
+ zfs_close(zhp);
+ }
+
+ return (ret);
+}
+
+/*
+ * zfs unmount -a
+ * zfs unmount filesystem
+ *
+ * Unmount all filesystems, or a specific ZFS filesystem.
+ */
+static int
+zfs_do_unmount(int argc, char **argv)
+{
+ return (unshare_unmount(OP_MOUNT, argc, argv));
+}
+
+/*
+ * zfs unshare -a
+ * zfs unshare filesystem
+ *
+ * Unshare all filesystems, or a specific ZFS filesystem.
+ */
+static int
+zfs_do_unshare(int argc, char **argv)
+{
+ return (unshare_unmount(OP_SHARE, argc, argv));
+}
+
+/*
+ * Attach/detach the given dataset to/from the given jail
+ */
+/* ARGSUSED */
+static int
+do_jail(int argc, char **argv, int attach)
+{
+ zfs_handle_t *zhp;
+ int jailid, ret;
+
+ /* check number of arguments */
+ if (argc < 3) {
+ (void) fprintf(stderr, gettext("missing argument(s)\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 3) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ jailid = jail_getid(argv[1]);
+ if (jailid < 0) {
+ (void) fprintf(stderr, gettext("invalid jail id or name\n"));
+ usage(B_FALSE);
+ }
+
+ zhp = zfs_open(g_zfs, argv[2], ZFS_TYPE_FILESYSTEM);
+ if (zhp == NULL)
+ return (1);
+
+ ret = (zfs_jail(zhp, jailid, attach) != 0);
+
+ zfs_close(zhp);
+ return (ret);
+}
+
+/*
+ * zfs jail jailid filesystem
+ *
+ * Attach the given dataset to the given jail
+ */
+/* ARGSUSED */
+static int
+zfs_do_jail(int argc, char **argv)
+{
+
+ return (do_jail(argc, argv, 1));
+}
+
+/*
+ * zfs unjail jailid filesystem
+ *
+ * Detach the given dataset from the given jail
+ */
+/* ARGSUSED */
+static int
+zfs_do_unjail(int argc, char **argv)
+{
+
+ return (do_jail(argc, argv, 0));
+}
+
+/*
+ * Called when invoked as /etc/fs/zfs/mount. Do the mount if the mountpoint is
+ * 'legacy'. Otherwise, complain that use should be using 'zfs mount'.
+ */
+static int
+manual_mount(int argc, char **argv)
+{
+ zfs_handle_t *zhp;
+ char mountpoint[ZFS_MAXPROPLEN];
+ char mntopts[MNT_LINE_MAX] = { '\0' };
+ int ret = 0;
+ int c;
+ int flags = 0;
+ char *dataset, *path;
+
+ /* check options */
+ while ((c = getopt(argc, argv, ":mo:O")) != -1) {
+ switch (c) {
+ case 'o':
+ (void) strlcpy(mntopts, optarg, sizeof (mntopts));
+ break;
+ case 'O':
+ flags |= MS_OVERLAY;
+ break;
+ case 'm':
+ flags |= MS_NOMNTTAB;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ (void) fprintf(stderr, gettext("usage: mount [-o opts] "
+ "<path>\n"));
+ return (2);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check that we only have two arguments */
+ if (argc != 2) {
+ if (argc == 0)
+ (void) fprintf(stderr, gettext("missing dataset "
+ "argument\n"));
+ else if (argc == 1)
+ (void) fprintf(stderr,
+ gettext("missing mountpoint argument\n"));
+ else
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ (void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n");
+ return (2);
+ }
+
+ dataset = argv[0];
+ path = argv[1];
+
+ /* try to open the dataset */
+ if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL)
+ return (1);
+
+ (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
+ sizeof (mountpoint), NULL, NULL, 0, B_FALSE);
+
+ /* check for legacy mountpoint and complain appropriately */
+ ret = 0;
+ if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
+ if (zmount(dataset, path, flags, MNTTYPE_ZFS,
+ NULL, 0, mntopts, sizeof (mntopts)) != 0) {
+ (void) fprintf(stderr, gettext("mount failed: %s\n"),
+ strerror(errno));
+ ret = 1;
+ }
+ } else {
+ (void) fprintf(stderr, gettext("filesystem '%s' cannot be "
+ "mounted using 'mount -t zfs'\n"), dataset);
+ (void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' "
+ "instead.\n"), path);
+ (void) fprintf(stderr, gettext("If you must use 'mount -t zfs' "
+ "or /etc/fstab, use 'zfs set mountpoint=legacy'.\n"));
+ (void) fprintf(stderr, gettext("See zfs(8) for more "
+ "information.\n"));
+ ret = 1;
+ }
+
+ return (ret);
+}
+
+/*
+ * Called when invoked as /etc/fs/zfs/umount. Unlike a manual mount, we allow
+ * unmounts of non-legacy filesystems, as this is the dominant administrative
+ * interface.
+ */
+static int
+manual_unmount(int argc, char **argv)
+{
+ int flags = 0;
+ int c;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "f")) != -1) {
+ switch (c) {
+ case 'f':
+ flags = MS_FORCE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ (void) fprintf(stderr, gettext("usage: unmount [-f] "
+ "<path>\n"));
+ return (2);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check arguments */
+ if (argc != 1) {
+ if (argc == 0)
+ (void) fprintf(stderr, gettext("missing path "
+ "argument\n"));
+ else
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ (void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n"));
+ return (2);
+ }
+
+ return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE));
+}
+
+static int
+find_command_idx(char *command, int *idx)
+{
+ int i;
+
+ for (i = 0; i < NCOMMAND; i++) {
+ if (command_table[i].name == NULL)
+ continue;
+
+ if (strcmp(command, command_table[i].name) == 0) {
+ *idx = i;
+ return (0);
+ }
+ }
+ return (1);
+}
+
+static int
+zfs_do_diff(int argc, char **argv)
+{
+ zfs_handle_t *zhp;
+ int flags = 0;
+ char *tosnap = NULL;
+ char *fromsnap = NULL;
+ char *atp, *copy;
+ int err = 0;
+ int c;
+
+ while ((c = getopt(argc, argv, "FHt")) != -1) {
+ switch (c) {
+ case 'F':
+ flags |= ZFS_DIFF_CLASSIFY;
+ break;
+ case 'H':
+ flags |= ZFS_DIFF_PARSEABLE;
+ break;
+ case 't':
+ flags |= ZFS_DIFF_TIMESTAMP;
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("invalid option '%c'\n"), optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr,
+ gettext("must provide at least one snapshot name\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc > 2) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ fromsnap = argv[0];
+ tosnap = (argc == 2) ? argv[1] : NULL;
+
+ copy = NULL;
+ if (*fromsnap != '@')
+ copy = strdup(fromsnap);
+ else if (tosnap)
+ copy = strdup(tosnap);
+ if (copy == NULL)
+ usage(B_FALSE);
+
+ if ((atp = strchr(copy, '@')) != NULL)
+ *atp = '\0';
+
+ if ((zhp = zfs_open(g_zfs, copy, ZFS_TYPE_FILESYSTEM)) == NULL)
+ return (1);
+
+ free(copy);
+
+ /*
+ * Ignore SIGPIPE so that the library can give us
+ * information on any failure
+ */
+ (void) sigignore(SIGPIPE);
+
+ err = zfs_show_diffs(zhp, STDOUT_FILENO, fromsnap, tosnap, flags);
+
+ zfs_close(zhp);
+
+ return (err != 0);
+}
+
+/*
+ * zfs remap <filesystem | volume>
+ *
+ * Remap the indirect blocks in the given fileystem or volume.
+ */
+static int
+zfs_do_remap(int argc, char **argv)
+{
+ const char *fsname;
+ int err = 0;
+ int c;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "")) != -1) {
+ switch (c) {
+ case '?':
+ (void) fprintf(stderr,
+ gettext("invalid option '%c'\n"), optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ if (argc != 2) {
+ (void) fprintf(stderr, gettext("wrong number of arguments\n"));
+ usage(B_FALSE);
+ }
+
+ fsname = argv[1];
+ err = zfs_remap_indirects(g_zfs, fsname);
+
+ return (err);
+}
+
+/*
+ * zfs bookmark <fs@snap> <fs#bmark>
+ *
+ * Creates a bookmark with the given name from the given snapshot.
+ */
+static int
+zfs_do_bookmark(int argc, char **argv)
+{
+ char snapname[ZFS_MAX_DATASET_NAME_LEN];
+ zfs_handle_t *zhp;
+ nvlist_t *nvl;
+ int ret = 0;
+ int c;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "")) != -1) {
+ switch (c) {
+ case '?':
+ (void) fprintf(stderr,
+ gettext("invalid option '%c'\n"), optopt);
+ goto usage;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing snapshot argument\n"));
+ goto usage;
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing bookmark argument\n"));
+ goto usage;
+ }
+
+ if (strchr(argv[1], '#') == NULL) {
+ (void) fprintf(stderr,
+ gettext("invalid bookmark name '%s' -- "
+ "must contain a '#'\n"), argv[1]);
+ goto usage;
+ }
+
+ if (argv[0][0] == '@') {
+ /*
+ * Snapshot name begins with @.
+ * Default to same fs as bookmark.
+ */
+ (void) strncpy(snapname, argv[1], sizeof (snapname));
+ *strchr(snapname, '#') = '\0';
+ (void) strlcat(snapname, argv[0], sizeof (snapname));
+ } else {
+ (void) strncpy(snapname, argv[0], sizeof (snapname));
+ }
+ zhp = zfs_open(g_zfs, snapname, ZFS_TYPE_SNAPSHOT);
+ if (zhp == NULL)
+ goto usage;
+ zfs_close(zhp);
+
+
+ nvl = fnvlist_alloc();
+ fnvlist_add_string(nvl, argv[1], snapname);
+ ret = lzc_bookmark(nvl, NULL);
+ fnvlist_free(nvl);
+
+ if (ret != 0) {
+ const char *err_msg;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot create bookmark '%s'"), argv[1]);
+
+ switch (ret) {
+ case EXDEV:
+ err_msg = "bookmark is in a different pool";
+ break;
+ case EEXIST:
+ err_msg = "bookmark exists";
+ break;
+ case EINVAL:
+ err_msg = "invalid argument";
+ break;
+ case ENOTSUP:
+ err_msg = "bookmark feature not enabled";
+ break;
+ case ENOSPC:
+ err_msg = "out of space";
+ break;
+ default:
+ err_msg = "unknown error";
+ break;
+ }
+ (void) fprintf(stderr, "%s: %s\n", errbuf,
+ dgettext(TEXT_DOMAIN, err_msg));
+ }
+
+ return (ret != 0);
+
+usage:
+ usage(B_FALSE);
+ return (-1);
+}
+
+static int
+zfs_do_channel_program(int argc, char **argv)
+{
+ int ret, fd;
+ char c;
+ char *progbuf, *filename, *poolname;
+ size_t progsize, progread;
+ nvlist_t *outnvl;
+ uint64_t instrlimit = ZCP_DEFAULT_INSTRLIMIT;
+ uint64_t memlimit = ZCP_DEFAULT_MEMLIMIT;
+ boolean_t sync_flag = B_TRUE, json_output = B_FALSE;
+ zpool_handle_t *zhp;
+
+ /* check options */
+ while (-1 !=
+ (c = getopt(argc, argv, "jnt:(instr-limit)m:(memory-limit)"))) {
+ switch (c) {
+ case 't':
+ case 'm': {
+ uint64_t arg;
+ char *endp;
+
+ errno = 0;
+ arg = strtoull(optarg, &endp, 0);
+ if (errno != 0 || *endp != '\0') {
+ (void) fprintf(stderr, gettext(
+ "invalid argument "
+ "'%s': expected integer\n"), optarg);
+ goto usage;
+ }
+
+ if (c == 't') {
+ if (arg > ZCP_MAX_INSTRLIMIT || arg == 0) {
+ (void) fprintf(stderr, gettext(
+ "Invalid instruction limit: "
+ "%s\n"), optarg);
+ return (1);
+ } else {
+ instrlimit = arg;
+ }
+ } else {
+ ASSERT3U(c, ==, 'm');
+ if (arg > ZCP_MAX_MEMLIMIT || arg == 0) {
+ (void) fprintf(stderr, gettext(
+ "Invalid memory limit: "
+ "%s\n"), optarg);
+ return (1);
+ } else {
+ memlimit = arg;
+ }
+ }
+ break;
+ }
+ case 'n': {
+ sync_flag = B_FALSE;
+ break;
+ }
+ case 'j': {
+ json_output = B_TRUE;
+ break;
+ }
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ goto usage;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2) {
+ (void) fprintf(stderr,
+ gettext("invalid number of arguments\n"));
+ goto usage;
+ }
+
+ poolname = argv[0];
+ filename = argv[1];
+ if (strcmp(filename, "-") == 0) {
+ fd = 0;
+ filename = "standard input";
+ } else if ((fd = open(filename, O_RDONLY)) < 0) {
+ (void) fprintf(stderr, gettext("cannot open '%s': %s\n"),
+ filename, strerror(errno));
+ return (1);
+ }
+
+ if ((zhp = zpool_open(g_zfs, poolname)) == NULL) {
+ (void) fprintf(stderr, gettext("cannot open pool '%s'"),
+ poolname);
+ return (1);
+ }
+ zpool_close(zhp);
+
+ /*
+ * Read in the channel program, expanding the program buffer as
+ * necessary.
+ */
+ progread = 0;
+ progsize = 1024;
+ progbuf = safe_malloc(progsize);
+ do {
+ ret = read(fd, progbuf + progread, progsize - progread);
+ progread += ret;
+ if (progread == progsize && ret > 0) {
+ progsize *= 2;
+ progbuf = safe_realloc(progbuf, progsize);
+ }
+ } while (ret > 0);
+
+ if (fd != 0)
+ (void) close(fd);
+ if (ret < 0) {
+ free(progbuf);
+ (void) fprintf(stderr,
+ gettext("cannot read '%s': %s\n"),
+ filename, strerror(errno));
+ return (1);
+ }
+ progbuf[progread] = '\0';
+
+ /*
+ * Any remaining arguments are passed as arguments to the lua script as
+ * a string array:
+ * {
+ * "argv" -> [ "arg 1", ... "arg n" ],
+ * }
+ */
+ nvlist_t *argnvl = fnvlist_alloc();
+ fnvlist_add_string_array(argnvl, ZCP_ARG_CLIARGV, argv + 2, argc - 2);
+
+ if (sync_flag) {
+ ret = lzc_channel_program(poolname, progbuf,
+ instrlimit, memlimit, argnvl, &outnvl);
+ } else {
+ ret = lzc_channel_program_nosync(poolname, progbuf,
+ instrlimit, memlimit, argnvl, &outnvl);
+ }
+
+ if (ret != 0) {
+ /*
+ * On error, report the error message handed back by lua if one
+ * exists. Otherwise, generate an appropriate error message,
+ * falling back on strerror() for an unexpected return code.
+ */
+ char *errstring = NULL;
+ if (nvlist_exists(outnvl, ZCP_RET_ERROR)) {
+ (void) nvlist_lookup_string(outnvl,
+ ZCP_RET_ERROR, &errstring);
+ if (errstring == NULL)
+ errstring = strerror(ret);
+ } else {
+ switch (ret) {
+ case EINVAL:
+ errstring =
+ "Invalid instruction or memory limit.";
+ break;
+ case ENOMEM:
+ errstring = "Return value too large.";
+ break;
+ case ENOSPC:
+ errstring = "Memory limit exhausted.";
+ break;
+#ifdef illumos
+ case ETIME:
+#else
+ case ETIMEDOUT:
+#endif
+ errstring = "Timed out.";
+ break;
+ case EPERM:
+ errstring = "Permission denied. Channel "
+ "programs must be run as root.";
+ break;
+ default:
+ errstring = strerror(ret);
+ }
+ }
+ (void) fprintf(stderr,
+ gettext("Channel program execution failed:\n%s\n"),
+ errstring);
+ } else {
+ if (json_output) {
+ (void) nvlist_print_json(stdout, outnvl);
+ } else if (nvlist_empty(outnvl)) {
+ (void) fprintf(stdout, gettext("Channel program fully "
+ "executed and did not produce output.\n"));
+ } else {
+ (void) fprintf(stdout, gettext("Channel program fully "
+ "executed and produced output:\n"));
+ dump_nvlist(outnvl, 4);
+ }
+ }
+
+ free(progbuf);
+ fnvlist_free(outnvl);
+ fnvlist_free(argnvl);
+ return (ret != 0);
+
+usage:
+ usage(B_FALSE);
+ return (-1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ret = 0;
+ int i;
+ char *progname;
+ char *cmdname;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ opterr = 0;
+
+ if ((g_zfs = libzfs_init()) == NULL) {
+ (void) fprintf(stderr, gettext("internal error: failed to "
+ "initialize ZFS library\n"));
+ return (1);
+ }
+
+ zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
+
+ libzfs_print_on_error(g_zfs, B_TRUE);
+
+ if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) {
+ (void) fprintf(stderr, gettext("internal error: unable to "
+ "open %s\n"), MNTTAB);
+ return (1);
+ }
+
+ /*
+ * This command also doubles as the /etc/fs mount and unmount program.
+ * Determine if we should take this behavior based on argv[0].
+ */
+ progname = basename(argv[0]);
+ if (strcmp(progname, "mount") == 0) {
+ ret = manual_mount(argc, argv);
+ } else if (strcmp(progname, "umount") == 0) {
+ ret = manual_unmount(argc, argv);
+ } else {
+ /*
+ * Make sure the user has specified some command.
+ */
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing command\n"));
+ usage(B_FALSE);
+ }
+
+ cmdname = argv[1];
+
+ /*
+ * The 'umount' command is an alias for 'unmount'
+ */
+ if (strcmp(cmdname, "umount") == 0)
+ cmdname = "unmount";
+
+ /*
+ * The 'recv' command is an alias for 'receive'
+ */
+ if (strcmp(cmdname, "recv") == 0)
+ cmdname = "receive";
+
+ /*
+ * The 'snap' command is an alias for 'snapshot'
+ */
+ if (strcmp(cmdname, "snap") == 0)
+ cmdname = "snapshot";
+
+ /*
+ * Special case '-?'
+ */
+ if (strcmp(cmdname, "-?") == 0)
+ usage(B_TRUE);
+
+ /*
+ * Run the appropriate command.
+ */
+ libzfs_mnttab_cache(g_zfs, B_TRUE);
+ if (find_command_idx(cmdname, &i) == 0) {
+ current_command = &command_table[i];
+ ret = command_table[i].func(argc - 1, argv + 1);
+ } else if (strchr(cmdname, '=') != NULL) {
+ verify(find_command_idx("set", &i) == 0);
+ current_command = &command_table[i];
+ ret = command_table[i].func(argc, argv);
+ } else {
+ (void) fprintf(stderr, gettext("unrecognized "
+ "command '%s'\n"), cmdname);
+ usage(B_FALSE);
+ }
+ libzfs_mnttab_cache(g_zfs, B_FALSE);
+ }
+
+ (void) fclose(mnttab_file);
+
+ if (ret == 0 && log_history)
+ (void) zpool_log_history(g_zfs, history_str);
+
+ libzfs_fini(g_zfs);
+
+ /*
+ * The 'ZFS_ABORT' environment variable causes us to dump core on exit
+ * for the purposes of running ::findleaks.
+ */
+ if (getenv("ZFS_ABORT") != NULL) {
+ (void) printf("dumping core by request\n");
+ abort();
+ }
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_util.h b/cddl/contrib/opensolaris/cmd/zfs/zfs_util.h
new file mode 100644
index 000000000000..3ddff9e22d7d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_util.h
@@ -0,0 +1,42 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _ZFS_UTIL_H
+#define _ZFS_UTIL_H
+
+#include <libzfs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void * safe_malloc(size_t size);
+void nomem(void);
+libzfs_handle_t *g_zfs;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFS_UTIL_H */
diff --git a/cddl/contrib/opensolaris/cmd/zhack/zhack.c b/cddl/contrib/opensolaris/cmd/zhack/zhack.c
new file mode 100644
index 000000000000..20a0c60e6a18
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zhack/zhack.c
@@ -0,0 +1,535 @@
+/*
+ * 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 (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ */
+
+/*
+ * zhack is a debugging tool that can write changes to ZFS pool using libzpool
+ * for testing purposes. Altering pools with zhack is unsupported and may
+ * result in corrupted pools.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/dmu.h>
+#include <sys/zap.h>
+#include <sys/zfs_znode.h>
+#include <sys/dsl_synctask.h>
+#include <sys/vdev.h>
+#include <sys/fs/zfs.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_pool.h>
+#include <sys/zio_checksum.h>
+#include <sys/zio_compress.h>
+#include <sys/zfeature.h>
+#include <sys/dmu_tx.h>
+#undef verify
+#include <libzfs.h>
+
+extern boolean_t zfeature_checks_disable;
+
+const char cmdname[] = "zhack";
+libzfs_handle_t *g_zfs;
+static importargs_t g_importargs;
+static char *g_pool;
+static boolean_t g_readonly;
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr,
+ "Usage: %s [-c cachefile] [-d dir] <subcommand> <args> ...\n"
+ "where <subcommand> <args> is one of the following:\n"
+ "\n", cmdname);
+
+ (void) fprintf(stderr,
+ " feature stat <pool>\n"
+ " print information about enabled features\n"
+ " feature enable [-d desc] <pool> <feature>\n"
+ " add a new enabled feature to the pool\n"
+ " -d <desc> sets the feature's description\n"
+ " feature ref [-md] <pool> <feature>\n"
+ " change the refcount on the given feature\n"
+ " -d decrease instead of increase the refcount\n"
+ " -m add the feature to the label if increasing refcount\n"
+ "\n"
+ " <feature> : should be a feature guid\n");
+ exit(1);
+}
+
+
+static void
+fatal(spa_t *spa, void *tag, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (spa != NULL) {
+ spa_close(spa, tag);
+ (void) spa_export(g_pool, NULL, B_TRUE, B_FALSE);
+ }
+
+ va_start(ap, fmt);
+ (void) fprintf(stderr, "%s: ", cmdname);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void) fprintf(stderr, "\n");
+
+ exit(1);
+}
+
+/* ARGSUSED */
+static int
+space_delta_cb(dmu_object_type_t bonustype, void *data,
+ uint64_t *userp, uint64_t *groupp)
+{
+ /*
+ * Is it a valid type of object to track?
+ */
+ if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
+ return (ENOENT);
+ (void) fprintf(stderr, "modifying object that needs user accounting");
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * Target is the dataset whose pool we want to open.
+ */
+static void
+zhack_import(char *target, boolean_t readonly)
+{
+ nvlist_t *config;
+ nvlist_t *props;
+ int error;
+
+ kernel_init(readonly ? FREAD : (FREAD | FWRITE));
+ g_zfs = libzfs_init();
+ ASSERT(g_zfs != NULL);
+
+ dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb);
+
+ g_readonly = readonly;
+ g_importargs.unique = B_TRUE;
+ g_importargs.can_be_active = readonly;
+ g_pool = strdup(target);
+
+ error = zpool_tryimport(g_zfs, target, &config, &g_importargs);
+ if (error)
+ fatal(NULL, FTAG, "cannot import '%s': %s", target,
+ libzfs_error_description(g_zfs));
+
+ props = NULL;
+ if (readonly) {
+ VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
+ VERIFY(nvlist_add_uint64(props,
+ zpool_prop_to_name(ZPOOL_PROP_READONLY), 1) == 0);
+ }
+
+ zfeature_checks_disable = B_TRUE;
+ error = spa_import(target, config, props,
+ (readonly ? ZFS_IMPORT_SKIP_MMP : ZFS_IMPORT_NORMAL));
+ zfeature_checks_disable = B_FALSE;
+ if (error == EEXIST)
+ error = 0;
+
+ if (error)
+ fatal(NULL, FTAG, "can't import '%s': %s", target,
+ strerror(error));
+}
+
+static void
+zhack_spa_open(char *target, boolean_t readonly, void *tag, spa_t **spa)
+{
+ int err;
+
+ zhack_import(target, readonly);
+
+ zfeature_checks_disable = B_TRUE;
+ err = spa_open(target, spa, tag);
+ zfeature_checks_disable = B_FALSE;
+
+ if (err != 0)
+ fatal(*spa, FTAG, "cannot open '%s': %s", target,
+ strerror(err));
+ if (spa_version(*spa) < SPA_VERSION_FEATURES) {
+ fatal(*spa, FTAG, "'%s' has version %d, features not enabled",
+ target, (int)spa_version(*spa));
+ }
+}
+
+static void
+dump_obj(objset_t *os, uint64_t obj, const char *name)
+{
+ zap_cursor_t zc;
+ zap_attribute_t za;
+
+ (void) printf("%s_obj:\n", name);
+
+ for (zap_cursor_init(&zc, os, obj);
+ zap_cursor_retrieve(&zc, &za) == 0;
+ zap_cursor_advance(&zc)) {
+ if (za.za_integer_length == 8) {
+ ASSERT(za.za_num_integers == 1);
+ (void) printf("\t%s = %llu\n",
+ za.za_name, (u_longlong_t)za.za_first_integer);
+ } else {
+ ASSERT(za.za_integer_length == 1);
+ char val[1024];
+ VERIFY(zap_lookup(os, obj, za.za_name,
+ 1, sizeof (val), val) == 0);
+ (void) printf("\t%s = %s\n", za.za_name, val);
+ }
+ }
+ zap_cursor_fini(&zc);
+}
+
+static void
+dump_mos(spa_t *spa)
+{
+ nvlist_t *nv = spa->spa_label_features;
+
+ (void) printf("label config:\n");
+ for (nvpair_t *pair = nvlist_next_nvpair(nv, NULL);
+ pair != NULL;
+ pair = nvlist_next_nvpair(nv, pair)) {
+ (void) printf("\t%s\n", nvpair_name(pair));
+ }
+}
+
+static void
+zhack_do_feature_stat(int argc, char **argv)
+{
+ spa_t *spa;
+ objset_t *os;
+ char *target;
+
+ argc--;
+ argv++;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, "error: missing pool name\n");
+ usage();
+ }
+ target = argv[0];
+
+ zhack_spa_open(target, B_TRUE, FTAG, &spa);
+ os = spa->spa_meta_objset;
+
+ dump_obj(os, spa->spa_feat_for_read_obj, "for_read");
+ dump_obj(os, spa->spa_feat_for_write_obj, "for_write");
+ dump_obj(os, spa->spa_feat_desc_obj, "descriptions");
+ if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) {
+ dump_obj(os, spa->spa_feat_enabled_txg_obj, "enabled_txg");
+ }
+ dump_mos(spa);
+
+ spa_close(spa, FTAG);
+}
+
+static void
+zhack_feature_enable_sync(void *arg, dmu_tx_t *tx)
+{
+ spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+ zfeature_info_t *feature = arg;
+
+ feature_enable_sync(spa, feature, tx);
+
+ spa_history_log_internal(spa, "zhack enable feature", tx,
+ "guid=%s flags=%x",
+ feature->fi_guid, feature->fi_flags);
+}
+
+static void
+zhack_do_feature_enable(int argc, char **argv)
+{
+ char c;
+ char *desc, *target;
+ spa_t *spa;
+ objset_t *mos;
+ zfeature_info_t feature;
+ spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
+
+ /*
+ * Features are not added to the pool's label until their refcounts
+ * are incremented, so fi_mos can just be left as false for now.
+ */
+ desc = NULL;
+ feature.fi_uname = "zhack";
+ feature.fi_flags = 0;
+ feature.fi_depends = nodeps;
+ feature.fi_feature = SPA_FEATURE_NONE;
+
+ optind = 1;
+ while ((c = getopt(argc, argv, "rmd:")) != -1) {
+ switch (c) {
+ case 'r':
+ feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
+ break;
+ case 'd':
+ desc = strdup(optarg);
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (desc == NULL)
+ desc = strdup("zhack injected");
+ feature.fi_desc = desc;
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "error: missing feature or pool name\n");
+ usage();
+ }
+ target = argv[0];
+ feature.fi_guid = argv[1];
+
+ if (!zfeature_is_valid_guid(feature.fi_guid))
+ fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
+
+ zhack_spa_open(target, B_FALSE, FTAG, &spa);
+ mos = spa->spa_meta_objset;
+
+ if (zfeature_is_supported(feature.fi_guid))
+ fatal(spa, FTAG, "'%s' is a real feature, will not enable");
+ if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
+ fatal(spa, FTAG, "feature already enabled: %s",
+ feature.fi_guid);
+
+ VERIFY0(dsl_sync_task(spa_name(spa), NULL,
+ zhack_feature_enable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL));
+
+ spa_close(spa, FTAG);
+
+ free(desc);
+}
+
+static void
+feature_incr_sync(void *arg, dmu_tx_t *tx)
+{
+ spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+ zfeature_info_t *feature = arg;
+ uint64_t refcount;
+
+ VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
+ feature_sync(spa, feature, refcount + 1, tx);
+ spa_history_log_internal(spa, "zhack feature incr", tx,
+ "name=%s", feature->fi_guid);
+}
+
+static void
+feature_decr_sync(void *arg, dmu_tx_t *tx)
+{
+ spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+ zfeature_info_t *feature = arg;
+ uint64_t refcount;
+
+ VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
+ feature_sync(spa, feature, refcount - 1, tx);
+ spa_history_log_internal(spa, "zhack feature decr", tx,
+ "name=%s", feature->fi_guid);
+}
+
+static void
+zhack_do_feature_ref(int argc, char **argv)
+{
+ char c;
+ char *target;
+ boolean_t decr = B_FALSE;
+ spa_t *spa;
+ objset_t *mos;
+ zfeature_info_t feature;
+ spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
+
+ /*
+ * fi_desc does not matter here because it was written to disk
+ * when the feature was enabled, but we need to properly set the
+ * feature for read or write based on the information we read off
+ * disk later.
+ */
+ feature.fi_uname = "zhack";
+ feature.fi_flags = 0;
+ feature.fi_desc = NULL;
+ feature.fi_depends = nodeps;
+ feature.fi_feature = SPA_FEATURE_NONE;
+
+ optind = 1;
+ while ((c = getopt(argc, argv, "md")) != -1) {
+ switch (c) {
+ case 'm':
+ feature.fi_flags |= ZFEATURE_FLAG_MOS;
+ break;
+ case 'd':
+ decr = B_TRUE;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "error: missing feature or pool name\n");
+ usage();
+ }
+ target = argv[0];
+ feature.fi_guid = argv[1];
+
+ if (!zfeature_is_valid_guid(feature.fi_guid))
+ fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
+
+ zhack_spa_open(target, B_FALSE, FTAG, &spa);
+ mos = spa->spa_meta_objset;
+
+ if (zfeature_is_supported(feature.fi_guid)) {
+ fatal(spa, FTAG,
+ "'%s' is a real feature, will not change refcount");
+ }
+
+ if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
+ feature.fi_guid)) {
+ feature.fi_flags &= ~ZFEATURE_FLAG_READONLY_COMPAT;
+ } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
+ feature.fi_guid)) {
+ feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
+ } else {
+ fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
+ }
+
+ if (decr) {
+ uint64_t count;
+ if (feature_get_refcount_from_disk(spa, &feature,
+ &count) == 0 && count != 0) {
+ fatal(spa, FTAG, "feature refcount already 0: %s",
+ feature.fi_guid);
+ }
+ }
+
+ VERIFY0(dsl_sync_task(spa_name(spa), NULL,
+ decr ? feature_decr_sync : feature_incr_sync, &feature,
+ 5, ZFS_SPACE_CHECK_NORMAL));
+
+ spa_close(spa, FTAG);
+}
+
+static int
+zhack_do_feature(int argc, char **argv)
+{
+ char *subcommand;
+
+ argc--;
+ argv++;
+ if (argc == 0) {
+ (void) fprintf(stderr,
+ "error: no feature operation specified\n");
+ usage();
+ }
+
+ subcommand = argv[0];
+ if (strcmp(subcommand, "stat") == 0) {
+ zhack_do_feature_stat(argc, argv);
+ } else if (strcmp(subcommand, "enable") == 0) {
+ zhack_do_feature_enable(argc, argv);
+ } else if (strcmp(subcommand, "ref") == 0) {
+ zhack_do_feature_ref(argc, argv);
+ } else {
+ (void) fprintf(stderr, "error: unknown subcommand: %s\n",
+ subcommand);
+ usage();
+ }
+
+ return (0);
+}
+
+#define MAX_NUM_PATHS 1024
+
+int
+main(int argc, char **argv)
+{
+ extern void zfs_prop_init(void);
+
+ char *path[MAX_NUM_PATHS];
+ const char *subcommand;
+ int rv = 0;
+ char c;
+
+ g_importargs.path = path;
+
+ dprintf_setup(&argc, argv);
+ zfs_prop_init();
+
+ while ((c = getopt(argc, argv, "c:d:")) != -1) {
+ switch (c) {
+ case 'c':
+ g_importargs.cachefile = optarg;
+ break;
+ case 'd':
+ assert(g_importargs.paths < MAX_NUM_PATHS);
+ g_importargs.path[g_importargs.paths++] = optarg;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 1;
+
+ if (argc == 0) {
+ (void) fprintf(stderr, "error: no command specified\n");
+ usage();
+ }
+
+ subcommand = argv[0];
+
+ if (strcmp(subcommand, "feature") == 0) {
+ rv = zhack_do_feature(argc, argv);
+ } else {
+ (void) fprintf(stderr, "error: unknown subcommand: %s\n",
+ subcommand);
+ usage();
+ }
+
+ if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE) != 0) {
+ fatal(NULL, FTAG, "pool export failed; "
+ "changes may not be committed to disk\n");
+ }
+
+ libzfs_fini(g_zfs);
+ kernel_fini();
+
+ return (rv);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zinject/translate.c b/cddl/contrib/opensolaris/cmd/zinject/translate.c
new file mode 100644
index 000000000000..af25d3c3c17d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zinject/translate.c
@@ -0,0 +1,492 @@
+/*
+ * 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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <libzfs.h>
+
+#include <sys/zfs_context.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/file.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/dnode.h>
+#include <sys/vdev_impl.h>
+
+#include "zinject.h"
+
+extern void kernel_init(int);
+extern void kernel_fini(void);
+
+static int debug;
+
+static void
+ziprintf(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!debug)
+ return;
+
+ va_start(ap, fmt);
+ (void) vprintf(fmt, ap);
+ va_end(ap);
+}
+
+static void
+compress_slashes(const char *src, char *dest)
+{
+ while (*src != '\0') {
+ *dest = *src++;
+ while (*dest == '/' && *src == '/')
+ ++src;
+ ++dest;
+ }
+ *dest = '\0';
+}
+
+/*
+ * Given a full path to a file, translate into a dataset name and a relative
+ * path within the dataset. 'dataset' must be at least MAXNAMELEN characters,
+ * and 'relpath' must be at least MAXPATHLEN characters. We also pass a stat64
+ * buffer, which we need later to get the object ID.
+ */
+static int
+parse_pathname(const char *inpath, char *dataset, char *relpath,
+ struct stat64 *statbuf)
+{
+ struct statfs sfs;
+ const char *rel;
+ char fullpath[MAXPATHLEN];
+
+ compress_slashes(inpath, fullpath);
+
+ if (fullpath[0] != '/') {
+ (void) fprintf(stderr, "invalid object '%s': must be full "
+ "path\n", fullpath);
+ usage();
+ return (-1);
+ }
+
+ if (strlen(fullpath) >= MAXPATHLEN) {
+ (void) fprintf(stderr, "invalid object; pathname too long\n");
+ return (-1);
+ }
+
+ if (stat64(fullpath, statbuf) != 0) {
+ (void) fprintf(stderr, "cannot open '%s': %s\n",
+ fullpath, strerror(errno));
+ return (-1);
+ }
+
+ if (statfs(fullpath, &sfs) == -1) {
+ (void) fprintf(stderr, "cannot find mountpoint for '%s': %s\n",
+ fullpath, strerror(errno));
+ return (-1);
+ }
+
+ if (strcmp(sfs.f_fstypename, MNTTYPE_ZFS) != 0) {
+ (void) fprintf(stderr, "invalid path '%s': not a ZFS "
+ "filesystem\n", fullpath);
+ return (-1);
+ }
+
+ if (strncmp(fullpath, sfs.f_mntonname, strlen(sfs.f_mntonname)) != 0) {
+ (void) fprintf(stderr, "invalid path '%s': mountpoint "
+ "doesn't match path\n", fullpath);
+ return (-1);
+ }
+
+ (void) strcpy(dataset, sfs.f_mntfromname);
+
+ rel = fullpath + strlen(sfs.f_mntonname);
+ if (rel[0] == '/')
+ rel++;
+ (void) strcpy(relpath, rel);
+
+ return (0);
+}
+
+/*
+ * Convert from a (dataset, path) pair into a (objset, object) pair. Note that
+ * we grab the object number from the inode number, since looking this up via
+ * libzpool is a real pain.
+ */
+/* ARGSUSED */
+static int
+object_from_path(const char *dataset, const char *path, struct stat64 *statbuf,
+ zinject_record_t *record)
+{
+ objset_t *os;
+ int err;
+
+ /*
+ * Before doing any libzpool operations, call sync() to ensure that the
+ * on-disk state is consistent with the in-core state.
+ */
+ sync();
+
+ err = dmu_objset_own(dataset, DMU_OST_ZFS, B_TRUE, FTAG, &os);
+ if (err != 0) {
+ (void) fprintf(stderr, "cannot open dataset '%s': %s\n",
+ dataset, strerror(err));
+ return (-1);
+ }
+
+ record->zi_objset = dmu_objset_id(os);
+ record->zi_object = statbuf->st_ino;
+
+ dmu_objset_disown(os, FTAG);
+
+ return (0);
+}
+
+/*
+ * Calculate the real range based on the type, level, and range given.
+ */
+static int
+calculate_range(const char *dataset, err_type_t type, int level, char *range,
+ zinject_record_t *record)
+{
+ objset_t *os = NULL;
+ dnode_t *dn = NULL;
+ int err;
+ int ret = -1;
+
+ /*
+ * Determine the numeric range from the string.
+ */
+ if (range == NULL) {
+ /*
+ * If range is unspecified, set the range to [0,-1], which
+ * indicates that the whole object should be treated as an
+ * error.
+ */
+ record->zi_start = 0;
+ record->zi_end = -1ULL;
+ } else {
+ char *end;
+
+ /* XXX add support for suffixes */
+ record->zi_start = strtoull(range, &end, 10);
+
+
+ if (*end == '\0')
+ record->zi_end = record->zi_start + 1;
+ else if (*end == ',')
+ record->zi_end = strtoull(end + 1, &end, 10);
+
+ if (*end != '\0') {
+ (void) fprintf(stderr, "invalid range '%s': must be "
+ "a numeric range of the form 'start[,end]'\n",
+ range);
+ goto out;
+ }
+ }
+
+ switch (type) {
+ case TYPE_DATA:
+ break;
+
+ case TYPE_DNODE:
+ /*
+ * If this is a request to inject faults into the dnode, then we
+ * must translate the current (objset,object) pair into an
+ * offset within the metadnode for the objset. Specifying any
+ * kind of range with type 'dnode' is illegal.
+ */
+ if (range != NULL) {
+ (void) fprintf(stderr, "range cannot be specified when "
+ "type is 'dnode'\n");
+ goto out;
+ }
+
+ record->zi_start = record->zi_object * sizeof (dnode_phys_t);
+ record->zi_end = record->zi_start + sizeof (dnode_phys_t);
+ record->zi_object = 0;
+ break;
+ }
+
+ /*
+ * Get the dnode associated with object, so we can calculate the block
+ * size.
+ */
+ if ((err = dmu_objset_own(dataset, DMU_OST_ANY,
+ B_TRUE, FTAG, &os)) != 0) {
+ (void) fprintf(stderr, "cannot open dataset '%s': %s\n",
+ dataset, strerror(err));
+ goto out;
+ }
+
+ if (record->zi_object == 0) {
+ dn = DMU_META_DNODE(os);
+ } else {
+ err = dnode_hold(os, record->zi_object, FTAG, &dn);
+ if (err != 0) {
+ (void) fprintf(stderr, "failed to hold dnode "
+ "for object %llu\n",
+ (u_longlong_t)record->zi_object);
+ goto out;
+ }
+ }
+
+
+ ziprintf("data shift: %d\n", (int)dn->dn_datablkshift);
+ ziprintf(" ind shift: %d\n", (int)dn->dn_indblkshift);
+
+ /*
+ * Translate range into block IDs.
+ */
+ if (record->zi_start != 0 || record->zi_end != -1ULL) {
+ record->zi_start >>= dn->dn_datablkshift;
+ record->zi_end >>= dn->dn_datablkshift;
+ }
+
+ /*
+ * Check level, and then translate level 0 blkids into ranges
+ * appropriate for level of indirection.
+ */
+ record->zi_level = level;
+ if (level > 0) {
+ ziprintf("level 0 blkid range: [%llu, %llu]\n",
+ record->zi_start, record->zi_end);
+
+ if (level >= dn->dn_nlevels) {
+ (void) fprintf(stderr, "level %d exceeds max level "
+ "of object (%d)\n", level, dn->dn_nlevels - 1);
+ goto out;
+ }
+
+ if (record->zi_start != 0 || record->zi_end != 0) {
+ int shift = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+
+ for (; level > 0; level--) {
+ record->zi_start >>= shift;
+ record->zi_end >>= shift;
+ }
+ }
+ }
+
+ ret = 0;
+out:
+ if (dn) {
+ if (dn != DMU_META_DNODE(os))
+ dnode_rele(dn, FTAG);
+ }
+ if (os)
+ dmu_objset_disown(os, FTAG);
+
+ return (ret);
+}
+
+int
+translate_record(err_type_t type, const char *object, const char *range,
+ int level, zinject_record_t *record, char *poolname, char *dataset)
+{
+ char path[MAXPATHLEN];
+ char *slash;
+ struct stat64 statbuf;
+ int ret = -1;
+
+ kernel_init(FREAD);
+
+ debug = (getenv("ZINJECT_DEBUG") != NULL);
+
+ ziprintf("translating: %s\n", object);
+
+ if (MOS_TYPE(type)) {
+ /*
+ * MOS objects are treated specially.
+ */
+ switch (type) {
+ case TYPE_MOS:
+ record->zi_type = 0;
+ break;
+ case TYPE_MOSDIR:
+ record->zi_type = DMU_OT_OBJECT_DIRECTORY;
+ break;
+ case TYPE_METASLAB:
+ record->zi_type = DMU_OT_OBJECT_ARRAY;
+ break;
+ case TYPE_CONFIG:
+ record->zi_type = DMU_OT_PACKED_NVLIST;
+ break;
+ case TYPE_BPOBJ:
+ record->zi_type = DMU_OT_BPOBJ;
+ break;
+ case TYPE_SPACEMAP:
+ record->zi_type = DMU_OT_SPACE_MAP;
+ break;
+ case TYPE_ERRLOG:
+ record->zi_type = DMU_OT_ERROR_LOG;
+ break;
+ }
+
+ dataset[0] = '\0';
+ (void) strcpy(poolname, object);
+ return (0);
+ }
+
+ /*
+ * Convert a full path into a (dataset, file) pair.
+ */
+ if (parse_pathname(object, dataset, path, &statbuf) != 0)
+ goto err;
+
+ ziprintf(" dataset: %s\n", dataset);
+ ziprintf(" path: %s\n", path);
+
+ /*
+ * Convert (dataset, file) into (objset, object)
+ */
+ if (object_from_path(dataset, path, &statbuf, record) != 0)
+ goto err;
+
+ ziprintf("raw objset: %llu\n", record->zi_objset);
+ ziprintf("raw object: %llu\n", record->zi_object);
+
+ /*
+ * For the given object, calculate the real (type, level, range)
+ */
+ if (calculate_range(dataset, type, level, (char *)range, record) != 0)
+ goto err;
+
+ ziprintf(" objset: %llu\n", record->zi_objset);
+ ziprintf(" object: %llu\n", record->zi_object);
+ if (record->zi_start == 0 &&
+ record->zi_end == -1ULL)
+ ziprintf(" range: all\n");
+ else
+ ziprintf(" range: [%llu, %llu]\n", record->zi_start,
+ record->zi_end);
+
+ /*
+ * Copy the pool name
+ */
+ (void) strcpy(poolname, dataset);
+ if ((slash = strchr(poolname, '/')) != NULL)
+ *slash = '\0';
+
+ ret = 0;
+
+err:
+ kernel_fini();
+ return (ret);
+}
+
+int
+translate_raw(const char *str, zinject_record_t *record)
+{
+ /*
+ * A raw bookmark of the form objset:object:level:blkid, where each
+ * number is a hexidecimal value.
+ */
+ if (sscanf(str, "%llx:%llx:%x:%llx", (u_longlong_t *)&record->zi_objset,
+ (u_longlong_t *)&record->zi_object, &record->zi_level,
+ (u_longlong_t *)&record->zi_start) != 4) {
+ (void) fprintf(stderr, "bad raw spec '%s': must be of the form "
+ "'objset:object:level:blkid'\n", str);
+ return (-1);
+ }
+
+ record->zi_end = record->zi_start;
+
+ return (0);
+}
+
+int
+translate_device(const char *pool, const char *device, err_type_t label_type,
+ zinject_record_t *record)
+{
+ char *end;
+ zpool_handle_t *zhp;
+ nvlist_t *tgt;
+ boolean_t isspare, iscache;
+
+ /*
+ * Given a device name or GUID, create an appropriate injection record
+ * with zi_guid set.
+ */
+ if ((zhp = zpool_open(g_zfs, pool)) == NULL)
+ return (-1);
+
+ record->zi_guid = strtoull(device, &end, 16);
+ if (record->zi_guid == 0 || *end != '\0') {
+ tgt = zpool_find_vdev(zhp, device, &isspare, &iscache, NULL);
+
+ if (tgt == NULL) {
+ (void) fprintf(stderr, "cannot find device '%s' in "
+ "pool '%s'\n", device, pool);
+ return (-1);
+ }
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
+ &record->zi_guid) == 0);
+ }
+
+ /*
+ * Device faults can take on three different forms:
+ * 1). delayed or hanging I/O
+ * 2). zfs label faults
+ * 3). generic disk faults
+ */
+ if (record->zi_timer != 0) {
+ record->zi_cmd = ZINJECT_DELAY_IO;
+ } else if (label_type != TYPE_INVAL) {
+ record->zi_cmd = ZINJECT_LABEL_FAULT;
+ } else {
+ record->zi_cmd = ZINJECT_DEVICE_FAULT;
+ }
+
+ switch (label_type) {
+ case TYPE_LABEL_UBERBLOCK:
+ record->zi_start = offsetof(vdev_label_t, vl_uberblock[0]);
+ record->zi_end = record->zi_start + VDEV_UBERBLOCK_RING - 1;
+ break;
+ case TYPE_LABEL_NVLIST:
+ record->zi_start = offsetof(vdev_label_t, vl_vdev_phys);
+ record->zi_end = record->zi_start + VDEV_PHYS_SIZE - 1;
+ break;
+ case TYPE_LABEL_PAD1:
+ record->zi_start = offsetof(vdev_label_t, vl_pad1);
+ record->zi_end = record->zi_start + VDEV_PAD_SIZE - 1;
+ break;
+ case TYPE_LABEL_PAD2:
+ record->zi_start = offsetof(vdev_label_t, vl_pad2);
+ record->zi_end = record->zi_start + VDEV_PAD_SIZE - 1;
+ break;
+ }
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zinject/zinject.c b/cddl/contrib/opensolaris/cmd/zinject/zinject.c
new file mode 100644
index 000000000000..bf42bc483830
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zinject/zinject.c
@@ -0,0 +1,1093 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ */
+
+/*
+ * ZFS Fault Injector
+ *
+ * This userland component takes a set of options and uses libzpool to translate
+ * from a user-visible object type and name to an internal representation.
+ * There are two basic types of faults: device faults and data faults.
+ *
+ *
+ * DEVICE FAULTS
+ *
+ * Errors can be injected into a particular vdev using the '-d' option. This
+ * option takes a path or vdev GUID to uniquely identify the device within a
+ * pool. There are two types of errors that can be injected, EIO and ENXIO,
+ * that can be controlled through the '-e' option. The default is ENXIO. For
+ * EIO failures, any attempt to read data from the device will return EIO, but
+ * subsequent attempt to reopen the device will succeed. For ENXIO failures,
+ * any attempt to read from the device will return EIO, but any attempt to
+ * reopen the device will also return ENXIO.
+ * For label faults, the -L option must be specified. This allows faults
+ * to be injected into either the nvlist, uberblock, pad1, or pad2 region
+ * of all the labels for the specified device.
+ *
+ * This form of the command looks like:
+ *
+ * zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool
+ *
+ *
+ * DATA FAULTS
+ *
+ * We begin with a tuple of the form:
+ *
+ * <type,level,range,object>
+ *
+ * type A string describing the type of data to target. Each type
+ * implicitly describes how to interpret 'object'. Currently,
+ * the following values are supported:
+ *
+ * data User data for a file
+ * dnode Dnode for a file or directory
+ *
+ * The following MOS objects are special. Instead of injecting
+ * errors on a particular object or blkid, we inject errors across
+ * all objects of the given type.
+ *
+ * mos Any data in the MOS
+ * mosdir object directory
+ * config pool configuration
+ * bpobj blkptr list
+ * spacemap spacemap
+ * metaslab metaslab
+ * errlog persistent error log
+ *
+ * level Object level. Defaults to '0', not applicable to all types. If
+ * a range is given, this corresponds to the indirect block
+ * corresponding to the specific range.
+ *
+ * range A numerical range [start,end) within the object. Defaults to
+ * the full size of the file.
+ *
+ * object A string describing the logical location of the object. For
+ * files and directories (currently the only supported types),
+ * this is the path of the object on disk.
+ *
+ * This is translated, via libzpool, into the following internal representation:
+ *
+ * <type,objset,object,level,range>
+ *
+ * These types should be self-explanatory. This tuple is then passed to the
+ * kernel via a special ioctl() to initiate fault injection for the given
+ * object. Note that 'type' is not strictly necessary for fault injection, but
+ * is used when translating existing faults into a human-readable string.
+ *
+ *
+ * The command itself takes one of the forms:
+ *
+ * zinject
+ * zinject <-a | -u pool>
+ * zinject -c <id|all>
+ * zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
+ * [-r range] <object>
+ * zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
+ *
+ * With no arguments, the command prints all currently registered injection
+ * handlers, with their numeric identifiers.
+ *
+ * The '-c' option will clear the given handler, or all handlers if 'all' is
+ * specified.
+ *
+ * The '-e' option takes a string describing the errno to simulate. This must
+ * be either 'io' or 'checksum'. In most cases this will result in the same
+ * behavior, but RAID-Z will produce a different set of ereports for this
+ * situation.
+ *
+ * The '-a', '-u', and '-m' flags toggle internal flush behavior. If '-a' is
+ * specified, then the ARC cache is flushed appropriately. If '-u' is
+ * specified, then the underlying SPA is unloaded. Either of these flags can be
+ * specified independently of any other handlers. The '-m' flag automatically
+ * does an unmount and remount of the underlying dataset to aid in flushing the
+ * cache.
+ *
+ * The '-f' flag controls the frequency of errors injected, expressed as a
+ * integer percentage between 1 and 100. The default is 100.
+ *
+ * The this form is responsible for actually injecting the handler into the
+ * framework. It takes the arguments described above, translates them to the
+ * internal tuple using libzpool, and then issues an ioctl() to register the
+ * handler.
+ *
+ * The final form can target a specific bookmark, regardless of whether a
+ * human-readable interface has been designed. It allows developers to specify
+ * a particular block by number.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <sys/fs/zfs.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <libzfs.h>
+#include <libzfs_compat.h>
+
+#undef verify /* both libzfs.h and zfs_context.h want to define this */
+
+#include "zinject.h"
+
+libzfs_handle_t *g_zfs;
+int zfs_fd;
+
+#ifndef ECKSUM
+#define ECKSUM EBADE
+#endif
+
+static const char *errtable[TYPE_INVAL] = {
+ "data",
+ "dnode",
+ "mos",
+ "mosdir",
+ "metaslab",
+ "config",
+ "bpobj",
+ "spacemap",
+ "errlog",
+ "uber",
+ "nvlist",
+ "pad1",
+ "pad2"
+};
+
+static err_type_t
+name_to_type(const char *arg)
+{
+ int i;
+ for (i = 0; i < TYPE_INVAL; i++)
+ if (strcmp(errtable[i], arg) == 0)
+ return (i);
+
+ return (TYPE_INVAL);
+}
+
+static const char *
+type_to_name(uint64_t type)
+{
+ switch (type) {
+ case DMU_OT_OBJECT_DIRECTORY:
+ return ("mosdir");
+ case DMU_OT_OBJECT_ARRAY:
+ return ("metaslab");
+ case DMU_OT_PACKED_NVLIST:
+ return ("config");
+ case DMU_OT_BPOBJ:
+ return ("bpobj");
+ case DMU_OT_SPACE_MAP:
+ return ("spacemap");
+ case DMU_OT_ERROR_LOG:
+ return ("errlog");
+ default:
+ return ("-");
+ }
+}
+
+
+/*
+ * Print usage message.
+ */
+void
+usage(void)
+{
+ (void) printf(
+ "usage:\n"
+ "\n"
+ "\tzinject\n"
+ "\n"
+ "\t\tList all active injection records.\n"
+ "\n"
+ "\tzinject -c <id|all>\n"
+ "\n"
+ "\t\tClear the particular record (if given a numeric ID), or\n"
+ "\t\tall records if 'all' is specificed.\n"
+ "\n"
+ "\tzinject -p <function name> pool\n"
+ "\n"
+ "\t\tInject a panic fault at the specified function. Only \n"
+ "\t\tfunctions which call spa_vdev_config_exit(), or \n"
+ "\t\tspa_vdev_exit() will trigger a panic.\n"
+ "\n"
+ "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
+ "\t [-T <read|write|free|claim|all> pool\n"
+ "\n"
+ "\t\tInject a fault into a particular device or the device's\n"
+ "\t\tlabel. Label injection can either be 'nvlist', 'uber',\n "
+ "\t\t'pad1', or 'pad2'.\n"
+ "\t\t'errno' can be 'nxio' (the default), 'io', or 'dtl'.\n"
+ "\n"
+ "\tzinject -d device -A <degrade|fault> pool\n"
+ "\n"
+ "\t\tPerform a specific action on a particular device\n"
+ "\n"
+ "\tzinject -d device -D latency:lanes pool\n"
+ "\n"
+ "\t\tAdd an artificial delay to IO requests on a particular\n"
+ "\t\tdevice, such that the requests take a minimum of 'latency'\n"
+ "\t\tmilliseconds to complete. Each delay has an associated\n"
+ "\t\tnumber of 'lanes' which defines the number of concurrent\n"
+ "\t\tIO requests that can be processed.\n"
+ "\n"
+ "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n"
+ "\t\tthe device will only be able to service a single IO request\n"
+ "\t\tat a time with each request taking 10 ms to complete. So,\n"
+ "\t\tif only a single request is submitted every 10 ms, the\n"
+ "\t\taverage latency will be 10 ms; but if more than one request\n"
+ "\t\tis submitted every 10 ms, the average latency will be more\n"
+ "\t\tthan 10 ms.\n"
+ "\n"
+ "\t\tSimilarly, if a delay of 10 ms is specified to have two\n"
+ "\t\tlanes (-D 10:2), then the device will be able to service\n"
+ "\t\ttwo requests at a time, each with a minimum latency of\n"
+ "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n"
+ "\t\tthe average latency will be 10 ms; but if more than two\n"
+ "\t\trequests are submitted every 10 ms, the average latency\n"
+ "\t\twill be more than 10 ms.\n"
+ "\n"
+ "\t\tAlso note, these delays are additive. So two invocations\n"
+ "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n"
+ "\t\tof '-D 10:2'. This also means, one can specify multiple\n"
+ "\t\tlanes with differing target latencies. For example, an\n"
+ "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n"
+ "\t\tcreate 3 lanes on the device; one lane with a latency\n"
+ "\t\tof 10 ms and two lanes with a 25 ms latency.\n"
+ "\n"
+ "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
+ "\n"
+ "\t\tCause the pool to stop writing blocks yet not\n"
+ "\t\treport errors for a duration. Simulates buggy hardware\n"
+ "\t\tthat fails to honor cache flush requests.\n"
+ "\t\tDefault duration is 30 seconds. The machine is panicked\n"
+ "\t\tat the end of the duration.\n"
+ "\n"
+ "\tzinject -b objset:object:level:blkid pool\n"
+ "\n"
+ "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
+ "\t\tspecified by the remaining tuple. Each number is in\n"
+ "\t\thexidecimal, and only one block can be specified.\n"
+ "\n"
+ "\tzinject [-q] <-t type> [-e errno] [-l level] [-r range]\n"
+ "\t [-a] [-m] [-u] [-f freq] <object>\n"
+ "\n"
+ "\t\tInject an error into the object specified by the '-t' option\n"
+ "\t\tand the object descriptor. The 'object' parameter is\n"
+ "\t\tinterperted depending on the '-t' option.\n"
+ "\n"
+ "\t\t-q\tQuiet mode. Only print out the handler number added.\n"
+ "\t\t-e\tInject a specific error. Must be either 'io' or\n"
+ "\t\t\t'checksum'. Default is 'io'.\n"
+ "\t\t-l\tInject error at a particular block level. Default is "
+ "0.\n"
+ "\t\t-m\tAutomatically remount underlying filesystem.\n"
+ "\t\t-r\tInject error over a particular logical range of an\n"
+ "\t\t\tobject. Will be translated to the appropriate blkid\n"
+ "\t\t\trange according to the object's properties.\n"
+ "\t\t-a\tFlush the ARC cache. Can be specified without any\n"
+ "\t\t\tassociated object.\n"
+ "\t\t-u\tUnload the associated pool. Can be specified with only\n"
+ "\t\t\ta pool object.\n"
+ "\t\t-f\tOnly inject errors a fraction of the time. Expressed as\n"
+ "\t\t\ta percentage between 1 and 100.\n"
+ "\n"
+ "\t-t data\t\tInject an error into the plain file contents of a\n"
+ "\t\t\tfile. The object must be specified as a complete path\n"
+ "\t\t\tto a file on a ZFS filesystem.\n"
+ "\n"
+ "\t-t dnode\tInject an error into the metadnode in the block\n"
+ "\t\t\tcorresponding to the dnode for a file or directory. The\n"
+ "\t\t\t'-r' option is incompatible with this mode. The object\n"
+ "\t\t\tis specified as a complete path to a file or directory\n"
+ "\t\t\ton a ZFS filesystem.\n"
+ "\n"
+ "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
+ "\t\t\ttype. Valid types are: mos, mosdir, config, bpobj,\n"
+ "\t\t\tspacemap, metaslab, errlog. The only valid <object> is\n"
+ "\t\t\tthe poolname.\n");
+}
+
+static int
+iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
+ void *data)
+{
+ zfs_cmd_t zc = { 0 };
+ int ret;
+
+ while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
+ if ((ret = func((int)zc.zc_guid, zc.zc_name,
+ &zc.zc_inject_record, data)) != 0)
+ return (ret);
+
+ if (errno != ENOENT) {
+ (void) fprintf(stderr, "Unable to list handlers: %s\n",
+ strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+print_data_handler(int id, const char *pool, zinject_record_t *record,
+ void *data)
+{
+ int *count = data;
+
+ if (record->zi_guid != 0 || record->zi_func[0] != '\0')
+ return (0);
+
+ if (*count == 0) {
+ (void) printf("%3s %-15s %-6s %-6s %-8s %3s %-15s\n",
+ "ID", "POOL", "OBJSET", "OBJECT", "TYPE", "LVL", "RANGE");
+ (void) printf("--- --------------- ------ "
+ "------ -------- --- ---------------\n");
+ }
+
+ *count += 1;
+
+ (void) printf("%3d %-15s %-6llu %-6llu %-8s %3d ", id, pool,
+ (u_longlong_t)record->zi_objset, (u_longlong_t)record->zi_object,
+ type_to_name(record->zi_type), record->zi_level);
+
+ if (record->zi_start == 0 &&
+ record->zi_end == -1ULL)
+ (void) printf("all\n");
+ else
+ (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
+ (u_longlong_t)record->zi_end);
+
+ return (0);
+}
+
+static int
+print_device_handler(int id, const char *pool, zinject_record_t *record,
+ void *data)
+{
+ int *count = data;
+
+ if (record->zi_guid == 0 || record->zi_func[0] != '\0')
+ return (0);
+
+ if (record->zi_cmd == ZINJECT_DELAY_IO)
+ return (0);
+
+ if (*count == 0) {
+ (void) printf("%3s %-15s %s\n", "ID", "POOL", "GUID");
+ (void) printf("--- --------------- ----------------\n");
+ }
+
+ *count += 1;
+
+ (void) printf("%3d %-15s %llx\n", id, pool,
+ (u_longlong_t)record->zi_guid);
+
+ return (0);
+}
+
+static int
+print_delay_handler(int id, const char *pool, zinject_record_t *record,
+ void *data)
+{
+ int *count = data;
+
+ if (record->zi_guid == 0 || record->zi_func[0] != '\0')
+ return (0);
+
+ if (record->zi_cmd != ZINJECT_DELAY_IO)
+ return (0);
+
+ if (*count == 0) {
+ (void) printf("%3s %-15s %-15s %-15s %s\n",
+ "ID", "POOL", "DELAY (ms)", "LANES", "GUID");
+ (void) printf("--- --------------- --------------- "
+ "--------------- ----------------\n");
+ }
+
+ *count += 1;
+
+ (void) printf("%3d %-15s %-15llu %-15llu %llx\n", id, pool,
+ (u_longlong_t)NSEC2MSEC(record->zi_timer),
+ (u_longlong_t)record->zi_nlanes,
+ (u_longlong_t)record->zi_guid);
+
+ return (0);
+}
+
+static int
+print_panic_handler(int id, const char *pool, zinject_record_t *record,
+ void *data)
+{
+ int *count = data;
+
+ if (record->zi_func[0] == '\0')
+ return (0);
+
+ if (*count == 0) {
+ (void) printf("%3s %-15s %s\n", "ID", "POOL", "FUNCTION");
+ (void) printf("--- --------------- ----------------\n");
+ }
+
+ *count += 1;
+
+ (void) printf("%3d %-15s %s\n", id, pool, record->zi_func);
+
+ return (0);
+}
+
+/*
+ * Print all registered error handlers. Returns the number of handlers
+ * registered.
+ */
+static int
+print_all_handlers(void)
+{
+ int count = 0, total = 0;
+
+ (void) iter_handlers(print_device_handler, &count);
+ if (count > 0) {
+ total += count;
+ (void) printf("\n");
+ count = 0;
+ }
+
+ (void) iter_handlers(print_delay_handler, &count);
+ if (count > 0) {
+ total += count;
+ (void) printf("\n");
+ count = 0;
+ }
+
+ (void) iter_handlers(print_data_handler, &count);
+ if (count > 0) {
+ total += count;
+ (void) printf("\n");
+ count = 0;
+ }
+
+ (void) iter_handlers(print_panic_handler, &count);
+
+ return (count + total);
+}
+
+/* ARGSUSED */
+static int
+cancel_one_handler(int id, const char *pool, zinject_record_t *record,
+ void *data)
+{
+ zfs_cmd_t zc = { 0 };
+
+ zc.zc_guid = (uint64_t)id;
+
+ if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
+ (void) fprintf(stderr, "failed to remove handler %d: %s\n",
+ id, strerror(errno));
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Remove all fault injection handlers.
+ */
+static int
+cancel_all_handlers(void)
+{
+ int ret = iter_handlers(cancel_one_handler, NULL);
+
+ if (ret == 0)
+ (void) printf("removed all registered handlers\n");
+
+ return (ret);
+}
+
+/*
+ * Remove a specific fault injection handler.
+ */
+static int
+cancel_handler(int id)
+{
+ zfs_cmd_t zc = { 0 };
+
+ zc.zc_guid = (uint64_t)id;
+
+ if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
+ (void) fprintf(stderr, "failed to remove handler %d: %s\n",
+ id, strerror(errno));
+ return (1);
+ }
+
+ (void) printf("removed handler %d\n", id);
+
+ return (0);
+}
+
+/*
+ * Register a new fault injection handler.
+ */
+static int
+register_handler(const char *pool, int flags, zinject_record_t *record,
+ int quiet)
+{
+ zfs_cmd_t zc = { 0 };
+
+ (void) strcpy(zc.zc_name, pool);
+ zc.zc_inject_record = *record;
+ zc.zc_guid = flags;
+
+ if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
+ (void) fprintf(stderr, "failed to add handler: %s\n",
+ strerror(errno));
+ return (1);
+ }
+
+ if (flags & ZINJECT_NULL)
+ return (0);
+
+ if (quiet) {
+ (void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
+ } else {
+ (void) printf("Added handler %llu with the following "
+ "properties:\n", (u_longlong_t)zc.zc_guid);
+ (void) printf(" pool: %s\n", pool);
+ if (record->zi_guid) {
+ (void) printf(" vdev: %llx\n",
+ (u_longlong_t)record->zi_guid);
+ } else if (record->zi_func[0] != '\0') {
+ (void) printf(" panic function: %s\n",
+ record->zi_func);
+ } else if (record->zi_duration > 0) {
+ (void) printf(" time: %lld seconds\n",
+ (u_longlong_t)record->zi_duration);
+ } else if (record->zi_duration < 0) {
+ (void) printf(" txgs: %lld \n",
+ (u_longlong_t)-record->zi_duration);
+ } else {
+ (void) printf("objset: %llu\n",
+ (u_longlong_t)record->zi_objset);
+ (void) printf("object: %llu\n",
+ (u_longlong_t)record->zi_object);
+ (void) printf(" type: %llu\n",
+ (u_longlong_t)record->zi_type);
+ (void) printf(" level: %d\n", record->zi_level);
+ if (record->zi_start == 0 &&
+ record->zi_end == -1ULL)
+ (void) printf(" range: all\n");
+ else
+ (void) printf(" range: [%llu, %llu)\n",
+ (u_longlong_t)record->zi_start,
+ (u_longlong_t)record->zi_end);
+ }
+ }
+
+ return (0);
+}
+
+int
+perform_action(const char *pool, zinject_record_t *record, int cmd)
+{
+ zfs_cmd_t zc = { 0 };
+
+ ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
+ (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
+ zc.zc_guid = record->zi_guid;
+ zc.zc_cookie = cmd;
+
+ if (ioctl(zfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+ return (0);
+
+ return (1);
+}
+
+static int
+parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
+{
+ unsigned long scan_delay;
+ unsigned long scan_nlanes;
+
+ if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2)
+ return (1);
+
+ /*
+ * We explicitly disallow a delay of zero here, because we key
+ * off this value being non-zero in translate_device(), to
+ * determine if the fault is a ZINJECT_DELAY_IO fault or not.
+ */
+ if (scan_delay == 0)
+ return (1);
+
+ /*
+ * The units for the CLI delay parameter is milliseconds, but
+ * the data passed to the kernel is interpreted as nanoseconds.
+ * Thus we scale the milliseconds to nanoseconds here, and this
+ * nanosecond value is used to pass the delay to the kernel.
+ */
+ *delay = MSEC2NSEC(scan_delay);
+ *nlanes = scan_nlanes;
+
+ return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ char *range = NULL;
+ char *cancel = NULL;
+ char *end;
+ char *raw = NULL;
+ char *device = NULL;
+ int level = 0;
+ int quiet = 0;
+ int error = 0;
+ int domount = 0;
+ int io_type = ZIO_TYPES;
+ int action = VDEV_STATE_UNKNOWN;
+ err_type_t type = TYPE_INVAL;
+ err_type_t label = TYPE_INVAL;
+ zinject_record_t record = { 0 };
+ char pool[MAXNAMELEN];
+ char dataset[MAXNAMELEN];
+ zfs_handle_t *zhp;
+ int nowrites = 0;
+ int dur_txg = 0;
+ int dur_secs = 0;
+ int ret;
+ int flags = 0;
+
+ if ((g_zfs = libzfs_init()) == NULL) {
+ (void) fprintf(stderr, "internal error: failed to "
+ "initialize ZFS library\n");
+ return (1);
+ }
+
+ libzfs_print_on_error(g_zfs, B_TRUE);
+
+ if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
+ (void) fprintf(stderr, "failed to open ZFS device\n");
+ return (1);
+ }
+
+ if (argc == 1) {
+ /*
+ * No arguments. Print the available handlers. If there are no
+ * available handlers, direct the user to '-h' for help
+ * information.
+ */
+ if (print_all_handlers() == 0) {
+ (void) printf("No handlers registered.\n");
+ (void) printf("Run 'zinject -h' for usage "
+ "information.\n");
+ }
+
+ return (0);
+ }
+
+ while ((c = getopt(argc, argv,
+ ":aA:b:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
+ switch (c) {
+ case 'a':
+ flags |= ZINJECT_FLUSH_ARC;
+ break;
+ case 'A':
+ if (strcasecmp(optarg, "degrade") == 0) {
+ action = VDEV_STATE_DEGRADED;
+ } else if (strcasecmp(optarg, "fault") == 0) {
+ action = VDEV_STATE_FAULTED;
+ } else {
+ (void) fprintf(stderr, "invalid action '%s': "
+ "must be 'degrade' or 'fault'\n", optarg);
+ usage();
+ return (1);
+ }
+ break;
+ case 'b':
+ raw = optarg;
+ break;
+ case 'c':
+ cancel = optarg;
+ break;
+ case 'd':
+ device = optarg;
+ break;
+ case 'D':
+ ret = parse_delay(optarg, &record.zi_timer,
+ &record.zi_nlanes);
+ if (ret != 0) {
+ (void) fprintf(stderr, "invalid i/o delay "
+ "value: '%s'\n", optarg);
+ usage();
+ return (1);
+ }
+ break;
+ case 'e':
+ if (strcasecmp(optarg, "io") == 0) {
+ error = EIO;
+ } else if (strcasecmp(optarg, "checksum") == 0) {
+ error = ECKSUM;
+ } else if (strcasecmp(optarg, "nxio") == 0) {
+ error = ENXIO;
+ } else if (strcasecmp(optarg, "dtl") == 0) {
+ error = ECHILD;
+ } else {
+ (void) fprintf(stderr, "invalid error type "
+ "'%s': must be 'io', 'checksum' or "
+ "'nxio'\n", optarg);
+ usage();
+ return (1);
+ }
+ break;
+ case 'f':
+ record.zi_freq = atoi(optarg);
+ if (record.zi_freq < 1 || record.zi_freq > 100) {
+ (void) fprintf(stderr, "frequency range must "
+ "be in the range (0, 100]\n");
+ return (1);
+ }
+ break;
+ case 'F':
+ record.zi_failfast = B_TRUE;
+ break;
+ case 'g':
+ dur_txg = 1;
+ record.zi_duration = (int)strtol(optarg, &end, 10);
+ if (record.zi_duration <= 0 || *end != '\0') {
+ (void) fprintf(stderr, "invalid duration '%s': "
+ "must be a positive integer\n", optarg);
+ usage();
+ return (1);
+ }
+ /* store duration of txgs as its negative */
+ record.zi_duration *= -1;
+ break;
+ case 'h':
+ usage();
+ return (0);
+ case 'I':
+ /* default duration, if one hasn't yet been defined */
+ nowrites = 1;
+ if (dur_secs == 0 && dur_txg == 0)
+ record.zi_duration = 30;
+ break;
+ case 'l':
+ level = (int)strtol(optarg, &end, 10);
+ if (*end != '\0') {
+ (void) fprintf(stderr, "invalid level '%s': "
+ "must be an integer\n", optarg);
+ usage();
+ return (1);
+ }
+ break;
+ case 'm':
+ domount = 1;
+ break;
+ case 'p':
+ (void) strlcpy(record.zi_func, optarg,
+ sizeof (record.zi_func));
+ record.zi_cmd = ZINJECT_PANIC;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'r':
+ range = optarg;
+ break;
+ case 's':
+ dur_secs = 1;
+ record.zi_duration = (int)strtol(optarg, &end, 10);
+ if (record.zi_duration <= 0 || *end != '\0') {
+ (void) fprintf(stderr, "invalid duration '%s': "
+ "must be a positive integer\n", optarg);
+ usage();
+ return (1);
+ }
+ break;
+ case 'T':
+ if (strcasecmp(optarg, "read") == 0) {
+ io_type = ZIO_TYPE_READ;
+ } else if (strcasecmp(optarg, "write") == 0) {
+ io_type = ZIO_TYPE_WRITE;
+ } else if (strcasecmp(optarg, "free") == 0) {
+ io_type = ZIO_TYPE_FREE;
+ } else if (strcasecmp(optarg, "claim") == 0) {
+ io_type = ZIO_TYPE_CLAIM;
+ } else if (strcasecmp(optarg, "all") == 0) {
+ io_type = ZIO_TYPES;
+ } else {
+ (void) fprintf(stderr, "invalid I/O type "
+ "'%s': must be 'read', 'write', 'free', "
+ "'claim' or 'all'\n", optarg);
+ usage();
+ return (1);
+ }
+ break;
+ case 't':
+ if ((type = name_to_type(optarg)) == TYPE_INVAL &&
+ !MOS_TYPE(type)) {
+ (void) fprintf(stderr, "invalid type '%s'\n",
+ optarg);
+ usage();
+ return (1);
+ }
+ break;
+ case 'u':
+ flags |= ZINJECT_UNLOAD_SPA;
+ break;
+ case 'L':
+ if ((label = name_to_type(optarg)) == TYPE_INVAL &&
+ !LABEL_TYPE(type)) {
+ (void) fprintf(stderr, "invalid label type "
+ "'%s'\n", optarg);
+ usage();
+ return (1);
+ }
+ break;
+ case ':':
+ (void) fprintf(stderr, "option -%c requires an "
+ "operand\n", optopt);
+ usage();
+ return (1);
+ case '?':
+ (void) fprintf(stderr, "invalid option '%c'\n",
+ optopt);
+ usage();
+ return (2);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (record.zi_duration != 0)
+ record.zi_cmd = ZINJECT_IGNORED_WRITES;
+
+ if (cancel != NULL) {
+ /*
+ * '-c' is invalid with any other options.
+ */
+ if (raw != NULL || range != NULL || type != TYPE_INVAL ||
+ level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
+ (void) fprintf(stderr, "cancel (-c) incompatible with "
+ "any other options\n");
+ usage();
+ return (2);
+ }
+ if (argc != 0) {
+ (void) fprintf(stderr, "extraneous argument to '-c'\n");
+ usage();
+ return (2);
+ }
+
+ if (strcmp(cancel, "all") == 0) {
+ return (cancel_all_handlers());
+ } else {
+ int id = (int)strtol(cancel, &end, 10);
+ if (*end != '\0') {
+ (void) fprintf(stderr, "invalid handle id '%s':"
+ " must be an integer or 'all'\n", cancel);
+ usage();
+ return (1);
+ }
+ return (cancel_handler(id));
+ }
+ }
+
+ if (device != NULL) {
+ /*
+ * Device (-d) injection uses a completely different mechanism
+ * for doing injection, so handle it separately here.
+ */
+ if (raw != NULL || range != NULL || type != TYPE_INVAL ||
+ level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
+ (void) fprintf(stderr, "device (-d) incompatible with "
+ "data error injection\n");
+ usage();
+ return (2);
+ }
+
+ if (argc != 1) {
+ (void) fprintf(stderr, "device (-d) injection requires "
+ "a single pool name\n");
+ usage();
+ return (2);
+ }
+
+ (void) strcpy(pool, argv[0]);
+ dataset[0] = '\0';
+
+ if (error == ECKSUM) {
+ (void) fprintf(stderr, "device error type must be "
+ "'io' or 'nxio'\n");
+ return (1);
+ }
+
+ record.zi_iotype = io_type;
+ if (translate_device(pool, device, label, &record) != 0)
+ return (1);
+ if (!error)
+ error = ENXIO;
+
+ if (action != VDEV_STATE_UNKNOWN)
+ return (perform_action(pool, &record, action));
+
+ } else if (raw != NULL) {
+ if (range != NULL || type != TYPE_INVAL || level != 0 ||
+ record.zi_cmd != ZINJECT_UNINITIALIZED) {
+ (void) fprintf(stderr, "raw (-b) format with "
+ "any other options\n");
+ usage();
+ return (2);
+ }
+
+ if (argc != 1) {
+ (void) fprintf(stderr, "raw (-b) format expects a "
+ "single pool name\n");
+ usage();
+ return (2);
+ }
+
+ (void) strcpy(pool, argv[0]);
+ dataset[0] = '\0';
+
+ if (error == ENXIO) {
+ (void) fprintf(stderr, "data error type must be "
+ "'checksum' or 'io'\n");
+ return (1);
+ }
+
+ record.zi_cmd = ZINJECT_DATA_FAULT;
+ if (translate_raw(raw, &record) != 0)
+ return (1);
+ if (!error)
+ error = EIO;
+ } else if (record.zi_cmd == ZINJECT_PANIC) {
+ if (raw != NULL || range != NULL || type != TYPE_INVAL ||
+ level != 0 || device != NULL) {
+ (void) fprintf(stderr, "panic (-p) incompatible with "
+ "other options\n");
+ usage();
+ return (2);
+ }
+
+ if (argc < 1 || argc > 2) {
+ (void) fprintf(stderr, "panic (-p) injection requires "
+ "a single pool name and an optional id\n");
+ usage();
+ return (2);
+ }
+
+ (void) strcpy(pool, argv[0]);
+ if (argv[1] != NULL)
+ record.zi_type = atoi(argv[1]);
+ dataset[0] = '\0';
+ } else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
+ if (nowrites == 0) {
+ (void) fprintf(stderr, "-s or -g meaningless "
+ "without -I (ignore writes)\n");
+ usage();
+ return (2);
+ } else if (dur_secs && dur_txg) {
+ (void) fprintf(stderr, "choose a duration either "
+ "in seconds (-s) or a number of txgs (-g) "
+ "but not both\n");
+ usage();
+ return (2);
+ } else if (argc != 1) {
+ (void) fprintf(stderr, "ignore writes (-I) "
+ "injection requires a single pool name\n");
+ usage();
+ return (2);
+ }
+
+ (void) strcpy(pool, argv[0]);
+ dataset[0] = '\0';
+ } else if (type == TYPE_INVAL) {
+ if (flags == 0) {
+ (void) fprintf(stderr, "at least one of '-b', '-d', "
+ "'-t', '-a', '-p', '-I' or '-u' "
+ "must be specified\n");
+ usage();
+ return (2);
+ }
+
+ if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
+ (void) strcpy(pool, argv[0]);
+ dataset[0] = '\0';
+ } else if (argc != 0) {
+ (void) fprintf(stderr, "extraneous argument for "
+ "'-f'\n");
+ usage();
+ return (2);
+ }
+
+ flags |= ZINJECT_NULL;
+ } else {
+ if (argc != 1) {
+ (void) fprintf(stderr, "missing object\n");
+ usage();
+ return (2);
+ }
+
+ if (error == ENXIO) {
+ (void) fprintf(stderr, "data error type must be "
+ "'checksum' or 'io'\n");
+ return (1);
+ }
+
+ record.zi_cmd = ZINJECT_DATA_FAULT;
+ if (translate_record(type, argv[0], range, level, &record, pool,
+ dataset) != 0)
+ return (1);
+ if (!error)
+ error = EIO;
+ }
+
+ /*
+ * If this is pool-wide metadata, unmount everything. The ioctl() will
+ * unload the pool, so that we trigger spa-wide reopen of metadata next
+ * time we access the pool.
+ */
+ if (dataset[0] != '\0' && domount) {
+ if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
+ return (1);
+
+ if (zfs_unmount(zhp, NULL, 0) != 0)
+ return (1);
+ }
+
+ record.zi_error = error;
+
+ ret = register_handler(pool, flags, &record, quiet);
+
+ if (dataset[0] != '\0' && domount)
+ ret = (zfs_mount(zhp, NULL, 0) != 0);
+
+ libzfs_fini(g_zfs);
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zinject/zinject.h b/cddl/contrib/opensolaris/cmd/zinject/zinject.h
new file mode 100644
index 000000000000..46fdcad8b31f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zinject/zinject.h
@@ -0,0 +1,70 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _ZINJECT_H
+#define _ZINJECT_H
+
+#include <sys/zfs_ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ TYPE_DATA, /* plain file contents */
+ TYPE_DNODE, /* metadnode contents */
+ TYPE_MOS, /* all MOS data */
+ TYPE_MOSDIR, /* MOS object directory */
+ TYPE_METASLAB, /* metaslab objects */
+ TYPE_CONFIG, /* MOS config */
+ TYPE_BPOBJ, /* block pointer list */
+ TYPE_SPACEMAP, /* space map objects */
+ TYPE_ERRLOG, /* persistent error log */
+ TYPE_LABEL_UBERBLOCK, /* label specific uberblock */
+ TYPE_LABEL_NVLIST, /* label specific nvlist */
+ TYPE_LABEL_PAD1, /* label specific 8K pad1 area */
+ TYPE_LABEL_PAD2, /* label specific 8K pad2 area */
+ TYPE_INVAL
+} err_type_t;
+
+#define MOS_TYPE(t) \
+ ((t) >= TYPE_MOS && (t) < TYPE_LABEL_UBERBLOCK)
+
+#define LABEL_TYPE(t) \
+ ((t) >= TYPE_LABEL_UBERBLOCK && (t) < TYPE_INVAL)
+
+int translate_record(err_type_t type, const char *object, const char *range,
+ int level, zinject_record_t *record, char *poolname, char *dataset);
+int translate_raw(const char *raw, zinject_record_t *record);
+int translate_device(const char *pool, const char *device,
+ err_type_t label_type, zinject_record_t *record);
+void usage(void);
+
+extern libzfs_handle_t *g_zfs;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZINJECT_H */
diff --git a/cddl/contrib/opensolaris/cmd/zlook/zlook.c b/cddl/contrib/opensolaris/cmd/zlook/zlook.c
new file mode 100644
index 000000000000..29a6559f9023
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zlook/zlook.c
@@ -0,0 +1,411 @@
+/*
+ * 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * This is a test program that uses ioctls to the ZFS Unit Test driver
+ * to perform readdirs or lookups using flags not normally available
+ * to user-land programs. This allows testing of the flags'
+ * behavior outside of a complicated consumer, such as the SMB driver.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/dirent.h>
+#include <sys/attr.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+
+#define _KERNEL
+
+#include <sys/fs/zut.h>
+#include <sys/extdirent.h>
+
+#undef _KERNEL
+
+#define MAXBUF (64 * 1024)
+#define BIGBUF 4096
+#define LILBUF (sizeof (dirent_t))
+
+#define DIRENT_NAMELEN(reclen) \
+ ((reclen) - (offsetof(dirent_t, d_name[0])))
+
+static void
+usage(char *pnam)
+{
+ (void) fprintf(stderr, "Usage:\n %s -l [-is] dir-to-look-in "
+ "file-in-dir [xfile-on-file]\n", pnam);
+ (void) fprintf(stderr, " %s -i [-ls] dir-to-look-in "
+ "file-in-dir [xfile-on-file]\n", pnam);
+ (void) fprintf(stderr, " %s -s [-il] dir-to-look-in "
+ "file-in-dir [xfile-on-file]\n", pnam);
+ (void) fprintf(stderr, "\t Perform a lookup\n");
+ (void) fprintf(stderr, "\t -l == lookup\n");
+ (void) fprintf(stderr, "\t -i == request FIGNORECASE\n");
+ (void) fprintf(stderr, "\t -s == request stat(2) and xvattr info\n");
+ (void) fprintf(stderr, " %s -r [-ea] [-b buffer-size-in-bytes] "
+ "dir-to-look-in [file-in-dir]\n", pnam);
+ (void) fprintf(stderr, " %s -e [-ra] [-b buffer-size-in-bytes] "
+ "dir-to-look-in [file-in-dir]\n", pnam);
+ (void) fprintf(stderr, " %s -a [-re] [-b buffer-size-in-bytes] "
+ "dir-to-look-in [file-in-dir]\n", pnam);
+ (void) fprintf(stderr, "\t Perform a readdir\n");
+ (void) fprintf(stderr, "\t -r == readdir\n");
+ (void) fprintf(stderr, "\t -e == request extended entries\n");
+ (void) fprintf(stderr, "\t -a == request access filtering\n");
+ (void) fprintf(stderr, "\t -b == buffer size (default 4K)\n");
+ (void) fprintf(stderr, " %s -A path\n", pnam);
+ (void) fprintf(stderr, "\t Look up _PC_ACCESS_FILTERING "
+ "for path with pathconf(2)\n");
+ (void) fprintf(stderr, " %s -E path\n", pnam);
+ (void) fprintf(stderr, "\t Look up _PC_SATTR_EXISTS "
+ "for path with pathconf(2)\n");
+ (void) fprintf(stderr, " %s -S path\n", pnam);
+ (void) fprintf(stderr, "\t Look up _PC_SATTR_EXISTS "
+ "for path with pathconf(2)\n");
+ exit(EINVAL);
+}
+
+static void
+print_extd_entries(zut_readdir_t *r)
+{
+ struct edirent *eodp;
+ char *bufstart;
+
+ eodp = (edirent_t *)(uintptr_t)r->zr_buf;
+ bufstart = (char *)eodp;
+ while ((char *)eodp < bufstart + r->zr_bytes) {
+ char *blanks = " ";
+ int i = 0;
+ while (i < EDIRENT_NAMELEN(eodp->ed_reclen)) {
+ if (!eodp->ed_name[i])
+ break;
+ (void) printf("%c", eodp->ed_name[i++]);
+ }
+ if (i < 16)
+ (void) printf("%.*s", 16 - i, blanks);
+ (void) printf("\t%x\n", eodp->ed_eflags);
+ eodp = (edirent_t *)((intptr_t)eodp + eodp->ed_reclen);
+ }
+}
+
+static void
+print_entries(zut_readdir_t *r)
+{
+ dirent64_t *dp;
+ char *bufstart;
+
+ dp = (dirent64_t *)(intptr_t)r->zr_buf;
+ bufstart = (char *)dp;
+ while ((char *)dp < bufstart + r->zr_bytes) {
+ int i = 0;
+ while (i < DIRENT_NAMELEN(dp->d_reclen)) {
+ if (!dp->d_name[i])
+ break;
+ (void) printf("%c", dp->d_name[i++]);
+ }
+ (void) printf("\n");
+ dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen);
+ }
+}
+
+static void
+print_stats(struct stat64 *sb)
+{
+ char timebuf[512];
+
+ (void) printf("st_mode\t\t\t%04lo\n", (unsigned long)sb->st_mode);
+ (void) printf("st_ino\t\t\t%llu\n", (unsigned long long)sb->st_ino);
+ (void) printf("st_nlink\t\t%lu\n", (unsigned long)sb->st_nlink);
+ (void) printf("st_uid\t\t\t%d\n", sb->st_uid);
+ (void) printf("st_gid\t\t\t%d\n", sb->st_gid);
+ (void) printf("st_size\t\t\t%lld\n", (long long)sb->st_size);
+ (void) printf("st_blksize\t\t%ld\n", (long)sb->st_blksize);
+ (void) printf("st_blocks\t\t%lld\n", (long long)sb->st_blocks);
+
+ timebuf[0] = 0;
+ if (ctime_r(&sb->st_atime, timebuf, 512)) {
+ (void) printf("st_atime\t\t");
+ (void) printf("%s", timebuf);
+ }
+ timebuf[0] = 0;
+ if (ctime_r(&sb->st_mtime, timebuf, 512)) {
+ (void) printf("st_mtime\t\t");
+ (void) printf("%s", timebuf);
+ }
+ timebuf[0] = 0;
+ if (ctime_r(&sb->st_ctime, timebuf, 512)) {
+ (void) printf("st_ctime\t\t");
+ (void) printf("%s", timebuf);
+ }
+}
+
+static void
+print_xvs(uint64_t xvs)
+{
+ uint_t bits;
+ int idx = 0;
+
+ if (xvs == 0)
+ return;
+
+ (void) printf("-------------------\n");
+ (void) printf("Attribute bit(s) set:\n");
+ (void) printf("-------------------\n");
+
+ bits = xvs & ((1 << F_ATTR_ALL) - 1);
+ while (bits) {
+ uint_t rest = bits >> 1;
+ if (bits & 1) {
+ (void) printf("%s", attr_to_name((f_attr_t)idx));
+ if (rest)
+ (void) printf(", ");
+ }
+ idx++;
+ bits = rest;
+ }
+ (void) printf("\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ zut_lookup_t lk = {0};
+ zut_readdir_t rd = {0};
+ boolean_t checking = B_FALSE;
+ boolean_t looking = B_FALSE;
+ boolean_t reading = B_FALSE;
+ boolean_t bflag = B_FALSE;
+ long rddir_bufsize = BIGBUF;
+ int error = 0;
+ int check;
+ int fd;
+ int c;
+
+ while ((c = getopt(argc, argv, "lisaerb:ASE")) != -1) {
+ switch (c) {
+ case 'l':
+ looking = B_TRUE;
+ break;
+ case 'i':
+ lk.zl_reqflags |= ZUT_IGNORECASE;
+ looking = B_TRUE;
+ break;
+ case 's':
+ lk.zl_reqflags |= ZUT_GETSTAT;
+ looking = B_TRUE;
+ break;
+ case 'a':
+ rd.zr_reqflags |= ZUT_ACCFILTER;
+ reading = B_TRUE;
+ break;
+ case 'e':
+ rd.zr_reqflags |= ZUT_EXTRDDIR;
+ reading = B_TRUE;
+ break;
+ case 'r':
+ reading = B_TRUE;
+ break;
+ case 'b':
+ reading = B_TRUE;
+ bflag = B_TRUE;
+ rddir_bufsize = strtol(optarg, NULL, 0);
+ break;
+ case 'A':
+ checking = B_TRUE;
+ check = _PC_ACCESS_FILTERING;
+ break;
+ case 'S':
+ checking = B_TRUE;
+ check = _PC_SATTR_ENABLED;
+ break;
+ case 'E':
+ checking = B_TRUE;
+ check = _PC_SATTR_EXISTS;
+ break;
+ case '?':
+ default:
+ usage(argv[0]); /* no return */
+ }
+ }
+
+ if ((checking && looking) || (checking && reading) ||
+ (looking && reading) || (!reading && bflag) ||
+ (!checking && !reading && !looking))
+ usage(argv[0]); /* no return */
+
+ if (rddir_bufsize < LILBUF || rddir_bufsize > MAXBUF) {
+ (void) fprintf(stderr, "Sorry, buffer size "
+ "must be >= %d and less than or equal to %d bytes.\n",
+ (int)LILBUF, MAXBUF);
+ exit(EINVAL);
+ }
+
+ if (checking) {
+ char pathbuf[MAXPATHLEN];
+ long result;
+
+ if (argc - optind < 1)
+ usage(argv[0]); /* no return */
+ (void) strlcpy(pathbuf, argv[optind], MAXPATHLEN);
+ result = pathconf(pathbuf, check);
+ (void) printf("pathconf(2) check for %s\n", pathbuf);
+ switch (check) {
+ case _PC_SATTR_ENABLED:
+ (void) printf("System attributes ");
+ if (result != 0)
+ (void) printf("Enabled\n");
+ else
+ (void) printf("Not enabled\n");
+ break;
+ case _PC_SATTR_EXISTS:
+ (void) printf("System attributes ");
+ if (result != 0)
+ (void) printf("Exist\n");
+ else
+ (void) printf("Do not exist\n");
+ break;
+ case _PC_ACCESS_FILTERING:
+ (void) printf("Access filtering ");
+ if (result != 0)
+ (void) printf("Available\n");
+ else
+ (void) printf("Not available\n");
+ break;
+ }
+ return (result);
+ }
+
+ if ((fd = open(ZUT_DEV, O_RDONLY)) < 0) {
+ perror(ZUT_DEV);
+ return (ENXIO);
+ }
+
+ if (reading) {
+ char *buf;
+
+ if (argc - optind < 1)
+ usage(argv[0]); /* no return */
+
+ (void) strlcpy(rd.zr_dir, argv[optind], MAXPATHLEN);
+ if (argc - optind > 1) {
+ (void) strlcpy(rd.zr_file, argv[optind + 1],
+ MAXNAMELEN);
+ rd.zr_reqflags |= ZUT_XATTR;
+ }
+
+ if ((buf = malloc(rddir_bufsize)) == NULL) {
+ error = errno;
+ perror("malloc");
+ (void) close(fd);
+ return (error);
+ }
+
+ rd.zr_buf = (uint64_t)(uintptr_t)buf;
+ rd.zr_buflen = rddir_bufsize;
+
+ while (!rd.zr_eof) {
+ int ierr;
+
+ if ((ierr = ioctl(fd, ZUT_IOC_READDIR, &rd)) != 0) {
+ (void) fprintf(stderr,
+ "IOCTL error: %s (%d)\n",
+ strerror(ierr), ierr);
+ free(buf);
+ (void) close(fd);
+ return (ierr);
+ }
+ if (rd.zr_retcode) {
+ (void) fprintf(stderr,
+ "readdir result: %s (%d)\n",
+ strerror(rd.zr_retcode), rd.zr_retcode);
+ free(buf);
+ (void) close(fd);
+ return (rd.zr_retcode);
+ }
+ if (rd.zr_reqflags & ZUT_EXTRDDIR)
+ print_extd_entries(&rd);
+ else
+ print_entries(&rd);
+ }
+ free(buf);
+ } else {
+ int ierr;
+
+ if (argc - optind < 2)
+ usage(argv[0]); /* no return */
+
+ (void) strlcpy(lk.zl_dir, argv[optind], MAXPATHLEN);
+ (void) strlcpy(lk.zl_file, argv[optind + 1], MAXNAMELEN);
+ if (argc - optind > 2) {
+ (void) strlcpy(lk.zl_xfile,
+ argv[optind + 2], MAXNAMELEN);
+ lk.zl_reqflags |= ZUT_XATTR;
+ }
+
+ if ((ierr = ioctl(fd, ZUT_IOC_LOOKUP, &lk)) != 0) {
+ (void) fprintf(stderr,
+ "IOCTL error: %s (%d)\n",
+ strerror(ierr), ierr);
+ (void) close(fd);
+ return (ierr);
+ }
+
+ (void) printf("\nLookup of ");
+ if (lk.zl_reqflags & ZUT_XATTR) {
+ (void) printf("extended attribute \"%s\" of ",
+ lk.zl_xfile);
+ }
+ (void) printf("file \"%s\" ", lk.zl_file);
+ (void) printf("in directory \"%s\" ", lk.zl_dir);
+ if (lk.zl_retcode) {
+ (void) printf("failed: %s (%d)\n",
+ strerror(lk.zl_retcode), lk.zl_retcode);
+ (void) close(fd);
+ return (lk.zl_retcode);
+ }
+
+ (void) printf("succeeded.\n");
+ if (lk.zl_reqflags & ZUT_IGNORECASE) {
+ (void) printf("----------------------------\n");
+ (void) printf("dirent flags: 0x%0x\n", lk.zl_deflags);
+ (void) printf("real name: %s\n", lk.zl_real);
+ }
+ if (lk.zl_reqflags & ZUT_GETSTAT) {
+ (void) printf("----------------------------\n");
+ print_stats(&lk.zl_statbuf);
+ print_xvs(lk.zl_xvattrs);
+ }
+ }
+
+ (void) close(fd);
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7 b/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
new file mode 100644
index 000000000000..b40bf9b5b1c7
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
@@ -0,0 +1,672 @@
+'\" te
+.\" Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>.
+.\" All Rights Reserved.
+.\"
+.\" 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]
+.\"
+.\" Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+.\" Copyright (c) 2013, Joyent, Inc. All rights reserved.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 16, 2019
+.Dt ZPOOL-FEATURES 7
+.Os
+.Sh NAME
+.Nm zpool-features
+.Nd ZFS pool feature descriptions
+.Sh DESCRIPTION
+ZFS pool on\-disk format versions are specified via "features" which replace
+the old on\-disk format numbers (the last supported on\-disk format number is
+28).
+To enable a feature on a pool use the
+.Cm upgrade
+subcommand of the
+.Xr zpool 8
+command, or set the
+.Sy feature@feature_name
+property to
+.Ar enabled .
+.Pp
+The pool format does not affect file system version compatibility or the ability
+to send file systems between pools.
+.Pp
+Since most features can be enabled independently of each other the on\-disk
+format of the pool is specified by the set of all features marked as
+.Sy active
+on the pool.
+If the pool was created by another software version this set may
+include unsupported features.
+.Ss Identifying features
+Every feature has a guid of the form
+.Sy com.example:feature_name .
+The reverse DNS name ensures that the feature's guid is unique across all ZFS
+implementations.
+When unsupported features are encountered on a pool they will
+be identified by their guids.
+Refer to the documentation for the ZFS implementation that created the pool
+for information about those features.
+.Pp
+Each supported feature also has a short name.
+By convention a feature's short name is the portion of its guid which follows
+the ':' (e.g.
+.Sy com.example:feature_name
+would have the short name
+.Sy feature_name ),
+however a feature's short name may differ across ZFS implementations if
+following the convention would result in name conflicts.
+.Ss Feature states
+Features can be in one of three states:
+.Bl -tag -width "XXXXXXXX"
+.It Sy active
+This feature's on\-disk format changes are in effect on the pool.
+Support for this feature is required to import the pool in read\-write mode.
+If this feature is not read-only compatible, support is also required to
+import the pool in read\-only mode (see "Read\-only compatibility").
+.It Sy enabled
+An administrator has marked this feature as enabled on the pool, but the
+feature's on\-disk format changes have not been made yet.
+The pool can still be imported by software that does not support this feature,
+but changes may be made to the on\-disk format at any time which will move
+the feature to the
+.Sy active
+state.
+Some features may support returning to the
+.Sy enabled
+state after becoming
+.Sy active .
+See feature\-specific documentation for details.
+.It Sy disabled
+This feature's on\-disk format changes have not been made and will not be made
+unless an administrator moves the feature to the
+.Sy enabled
+state.
+Features cannot be disabled once they have been enabled.
+.El
+.Pp
+The state of supported features is exposed through pool properties of the form
+.Sy feature@short_name .
+.Ss Read\-only compatibility
+Some features may make on\-disk format changes that do not interfere with other
+software's ability to read from the pool.
+These features are referred to as "read\-only compatible".
+If all unsupported features on a pool are read\-only compatible, the pool can
+be imported in read\-only mode by setting the
+.Sy readonly
+property during import (see
+.Xr zpool 8
+for details on importing pools).
+.Ss Unsupported features
+For each unsupported feature enabled on an imported pool a pool property
+named
+.Sy unsupported@feature_guid
+will indicate why the import was allowed despite the unsupported feature.
+Possible values for this property are:
+.Bl -tag -width "XXXXXXXX"
+.It Sy inactive
+The feature is in the
+.Sy enabled
+state and therefore the pool's on\-disk format is still compatible with
+software that does not support this feature.
+.It Sy readonly
+The feature is read\-only compatible and the pool has been imported in
+read\-only mode.
+.El
+.Ss Feature dependencies
+Some features depend on other features being enabled in order to function
+properly.
+Enabling a feature will automatically enable any features it depends on.
+.Sh FEATURES
+The following features are supported on this system:
+.Bl -tag -width "XXXXXXXX"
+.It Sy async_destroy
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:async_destroy"
+.It GUID Ta com.delphix:async_destroy
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+Destroying a file system requires traversing all of its data in order to
+return its used space to the pool.
+Without
+.Sy async_destroy
+the file system is not fully removed until all space has been reclaimed.
+If the destroy operation is interrupted by a reboot or power outage the next
+attempt to open the pool will need to complete the destroy operation
+synchronously.
+.Pp
+When
+.Sy async_destroy
+is enabled the file system's data will be reclaimed by a background process,
+allowing the destroy operation to complete without traversing the entire file
+system.
+The background process is able to resume interrupted destroys after the pool
+has been opened, eliminating the need to finish interrupted destroys as part
+of the open operation.
+The amount of space remaining to be reclaimed by the background process is
+available through the
+.Sy freeing
+property.
+.Pp
+This feature is only
+.Sy active
+while
+.Sy freeing
+is non\-zero.
+.It Sy empty_bpobj
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:empty_bpobj"
+.It GUID Ta com.delphix:empty_bpobj
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature increases the performance of creating and using a large number
+of snapshots of a single filesystem or volume, and also reduces the disk
+space required.
+.Pp
+When there are many snapshots, each snapshot uses many Block Pointer Objects
+.Pq bpobj's
+to track blocks associated with that snapshot.
+However, in common use cases, most of these bpobj's are empty.
+This feature allows us to create each bpobj on-demand, thus eliminating the
+empty bpobjs.
+.Pp
+This feature is
+.Sy active
+while there are any filesystems, volumes, or snapshots which were created
+after enabling this feature.
+.It Sy filesystem_limits
+.Bl -column "READ\-ONLY COMPATIBLE" "com.joyent:filesystem_limits"
+.It GUID Ta com.joyent:filesystem_limits
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta extensible_dataset
+.El
+.Pp
+This feature enables filesystem and snapshot limits.
+These limits can be used
+to control how many filesystems and/or snapshots can be created at the point in
+the tree on which the limits are set.
+.Pp
+This feature is
+.Sy active
+once either of the limit properties has been
+set on a dataset.
+Once activated the feature is never deactivated.
+.It Sy lz4_compress
+.Bl -column "READ\-ONLY COMPATIBLE" "org.illumos:lz4_compress"
+.It GUID Ta org.illumos:lz4_compress
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta none
+.El
+.Pp
+.Sy lz4
+is a high-performance real-time compression algorithm that
+features significantly faster compression and decompression as well as a
+higher compression ratio than the older
+.Sy lzjb
+compression.
+Typically,
+.Sy lz4
+compression is approximately 50% faster on
+compressible data and 200% faster on incompressible data than
+.Sy lzjb .
+It is also approximately 80% faster on decompression, while
+giving approximately 10% better compression ratio.
+.Pp
+When the
+.Sy lz4_compress
+feature is set to
+.Sy enabled ,
+the
+administrator can turn on
+.Sy lz4
+compression on any dataset on the
+pool using the
+.Xr zfs 8
+command.
+Also, all newly written metadata
+will be compressed with
+.Sy lz4
+algorithm.
+Since this feature is not read-only compatible, this
+operation will render the pool unimportable on systems without support
+for the
+.Sy lz4_compress
+feature.
+Booting off of
+.Sy lz4
+-compressed root pools is supported.
+.Pp
+This feature becomes
+.Sy active
+as soon as it is enabled and will
+never return to being
+.Sy enabled .
+.It Sy multi_vdev_crash_dump
+.Bl -column "READ\-ONLY COMPATIBLE" "com.joyent:multi_vdev_crash_dump"
+.It GUID Ta com.joyent:multi_vdev_crash_dump
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature allows a dump device to be configured with a pool comprised
+of multiple vdevs.
+Those vdevs may be arranged in any mirrored or raidz
+configuration.
+.\" TODO: this is not yet supported on FreeBSD.
+.\" .Pp
+.\" When the
+.\" .Sy multi_vdev_crash_dump
+.\" feature is set to
+.\" .Sy enabled ,
+.\" the administrator can use the
+.\" .Xr dumpon 8
+.\" command to configure a
+.\" dump device on a pool comprised of multiple vdevs.
+.It Sy spacemap_histogram
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:spacemap_histogram"
+.It GUID Ta com.delphix:spacemap_histogram
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature allows ZFS to maintain more information about how free space
+is organized within the pool.
+If this feature is
+.Sy enabled ,
+ZFS will
+set this feature to
+.Sy active
+when a new space map object is created or
+an existing space map is upgraded to the new format.
+Once the feature is
+.Sy active ,
+it will remain in that state until the pool is destroyed.
+.It Sy extensible_dataset
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:extensible_dataset"
+.It GUID Ta com.delphix:extensible_dataset
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature allows more flexible use of internal ZFS data structures,
+and exists for other features to depend on.
+.Pp
+This feature will be
+.Sy active
+when the first dependent feature uses it,
+and will be returned to the
+.Sy enabled
+state when all datasets that use
+this feature are destroyed.
+.It Sy bookmarks
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:bookmarks"
+.It GUID Ta com.delphix:bookmarks
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta extensible_dataset
+.El
+.Pp
+This feature enables use of the
+.Nm zfs
+.Cm bookmark
+subcommand.
+.Pp
+This feature is
+.Sy active
+while any bookmarks exist in the pool.
+All bookmarks in the pool can be listed by running
+.Nm zfs
+.Cm list
+.Fl t No bookmark Fl r Ar poolname .
+.It Sy enabled_txg
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:enabled_txg"
+.It GUID Ta com.delphix:enabled_txg
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+Once this feature is enabled ZFS records the transaction group number
+in which new features are enabled.
+This has no user-visible impact,
+but other features may depend on this feature.
+.Pp
+This feature becomes
+.Sy active
+as soon as it is enabled and will
+never return to being
+.Sy enabled .
+.It Sy hole_birth
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:hole_birth"
+.It GUID Ta com.delphix:hole_birth
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta enabled_txg
+.El
+.Pp
+This feature improves performance of incremental sends
+.Pq Dq zfs send -i
+and receives for objects with many holes.
+The most common case of
+hole-filled objects is zvols.
+.Pp
+An incremental send stream from snapshot
+.Sy A
+to snapshot
+.Sy B
+contains information about every block that changed between
+.Sy A
+and
+.Sy B .
+Blocks which did not change between those snapshots can be
+identified and omitted from the stream using a piece of metadata called
+the 'block birth time', but birth times are not recorded for holes
+.Pq blocks filled only with zeroes .
+Since holes created after
+.Sy A
+cannot be
+distinguished from holes created before
+.Sy A ,
+information about every
+hole in the entire filesystem or zvol is included in the send stream.
+.Pp
+For workloads where holes are rare this is not a problem.
+However, when
+incrementally replicating filesystems or zvols with many holes
+.Pq for example a zvol formatted with another filesystem
+a lot of time will
+be spent sending and receiving unnecessary information about holes that
+already exist on the receiving side.
+.Pp
+Once the
+.Sy hole_birth
+feature has been enabled the block birth times
+of all new holes will be recorded.
+Incremental sends between snapshots
+created after this feature is enabled will use this new metadata to avoid
+sending information about holes that already exist on the receiving side.
+.Pp
+This feature becomes
+.Sy active
+as soon as it is enabled and will
+never return to being
+.Sy enabled .
+.It Sy embedded_data
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:embedded_data"
+.It GUID Ta com.delphix:embedded_data
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature improves the performance and compression ratio of
+highly-compressible blocks.
+Blocks whose contents can compress to 112 bytes
+or smaller can take advantage of this feature.
+.Pp
+When this feature is enabled, the contents of highly-compressible blocks are
+stored in the block "pointer" itself
+.Po a misnomer in this case, as it contains
+the compressed data, rather than a pointer to its location on disk
+.Pc .
+Thus
+the space of the block
+.Pq one sector, typically 512 bytes or 4KB
+is saved,
+and no additional i/o is needed to read and write the data block.
+.Pp
+This feature becomes
+.Sy active
+as soon as it is enabled and will
+never return to being
+.Sy enabled .
+.It Sy zpool_checkpoint
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:zpool_checkpoint"
+.It GUID Ta com.delphix:zpool_checkpoint
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature enables the "zpool checkpoint" subcommand that can
+checkpoint the state of the pool at the time it was issued and later
+rewind back to it or discard it.
+.Pp
+This feature becomes
+.Sy active
+when the "zpool checkpoint" command is used to checkpoint the pool.
+The feature will only return back to being
+.Sy enabled
+when the pool is rewound or the checkpoint has been discarded.
+.It Sy device_removal
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:device_removal"
+.It GUID Ta com.delphix:device_removal
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature enables the "zpool remove" subcommand to remove top-level
+vdevs, evacuating them to reduce the total size of the pool.
+.Pp
+This feature becomes
+.Sy active
+when the "zpool remove" command is used
+on a top-level vdev, and will never return to being
+.Sy enabled .
+.It Sy obsolete_counts
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:obsolete_counts"
+.It GUID Ta com.delphix:obsolete_counts
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta device_removal
+.El
+.Pp
+This feature is an enhancement of device_removal, which will over time
+reduce the memory used to track removed devices. When indirect blocks
+are freed or remapped, we note that their part of the indirect mapping
+is "obsolete", i.e. no longer needed. See also the "zfs remap"
+subcommand in
+.Xr zfs 8 .
+
+This feature becomes
+.Sy active
+when the "zpool remove" command is
+used on a top-level vdev, and will never return to being
+.Sy enabled .
+.It Sy spacemap_v2
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:spacemap_v2"
+.It GUID Ta com.delphix:spacemap_v2
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature enables the use of the new space map encoding which
+consists of two words (instead of one) whenever it is advantageous.
+The new encoding allows space maps to represent large regions of
+space more efficiently on-disk while also increasing their maximum
+addressable offset.
+.Pp
+This feature becomes
+.Sy active
+as soon as it is enabled and will
+never return to being
+.Sy enabled .
+.It Sy large_blocks
+.Bl -column "READ\-ONLY COMPATIBLE" "org.open-zfs:large_block"
+.It GUID Ta org.open-zfs:large_block
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta extensible_dataset
+.El
+.Pp
+The
+.Sy large_block
+feature allows the record size on a dataset to be
+set larger than 128KB.
+.Pp
+This feature becomes
+.Sy active
+once a
+.Sy recordsize
+property has been set larger than 128KB, and will return to being
+.Sy enabled
+once all filesystems that have ever had their recordsize larger than 128KB
+are destroyed.
+.Pp
+Please note that booting from datasets that have recordsize greater than
+128KB is
+.Em NOT
+supported by the
+.Fx
+boot loader.
+.It Sy large_dnode
+.Bl -column "READ\-ONLY COMPATIBLE" "org.zfsonlinux:large_dnode"
+.It GUID Ta org.zfsonlinux:large_dnode
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta extensible_dataset
+.El
+.Pp
+The
+.Sy large_dnode
+feature allows the size of dnodes in a dataset to be set larger than 512B.
+.Pp
+This feature becomes
+.Sy active
+once a dataset contains an object with a dnode larger than 512B,
+which occurs as a result of setting the
+.Sy dnodesize
+dataset property to a value other than
+.Sy legacy .
+The feature will return to being
+.Sy enabled
+once all filesystems that have ever contained a dnode larger than 512B are
+destroyed.
+Large dnodes allow more data to be stored in the bonus buffer, thus potentially
+improving performance by avoiding the use of spill blocks.
+.It Sy sha512
+.Bl -column "READ\-ONLY COMPATIBLE" "org.illumos:sha512"
+.It GUID Ta org.illumos:sha512
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta extensible_dataset
+.El
+.Pp
+The
+.Sy sha512
+feature enables the use of the SHA-512/256 truncated hash algorithm
+.Pq FIPS 180-4
+for checksum and dedup.
+The native 64-bit arithmetic of SHA-512 provides an approximate 50%
+performance boost over SHA-256 on 64-bit hardware and is thus a good
+minimum-change replacement candidate for systems where hash performance is
+important, but these systems cannot for whatever reason utilize the faster
+.Sy skein
+algorithms.
+.Pp
+When the
+.Sy sha512
+feature is set to
+.Sy enabled ,
+the administrator can turn on the
+.Sy sha512
+checksum on any dataset using the
+.Dl # zfs set checksum=sha512 Ar dataset
+command.
+This feature becomes
+.Sy active
+once a
+.Sy checksum
+property has been set to
+.Sy sha512 ,
+and will return to being
+.Sy enabled
+once all filesystems that have ever had their checksum set to
+.Sy sha512
+are destroyed.
+.It Sy skein
+.Bl -column "READ\-ONLY COMPATIBLE" "org.illumos:skein"
+.It GUID Ta org.illumos:skein
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta extensible_dataset
+.El
+.Pp
+The
+.Sy skein
+feature enables the use of the Skein hash algorithm for checksum and dedup.
+Skein is a high-performance secure hash algorithm that was a finalist in the
+NIST SHA-3 competition.
+It provides a very high security margin and high performance on 64-bit hardware
+.Pq 80% faster than SHA-256 .
+This implementation also utilizes the new salted checksumming functionality in
+ZFS, which means that the checksum is pre-seeded with a secret 256-bit random
+key
+.Pq stored on the pool
+before being fed the data block to be checksummed.
+Thus the produced checksums are unique to a given pool, preventing hash
+collision attacks on systems with dedup.
+.Pp
+When the
+.Sy skein
+feature is set to
+.Sy enabled ,
+the administrator can turn on the
+.Sy skein
+checksum on any dataset using the
+.Dl # zfs set checksum=skein Ar dataset
+command.
+This feature becomes
+.Sy active
+once a
+.Sy checksum
+property has been set to
+.Sy skein ,
+and will return to being
+.Sy enabled
+once all filesystems that have ever had their checksum set to
+.Sy skein
+are destroyed.
+.It Sy allocation_classes
+.Bl -column "READ\-ONLY COMPATIBLE" "com.intel:allocation_classes"
+.It GUID Ta com.intel:allocation_classes
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature enables support for separate allocation classes.
+.Pp
+This feature becomes
+.Sy active
+when a dedicated allocation class vdev
+(dedup or special) is created with
+.Dq zpool create
+or
+.Dq zpool add .
+With device removal, it can be returned to the
+.Sy enabled
+state if all the top-level vdevs from an allocation class are removed.
+.El
+.Sh SEE ALSO
+.Xr zpool 8
+.Sh AUTHORS
+This manual page is a
+.Xr mdoc 7
+reimplementation of the
+.Tn illumos
+manual page
+.Em zpool-features(5) ,
+modified and customized for
+.Fx
+and licensed under the Common Development and Distribution License
+.Pq Tn CDDL .
+.Pp
+The
+.Xr mdoc 7
+implementation of this manual page was initially written by
+.An Martin Matuska Aq mm@FreeBSD.org .
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool.8 b/cddl/contrib/opensolaris/cmd/zpool/zpool.8
new file mode 100644
index 000000000000..11d275d386f9
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool.8
@@ -0,0 +1,2480 @@
+'\" te
+.\" Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>.
+.\" Copyright (c) 2013-2014, Xin Li <delphij@FreeBSD.org>.
+.\" All Rights Reserved.
+.\"
+.\" 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]
+.\"
+.\" Copyright (c) 2010, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright (c) 2011, Justin T. Gibbs <gibbs@FreeBSD.org>
+.\" Copyright (c) 2012, Glen Barber <gjb@FreeBSD.org>
+.\" Copyright (c) 2012, 2017 by Delphix. All Rights Reserved.
+.\" Copyright 2017 Nexenta Systems, Inc.
+.\" Copyright (c) 2017 Datto Inc.
+.\" Copyright (c) 2017 George Melikov. All Rights Reserved.
+.\" Copyright 2019 Joyent, Inc.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 7, 2019
+.Dt ZPOOL 8
+.Os
+.Sh NAME
+.Nm zpool
+.Nd configures ZFS storage pools
+.Sh SYNOPSIS
+.Nm
+.Op Fl \&?
+.Nm
+.Cm add
+.Op Fl fgLnP
+.Ar pool vdev ...
+.Nm
+.Cm attach
+.Op Fl f
+.Ar pool device new_device
+.Nm
+.Cm checkpoint
+.Op Fl d, -discard
+.Ar pool
+.Nm
+.Cm clear
+.Op Fl F Op Fl n
+.Ar pool
+.Op Ar device
+.Nm
+.Cm create
+.Op Fl fnd
+.Op Fl o Ar property Ns = Ns Ar value
+.Ar ...
+.Op Fl O Ar file-system-property Ns = Ns Ar value
+.Ar ...
+.Op Fl m Ar mountpoint
+.Op Fl R Ar root
+.Op Fl t Ar tempname
+.Ar pool vdev ...
+.Nm
+.Cm destroy
+.Op Fl f
+.Ar pool
+.Nm
+.Cm detach
+.Ar pool device
+.Nm
+.Cm export
+.Op Fl f
+.Ar pool ...
+.Nm
+.Cm get
+.Op Fl Hp
+.Op Fl o Ar field Ns Op , Ns Ar ...
+.Ar all | property Ns Op , Ns Ar ...
+.Ar pool ...
+.Nm
+.Cm history
+.Op Fl il
+.Op Ar pool
+.Ar ...
+.Nm
+.Cm import
+.Op Fl d Ar dir | Fl c Ar cachefile
+.Op Fl D
+.Nm
+.Cm import
+.Op Fl o Ar mntopts
+.Op Fl o Ar property Ns = Ns Ar value
+.Ar ...
+.Op Fl -rewind-to-checkpoint
+.Op Fl d Ar dir | Fl c Ar cachefile
+.Op Fl D
+.Op Fl f
+.Op Fl m
+.Op Fl N
+.Op Fl R Ar root
+.Op Fl F Op Fl n
+.Fl a
+.Nm
+.Cm import
+.Op Fl o Ar mntopts
+.Op Fl o Ar property Ns = Ns Ar value
+.Ar ...
+.Op Fl -rewind-to-checkpoint
+.Op Fl d Ar dir | Fl c Ar cachefile
+.Op Fl D
+.Op Fl f
+.Op Fl m
+.Op Fl N
+.Op Fl R Ar root
+.Op Fl t
+.Op Fl F Op Fl n
+.Ar pool | id
+.Op Ar newpool
+.Nm
+.Cm initialize
+.Op Fl cs
+.Ar pool
+.Op Ar device Ns ...
+.Nm
+.Cm iostat
+.Op Fl v
+.Op Fl T Cm d Ns | Ns Cm u
+.Op Fl gLP
+.Op Ar pool
+.Ar ...
+.Op Ar inverval Op Ar count
+.Nm
+.Cm labelclear
+.Op Fl f
+.Ar device
+.Nm
+.Cm list
+.Op Fl HgLpPv
+.Op Fl o Ar property Ns Op , Ns Ar ...
+.Op Fl T Cm d Ns | Ns Cm u
+.Op Ar pool
+.Ar ...
+.Op Ar inverval Op Ar count
+.Nm
+.Cm offline
+.Op Fl t
+.Ar pool device ...
+.Nm
+.Cm online
+.Op Fl e
+.Ar pool device ...
+.Nm
+.Cm reguid
+.Ar pool
+.Nm
+.Cm remove
+.Op Fl np
+.Ar pool device ...
+.Nm
+.Cm remove
+.Fl s
+.Ar pool
+.Nm
+.Cm reopen
+.Ar pool
+.Nm
+.Cm replace
+.Op Fl f
+.Ar pool device
+.Op Ar new_device
+.Nm
+.Cm scrub
+.Op Fl s | Fl p
+.Ar pool ...
+.Nm
+.Cm set
+.Ar property Ns = Ns Ar value pool
+.Nm
+.Cm split
+.Op Fl gLnP
+.Op Fl R Ar altroot
+.Op Fl o Ar mntopts
+.Op Fl o Ar property Ns = Ns Ar value
+.Ar pool newpool
+.Op Ar device ...
+.Nm
+.Cm status
+.Op Fl DgLPvx
+.Op Fl T Cm d Ns | Ns Cm u
+.Op Ar pool
+.Ar ...
+.Op Ar interval Op Ar count
+.Nm
+.Cm sync
+.Oo Ar pool Oc Ns ...
+.Nm
+.Cm upgrade
+.Op Fl v
+.Nm
+.Cm upgrade
+.Op Fl V Ar version
+.Fl a | Ar pool ...
+.Sh DESCRIPTION
+The
+.Nm
+command configures
+.Tn ZFS
+storage pools. A storage pool is a collection of devices that provides physical
+storage and data replication for
+.Tn ZFS
+datasets.
+.Pp
+All datasets within a storage pool share the same space. See
+.Xr zfs 8
+for information on managing datasets.
+.Ss Virtual Devices (vdevs)
+A
+.Qq virtual device
+.Pq No vdev
+describes a single device or a collection of devices organized according to
+certain performance and fault characteristics. The following virtual devices
+are supported:
+.Bl -tag -width "XXXXXX"
+.It Sy disk
+A block device, typically located under
+.Pa /dev .
+.Tn ZFS
+can use individual slices or partitions, though the recommended mode of
+operation is to use whole disks. A disk can be specified by a full path to the
+device or the
+.Xr geom 4
+provider name. When given a whole disk,
+.Tn ZFS
+automatically labels the disk, if necessary.
+.It Sy file
+A regular file. The use of files as a backing store is strongly discouraged. It
+is designed primarily for experimental purposes, as the fault tolerance of a
+file is only as good the file system of which it is a part. A file must be
+specified by a full path.
+.It Sy mirror
+A mirror of two or more devices. Data is replicated in an identical fashion
+across all components of a mirror. A mirror with
+.Em N
+disks of size
+.Em X
+can hold
+.Em X
+bytes and can withstand
+.Pq Em N-1
+devices failing before data integrity is compromised.
+.It Sy raidz
+(or
+.Sy raidz1 raidz2 raidz3 ) .
+A variation on
+.Sy RAID-5
+that allows for better distribution of parity and eliminates the
+.Qq Sy RAID-5
+write hole (in which data and parity become inconsistent after a power loss).
+Data and parity is striped across all disks within a
+.No raidz
+group.
+.Pp
+A
+.No raidz
+group can have single-, double- , or triple parity, meaning that the
+.No raidz
+group can sustain one, two, or three failures, respectively, without
+losing any data. The
+.Sy raidz1 No vdev
+type specifies a single-parity
+.No raidz
+group; the
+.Sy raidz2 No vdev
+type specifies a double-parity
+.No raidz
+group; and the
+.Sy raidz3 No vdev
+type specifies a triple-parity
+.No raidz
+group. The
+.Sy raidz No vdev
+type is an alias for
+.Sy raidz1 .
+.Pp
+A
+.No raidz
+group with
+.Em N
+disks of size
+.Em X
+with
+.Em P
+parity disks can hold approximately
+.Sm off
+.Pq Em N-P
+*X
+.Sm on
+bytes and can withstand
+.Em P
+device(s) failing before data integrity is compromised. The minimum number of
+devices in a
+.No raidz
+group is one more than the number of parity disks. The
+recommended number is between 3 and 9 to help increase performance.
+.It Sy spare
+A special
+.No pseudo- Ns No vdev
+which keeps track of available hot spares for a pool.
+For more information, see the
+.Qq Sx Hot Spares
+section.
+.It Sy log
+A separate-intent log device. If more than one log device is specified, then
+writes are load-balanced between devices. Log devices can be mirrored. However,
+.No raidz
+.No vdev
+types are not supported for the intent log. For more information,
+see the
+.Qq Sx Intent Log
+section.
+.It Sy dedup
+A device dedicated solely for allocating dedup data.
+The redundancy of this device should match the redundancy of the other normal
+devices in the pool.
+If more than one dedup device is specified, then allocations are load-balanced
+between devices.
+.It Sy special
+A device dedicated solely for allocating various kinds of internal metadata,
+and optionally small file data.
+The redundancy of this device should match the redundancy of the other normal
+devices in the pool.
+If more than one special device is specified, then allocations are
+load-balanced between devices.
+.Pp
+For more information on special allocations, see the
+.Sx Special Allocation Class
+section.
+.It Sy cache
+A device used to cache storage pool data.
+A cache device cannot be configured as a mirror or raidz group.
+For more information, see the
+.Qq Sx Cache Devices
+section.
+.El
+.Pp
+Virtual devices cannot be nested, so a mirror or
+.No raidz
+virtual device can only
+contain files or disks. Mirrors of mirrors (or other combinations) are not
+allowed.
+.Pp
+A pool can have any number of virtual devices at the top of the configuration
+(known as
+.Qq root
+.No vdev Ns s).
+Data is dynamically distributed across all top-level devices to balance data
+among devices. As new virtual devices are added,
+.Tn ZFS
+automatically places data on the newly available devices.
+.Pp
+Virtual devices are specified one at a time on the command line, separated by
+whitespace. The keywords
+.Qq mirror
+and
+.Qq raidz
+are used to distinguish where a group ends and another begins. For example, the
+following creates two root
+.No vdev Ns s,
+each a mirror of two disks:
+.Bd -literal -offset 2n
+.Li # Ic zpool create mypool mirror da0 da1 mirror da2 da3
+.Ed
+.Ss Device Failure and Recovery
+.Tn ZFS
+supports a rich set of mechanisms for handling device failure and data
+corruption. All metadata and data is checksummed, and
+.Tn ZFS
+automatically repairs bad data from a good copy when corruption is detected.
+.Pp
+In order to take advantage of these features, a pool must make use of some form
+of redundancy, using either mirrored or
+.No raidz
+groups. While
+.Tn ZFS
+supports running in a non-redundant configuration, where each root
+.No vdev
+is simply a disk or file, this is strongly discouraged. A single case of bit
+corruption can render some or all of your data unavailable.
+.Pp
+A pool's health status is described by one of three states: online, degraded,
+or faulted. An online pool has all devices operating normally. A degraded pool
+is one in which one or more devices have failed, but the data is still
+available due to a redundant configuration. A faulted pool has corrupted
+metadata, or one or more faulted devices, and insufficient replicas to continue
+functioning.
+.Pp
+The health of the top-level
+.No vdev ,
+such as mirror or
+.No raidz
+device, is
+potentially impacted by the state of its associated
+.No vdev Ns s,
+or component devices. A top-level
+.No vdev
+or component device is in one of the following states:
+.Bl -tag -width "DEGRADED"
+.It Sy DEGRADED
+One or more top-level
+.No vdev Ns s
+is in the degraded state because one or more
+component devices are offline. Sufficient replicas exist to continue
+functioning.
+.Pp
+One or more component devices is in the degraded or faulted state, but
+sufficient replicas exist to continue functioning. The underlying conditions
+are as follows:
+.Bl -bullet -offset 2n
+.It
+The number of checksum errors exceeds acceptable levels and the device is
+degraded as an indication that something may be wrong.
+.Tn ZFS
+continues to use the device as necessary.
+.It
+The number of
+.Tn I/O
+errors exceeds acceptable levels. The device could not be
+marked as faulted because there are insufficient replicas to continue
+functioning.
+.El
+.It Sy FAULTED
+One or more top-level
+.No vdev Ns s
+is in the faulted state because one or more
+component devices are offline. Insufficient replicas exist to continue
+functioning.
+.Pp
+One or more component devices is in the faulted state, and insufficient
+replicas exist to continue functioning. The underlying conditions are as
+follows:
+.Bl -bullet -offset 2n
+.It
+The device could be opened, but the contents did not match expected values.
+.It
+The number of
+.Tn I/O
+errors exceeds acceptable levels and the device is faulted to
+prevent further use of the device.
+.El
+.It Sy OFFLINE
+The device was explicitly taken offline by the
+.Qq Nm Cm offline
+command.
+.It Sy ONLINE
+The device is online and functioning.
+.It Sy REMOVED
+The device was physically removed while the system was running. Device removal
+detection is hardware-dependent and may not be supported on all platforms.
+.It Sy UNAVAIL
+The device could not be opened. If a pool is imported when a device was
+unavailable, then the device will be identified by a unique identifier instead
+of its path since the path was never correct in the first place.
+.El
+.Pp
+If a device is removed and later reattached to the system,
+.Tn ZFS
+attempts to put the device online automatically. Device attach detection is
+hardware-dependent and might not be supported on all platforms.
+.Ss Hot Spares
+.Tn ZFS
+allows devices to be associated with pools as
+.Qq hot spares .
+These devices are not actively used in the pool, but when an active device
+fails, it is automatically replaced by a hot spare. To create a pool with hot
+spares, specify a
+.Qq spare
+.No vdev
+with any number of devices. For example,
+.Bd -literal -offset 2n
+.Li # Ic zpool create pool mirror da0 da1 spare da2 da3
+.Ed
+.Pp
+Spares can be shared across multiple pools, and can be added with the
+.Qq Nm Cm add
+command and removed with the
+.Qq Nm Cm remove
+command. Once a spare replacement is initiated, a new "spare"
+.No vdev
+is created
+within the configuration that will remain there until the original device is
+replaced. At this point, the hot spare becomes available again if another
+device fails.
+.Pp
+If a pool has a shared spare that is currently being used, the pool can not be
+exported since other pools may use this shared spare, which may lead to
+potential data corruption.
+.Pp
+Shared spares add some risk.
+If the pools are imported on different hosts, and both pools suffer a device
+failure at the same time, both could attempt to use the spare at the same time.
+This may not be detected, resulting in data corruption.
+.Pp
+An in-progress spare replacement can be cancelled by detaching the hot spare.
+If the original faulted device is detached, then the hot spare assumes its
+place in the configuration, and is removed from the spare list of all active
+pools.
+.Pp
+Spares cannot replace log devices.
+.Pp
+This feature requires a userland helper.
+FreeBSD provides
+.Xr zfsd 8
+for this purpose.
+It must be manually enabled by adding
+.Va zfsd_enable="YES"
+to
+.Pa /etc/rc.conf .
+.Ss Intent Log
+The
+.Tn ZFS
+Intent Log
+.Pq Tn ZIL
+satisfies
+.Tn POSIX
+requirements for synchronous transactions. For instance, databases often
+require their transactions to be on stable storage devices when returning from
+a system call.
+.Tn NFS
+and other applications can also use
+.Xr fsync 2
+to ensure data stability. By default, the intent log is allocated from blocks
+within the main pool. However, it might be possible to get better performance
+using separate intent log devices such as
+.Tn NVRAM
+or a dedicated disk. For example:
+.Bd -literal -offset 2n
+.Li # Ic zpool create pool da0 da1 log da2
+.Ed
+.Pp
+Multiple log devices can also be specified, and they can be mirrored. See the
+.Sx EXAMPLES
+section for an example of mirroring multiple log devices.
+.Pp
+Log devices can be added, replaced, attached, detached, imported and exported
+as part of the larger pool.
+Mirrored devices can be removed by specifying the top-level mirror vdev.
+.Ss Cache devices
+Devices can be added to a storage pool as "cache devices." These devices
+provide an additional layer of caching between main memory and disk. For
+read-heavy workloads, where the working set size is much larger than what can
+be cached in main memory, using cache devices allow much more of this working
+set to be served from low latency media. Using cache devices provides the
+greatest performance improvement for random read-workloads of mostly static
+content.
+.Pp
+To create a pool with cache devices, specify a "cache"
+.No vdev
+with any number of devices. For example:
+.Bd -literal -offset 2n
+.Li # Ic zpool create pool da0 da1 cache da2 da3
+.Ed
+.Pp
+Cache devices cannot be mirrored or part of a
+.No raidz
+configuration. If a read
+error is encountered on a cache device, that read
+.Tn I/O
+is reissued to the original storage pool device, which might be part of a
+mirrored or
+.No raidz
+configuration.
+.Pp
+The content of the cache devices is considered volatile, as is the case with
+other system caches.
+.Ss Pool checkpoint
+Before starting critical procedures that include destructive actions (e.g
+.Nm zfs Cm destroy
+), an administrator can checkpoint the pool's state and in the case of a
+mistake or failure, rewind the entire pool back to the checkpoint.
+Otherwise, the checkpoint can be discarded when the procedure has completed
+successfully.
+.Pp
+A pool checkpoint can be thought of as a pool-wide snapshot and should be used
+with care as it contains every part of the pool's state, from properties to vdev
+configuration.
+Thus, while a pool has a checkpoint certain operations are not allowed.
+Specifically, vdev removal/attach/detach, mirror splitting, and
+changing the pool's guid.
+Adding a new vdev is supported but in the case of a rewind it will have to be
+added again.
+Finally, users of this feature should keep in mind that scrubs in a pool that
+has a checkpoint do not repair checkpointed data.
+.Pp
+To create a checkpoint for a pool:
+.Bd -literal
+# zpool checkpoint pool
+.Ed
+.Pp
+To later rewind to its checkpointed state, you need to first export it and
+then rewind it during import:
+.Bd -literal
+# zpool export pool
+# zpool import --rewind-to-checkpoint pool
+.Ed
+.Pp
+To discard the checkpoint from a pool:
+.Bd -literal
+# zpool checkpoint -d pool
+.Ed
+.Pp
+Dataset reservations (controlled by the
+.Nm reservation
+or
+.Nm refreservation
+zfs properties) may be unenforceable while a checkpoint exists, because the
+checkpoint is allowed to consume the dataset's reservation.
+Finally, data that is part of the checkpoint but has been freed in the
+current state of the pool won't be scanned during a scrub.
+.Ss Special Allocation Class
+The allocations in the special class are dedicated to specific block types.
+By default this includes all metadata, the indirect blocks of user data, and
+any dedup data.
+The class can also be provisioned to accept a limited percentage of small file
+data blocks.
+.Pp
+A pool must always have at least one general (non-specified) vdev before
+other devices can be assigned to the special class.
+If the special class becomes full, then allocations intended for it will spill
+back into the normal class.
+.Pp
+Dedup data can be excluded from the special class by setting the
+.Sy vfs.zfs.ddt_data_is_special
+sysctl to false (0).
+.Pp
+Inclusion of small file blocks in the special class is opt-in.
+Each dataset can control the size of small file blocks allowed in the special
+class by setting the
+.Sy special_small_blocks
+dataset property.
+It defaults to zero so you must opt-in by setting it to a non-zero value.
+See
+.Xr zfs 1M
+for more info on setting this property.
+.Ss Properties
+Each pool has several properties associated with it. Some properties are
+read-only statistics while others are configurable and change the behavior of
+the pool. The following are read-only properties:
+.Bl -tag -width "dedupratio"
+.It Sy allocated
+Amount of storage space used within the pool.
+.It Sy capacity
+Percentage of pool space used. This property can also be referred to by its
+shortened column name, "cap".
+.It Sy dedupratio
+The deduplication ratio specified for a pool, expressed as a multiplier.
+For example, a
+.Sy dedupratio
+value of 1.76 indicates that 1.76 units of data were stored but only 1 unit of disk space was actually consumed. See
+.Xr zfs 8
+for a description of the deduplication feature.
+.It Sy expandsize
+Amount of uninitialized space within the pool or device that can be used to
+increase the total capacity of the pool.
+Uninitialized space consists of
+any space on an EFI labeled vdev which has not been brought online
+.Pq i.e. zpool online -e .
+This space occurs when a LUN is dynamically expanded.
+.It Sy fragmentation
+The amount of fragmentation in the pool.
+.It Sy free
+Number of blocks within the pool that are not allocated.
+.It Sy freeing
+After a file system or snapshot is destroyed, the space it was using is
+returned to the pool asynchronously.
+.Sy freeing
+is the amount of space remaining to be reclaimed.
+Over time
+.Sy freeing
+will decrease while
+.Sy free
+increases.
+.It Sy guid
+A unique identifier for the pool.
+.It Sy health
+The current health of the pool. Health can be
+.Qq Sy ONLINE ,
+.Qq Sy DEGRADED ,
+.Qq Sy FAULTED ,
+.Qq Sy OFFLINE ,
+.Qq Sy REMOVED ,
+or
+.Qq Sy UNAVAIL .
+.It Sy size
+Total size of the storage pool.
+.It Sy unsupported@ Ns Ar feature_guid
+Information about unsupported features that are enabled on the pool.
+See
+.Xr zpool-features 7
+for details.
+.El
+.Pp
+The space usage properties report actual physical space available to the
+storage pool. The physical space can be different from the total amount of
+space that any contained datasets can actually use. The amount of space used in
+a
+.No raidz
+configuration depends on the characteristics of the data being written.
+In addition,
+.Tn ZFS
+reserves some space for internal accounting that the
+.Xr zfs 8
+command takes into account, but the
+.Xr zpool 8
+command does not. For non-full pools of a reasonable size, these effects should
+be invisible. For small pools, or pools that are close to being completely
+full, these discrepancies may become more noticeable.
+.Pp
+The following property can be set at creation time and import time:
+.Bl -tag -width 2n
+.It Sy altroot
+Alternate root directory. If set, this directory is prepended to any mount
+points within the pool. This can be used when examining an unknown pool where
+the mount points cannot be trusted, or in an alternate boot environment, where
+the typical paths are not valid.
+.Sy altroot
+is not a persistent property. It is valid only while the system is up.
+Setting
+.Sy altroot
+defaults to using
+.Cm cachefile=none ,
+though this may be overridden using an explicit setting.
+.El
+.Pp
+The following property can only be set at import time:
+.Bl -tag -width 2n
+.It Sy readonly Ns = Ns Cm on No | Cm off
+If set to
+.Cm on ,
+pool will be imported in read-only mode with the following restrictions:
+.Bl -bullet -offset 2n
+.It
+Synchronous data in the intent log will not be accessible
+.It
+Properties of the pool can not be changed
+.It
+Datasets of this pool can only be mounted read-only
+.It
+To write to a read-only pool, a export and import of the pool is required.
+.El
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy rdonly .
+.El
+.Pp
+The following properties can be set at creation time and import time, and later
+changed with the
+.Ic zpool set
+command:
+.Bl -tag -width 2n
+.It Sy autoexpand Ns = Ns Cm on No | Cm off
+Controls automatic pool expansion when the underlying LUN is grown. If set to
+.Qq Cm on ,
+the pool will be resized according to the size of the expanded
+device. If the device is part of a mirror or
+.No raidz
+then all devices within that
+.No mirror/ Ns No raidz
+group must be expanded before the new space is made available to
+the pool. The default behavior is
+.Qq off .
+This property can also be referred to by its shortened column name,
+.Sy expand .
+.It Sy autoreplace Ns = Ns Cm on No | Cm off
+Controls automatic device replacement. If set to
+.Qq Cm off ,
+device replacement must be initiated by the administrator by using the
+.Qq Nm Cm replace
+command. If set to
+.Qq Cm on ,
+any new device, found in the same
+physical location as a device that previously belonged to the pool, is
+automatically formatted and replaced. The default behavior is
+.Qq Cm off .
+This property can also be referred to by its shortened column name, "replace".
+.It Sy bootfs Ns = Ns Ar pool Ns / Ns Ar dataset
+Identifies the default bootable dataset for the root pool. This property is
+expected to be set mainly by the installation and upgrade programs.
+.It Sy cachefile Ns = Ns Ar path No | Cm none
+Controls the location of where the pool configuration is cached. Discovering
+all pools on system startup requires a cached copy of the configuration data
+that is stored on the root file system. All pools in this cache are
+automatically imported when the system boots. Some environments, such as
+install and clustering, need to cache this information in a different location
+so that pools are not automatically imported. Setting this property caches the
+pool configuration in a different location that can later be imported with
+.Qq Nm Cm import Fl c .
+Setting it to the special value
+.Qq Cm none
+creates a temporary pool that is never cached, and the special value
+.Cm ''
+(empty string) uses the default location.
+.It Sy comment Ns = Ns Ar text
+A text string consisting of printable ASCII characters that will be stored
+such that it is available even if the pool becomes faulted.
+An administrator can provide additional information about a pool using this
+property.
+.It Sy dedupditto Ns = Ns Ar number
+Threshold for the number of block ditto copies. If the reference count for a
+deduplicated block increases above this number, a new ditto copy of this block
+is automatically stored. Default setting is
+.Cm 0
+which causes no ditto copies to be created for deduplicated blocks.
+The miniumum legal nonzero setting is 100.
+.It Sy delegation Ns = Ns Cm on No | Cm off
+Controls whether a non-privileged user is granted access based on the dataset
+permissions defined on the dataset. See
+.Xr zfs 8
+for more information on
+.Tn ZFS
+delegated administration.
+.It Sy failmode Ns = Ns Cm wait No | Cm continue No | Cm panic
+Controls the system behavior in the event of catastrophic pool failure. This
+condition is typically a result of a loss of connectivity to the underlying
+storage device(s) or a failure of all devices within the pool. The behavior of
+such an event is determined as follows:
+.Bl -tag -width indent
+.It Sy wait
+Blocks all
+.Tn I/O
+access until the device connectivity is recovered and the errors are cleared.
+This is the default behavior.
+.It Sy continue
+Returns
+.Em EIO
+to any new write
+.Tn I/O
+requests but allows reads to any of the remaining healthy devices. Any write
+requests that have yet to be committed to disk would be blocked.
+.It Sy panic
+Prints out a message to the console and generates a system crash dump.
+.El
+.It Sy feature@ Ns Ar feature_name Ns = Ns Sy enabled
+The value of this property is the current state of
+.Ar feature_name .
+The only valid value when setting this property is
+.Sy enabled
+which moves
+.Ar feature_name
+to the enabled state.
+See
+.Xr zpool-features 7
+for details on feature states.
+.It Sy listsnapshots Ns = Ns Cm on No | Cm off
+Controls whether information about snapshots associated with this pool is
+output when
+.Qq Nm zfs Cm list
+is run without the
+.Fl t
+option. The default value is
+.Cm off .
+This property can also be referred to by its shortened name,
+.Sy listsnaps .
+.It Sy multihost Ns = Ns Sy on No | Sy off
+Controls whether a pool activity check should be performed during
+.Nm zpool Cm import .
+When a pool is determined to be active it cannot be imported, even with the
+.Fl f
+option.
+This property is intended to be used in failover configurations
+where multiple hosts have access to a pool on shared storage.
+.Pp
+Multihost provides protection on import only.
+It does not protect against an
+individual device being used in multiple pools, regardless of the type of vdev.
+See the discussion under
+.Sy zpool create.
+.Pp
+When this property is on, periodic writes to storage occur to show the pool is
+in use.
+See
+.Sy vfs.zfs.multihost_interval
+sysctl.
+In order to enable this property each host must set a unique hostid.
+The default value is
+.Sy off .
+.It Sy version Ns = Ns Ar version
+The current on-disk version of the pool. This can be increased, but never
+decreased. The preferred method of updating pools is with the
+.Qq Nm Cm upgrade
+command, though this property can be used when a specific version is needed
+for backwards compatibility.
+Once feature flags is enabled on a pool this property will no longer have a
+value.
+.El
+.Sh SUBCOMMANDS
+All subcommands that modify state are logged persistently to the pool in their
+original form.
+.Pp
+The
+.Nm
+command provides subcommands to create and destroy storage pools, add capacity
+to storage pools, and provide information about the storage pools. The following
+subcommands are supported:
+.Bl -tag -width 2n
+.It Xo
+.Nm
+.Op Fl \&?
+.Xc
+.Pp
+Displays a help message.
+.It Xo
+.Nm
+.Cm add
+.Op Fl fgLnP
+.Ar pool vdev ...
+.Xc
+.Pp
+Adds the specified virtual devices to the given pool. The
+.No vdev
+specification is described in the
+.Qq Sx Virtual Devices
+section. The behavior of the
+.Fl f
+option, and the device checks performed are described in the
+.Qq Nm Cm create
+subcommand.
+.Bl -tag -width indent
+.It Fl f
+Forces use of
+.Ar vdev ,
+even if they appear in use or specify a conflicting replication level.
+Not all devices can be overridden in this manner.
+.It Fl g
+Display
+.Ar vdev ,
+GUIDs instead of the normal device names.
+These GUIDs can be used in place of
+device names for the zpool detach/offline/remove/replace commands.
+.It Fl L
+Display real paths for
+.Ar vdev Ns s
+resolving all symbolic links.
+This can be used to look up the current block
+device name regardless of the /dev/disk/ path used to open it.
+.It Fl n
+Displays the configuration that would be used without actually adding the
+.Ar vdev Ns s.
+The actual pool creation can still fail due to insufficient privileges or
+device sharing.
+.It Fl P
+Display real paths for
+.Ar vdev Ns s
+instead of only the last component of the path.
+This can be used in conjunction with the
+.Fl L
+flag.
+.El
+.It Xo
+.Nm
+.Cm attach
+.Op Fl f
+.Ar pool device new_device
+.Xc
+.Pp
+Attaches
+.Ar new_device
+to an existing
+.Sy zpool
+device. The existing device cannot be part of a
+.No raidz
+configuration. If
+.Ar device
+is not currently part of a mirrored configuration,
+.Ar device
+automatically transforms into a two-way mirror of
+.Ar device No and Ar new_device .
+If
+.Ar device
+is part of a two-way mirror, attaching
+.Ar new_device
+creates a three-way mirror, and so on. In either case,
+.Ar new_device
+begins to resilver immediately.
+.Bl -tag -width indent
+.It Fl f
+Forces use of
+.Ar new_device ,
+even if its appears to be in use. Not all devices can be overridden in this
+manner.
+.El
+.It Xo
+.Nm
+.Cm checkpoint
+.Op Fl d, -discard
+.Ar pool
+.Xc
+Checkpoints the current state of
+.Ar pool
+, which can be later restored by
+.Nm zpool Cm import --rewind-to-checkpoint .
+The existence of a checkpoint in a pool prohibits the following
+.Nm zpool
+commands:
+.Cm remove ,
+.Cm attach ,
+.Cm detach ,
+.Cm split ,
+and
+.Cm reguid .
+In addition, it may break reservation boundaries if the pool lacks free
+space.
+The
+.Nm zpool Cm status
+command indicates the existence of a checkpoint or the progress of discarding a
+checkpoint from a pool.
+The
+.Nm zpool Cm list
+command reports how much space the checkpoint takes from the pool.
+.Bl -tag -width Ds
+.It Fl d, -discard
+Discards an existing checkpoint from
+.Ar pool .
+.El
+.It Xo
+.Nm
+.Cm clear
+.Op Fl F Op Fl n
+.Ar pool
+.Op Ar device
+.Xc
+.Pp
+Clears device errors in a pool.
+If no arguments are specified, all device errors within the pool are cleared.
+If one or more devices is specified, only those errors associated with the
+specified device or devices are cleared.
+If multihost is enabled, and the pool has been suspended, this will not
+resume I/O.
+While the pool was suspended, it may have been imported on
+another host, and resuming I/O could result in pool damage.
+.Bl -tag -width indent
+.It Fl F
+Initiates recovery mode for an unopenable pool. Attempts to discard the last
+few transactions in the pool to return it to an openable state. Not all damaged
+pools can be recovered by using this option. If successful, the data from the
+discarded transactions is irretrievably lost.
+.It Fl n
+Used in combination with the
+.Fl F
+flag. Check whether discarding transactions would make the pool openable, but
+do not actually discard any transactions.
+.El
+.It Xo
+.Nm
+.Cm create
+.Op Fl fnd
+.Op Fl o Ar property Ns = Ns Ar value
+.Ar ...
+.Op Fl O Ar file-system-property Ns = Ns Ar value
+.Ar ...
+.Op Fl m Ar mountpoint
+.Op Fl R Ar root
+.Op Fl t Ar tempname
+.Ar pool vdev ...
+.Xc
+.Pp
+Creates a new storage pool containing the virtual devices specified on the
+command line. The pool name must begin with a letter, and can only contain
+alphanumeric characters as well as underscore ("_"), dash ("-"), and period
+("."). The pool names "mirror", "raidz", "spare" and "log" are reserved, as are
+names beginning with the pattern "c[0-9]". The
+.No vdev
+specification is described in the
+.Qq Sx Virtual Devices
+section.
+.Pp
+The command attempts to verify that each device specified is accessible and not
+currently in use by another subsystem.
+However this check is not robust enough
+to detect simultaneous attempts to use a new device in different pools, even if
+.Sy multihost
+is
+.Sy enabled.
+The
+administrator must ensure that simultaneous invocations of any combination of
+.Sy zpool replace ,
+.Sy zpool create ,
+.Sy zpool add ,
+or
+.Sy zpool labelclear ,
+do not refer to the same device.
+Using the same device in two pools will
+result in pool corruption.
+.Pp
+There are some uses, such as being currently mounted, or specified as the
+dedicated dump device, that prevents a device from ever being used by ZFS.
+Other uses, such as having a preexisting UFS file system, can be overridden
+with the
+.Fl f
+option.
+.Pp
+The command also checks that the replication strategy for the pool is
+consistent. An attempt to combine redundant and non-redundant storage in a
+single pool, or to mix disks and files, results in an error unless
+.Fl f
+is specified. The use of differently sized devices within a single
+.No raidz
+or mirror group is also flagged as an error unless
+.Fl f
+is specified.
+.Pp
+Unless the
+.Fl R
+option is specified, the default mount point is
+.Qq Pa /pool .
+The mount point must not exist or must be empty, or else the
+root dataset cannot be mounted. This can be overridden with the
+.Fl m
+option.
+.Pp
+By default all supported features are enabled on the new pool unless the
+.Fl d
+option is specified.
+.Bl -tag -width indent
+.It Fl f
+Forces use of
+.Ar vdev Ns s,
+even if they appear in use or specify a conflicting replication level.
+Not all devices can be overridden in this manner.
+.It Fl n
+Displays the configuration that would be used without actually creating the
+pool. The actual pool creation can still fail due to insufficient privileges or
+device sharing.
+.It Fl d
+Do not enable any features on the new pool.
+Individual features can be enabled by setting their corresponding properties
+to
+.Sy enabled
+with the
+.Fl o
+option.
+See
+.Xr zpool-features 7
+for details about feature properties.
+.It Xo
+.Fl o Ar property Ns = Ns Ar value
+.Op Fl o Ar property Ns = Ns Ar value
+.Ar ...
+.Xc
+Sets the given pool properties. See the
+.Qq Sx Properties
+section for a list of valid properties that can be set.
+.It Xo
+.Fl O
+.Ar file-system-property Ns = Ns Ar value
+.Op Fl O Ar file-system-property Ns = Ns Ar value
+.Ar ...
+.Xc
+Sets the given file system properties in the root file system of the pool. See
+.Xr zfs 8 Properties
+for a list of valid properties that
+can be set.
+.It Fl R Ar root
+Equivalent to
+.Qq Fl o Cm cachefile=none,altroot= Ns Pa root
+.It Fl m Ar mountpoint
+Sets the mount point for the root dataset. The default mount point is
+.Qq Pa /pool
+or
+.Qq Cm altroot Ns Pa /pool
+if
+.Sy altroot
+is specified. The mount point must be an absolute path,
+.Qq Cm legacy ,
+or
+.Qq Cm none .
+For more information on dataset mount points, see
+.Xr zfs 8 .
+.It Fl t Ar tempname
+Sets the in-core pool name to
+.Pa tempname
+while the on-disk name will be the name specified as the pool name
+.Pa pool .
+This will set the default
+.Sy cachefile
+property to
+.Sy none .
+This is intended to handle name space collisions when creating pools
+for other systems, such as virtual machines or physical machines
+whose pools live on network block devices.
+.El
+.It Xo
+.Nm
+.Cm destroy
+.Op Fl f
+.Ar pool
+.Xc
+.Pp
+Destroys the given pool, freeing up any devices for other use. This command
+tries to unmount any active datasets before destroying the pool.
+.Bl -tag -width indent
+.It Fl f
+Forces any active datasets contained within the pool to be unmounted.
+.El
+.It Xo
+.Nm
+.Cm detach
+.Ar pool device
+.Xc
+.Pp
+Detaches
+.Ar device
+from a mirror. The operation is refused if there are no other valid replicas
+of the data.
+.It Xo
+.Nm
+.Cm export
+.Op Fl f
+.Ar pool ...
+.Xc
+.Pp
+Exports the given pools from the system. All devices are marked as exported,
+but are still considered in use by other subsystems. The devices can be moved
+between systems (even those of different endianness) and imported as long as a
+sufficient number of devices are present.
+.Pp
+Before exporting the pool, all datasets within the pool are unmounted. A pool
+can not be exported if it has a shared spare that is currently being used.
+.Pp
+For pools to be portable, you must give the
+.Nm
+command whole disks, not just slices, so that
+.Tn ZFS
+can label the disks with portable
+.Sy EFI
+labels. Otherwise, disk drivers on platforms of different endianness will not
+recognize the disks.
+.Bl -tag -width indent
+.It Fl f
+Forcefully unmount all datasets, using the
+.Qq Nm unmount Fl f
+command.
+.Pp
+This command will forcefully export the pool even if it has a shared spare that
+is currently being used. This may lead to potential data corruption.
+.El
+.It Xo
+.Nm
+.Cm get
+.Op Fl Hp
+.Op Fl o Ar field Ns Op , Ns Ar ...
+.Ar all | property Ns Op , Ns Ar ...
+.Ar pool ...
+.Xc
+.Pp
+Retrieves the given list of properties (or all properties if
+.Qq Cm all
+is used) for the specified storage pool(s). These properties are displayed with
+the following fields:
+.Bl -column -offset indent "property"
+.It name Ta Name of storage pool
+.It property Ta Property name
+.It value Ta Property value
+.It source Ta Property source, either 'default' or 'local'.
+.El
+.Pp
+See the
+.Qq Sx Properties
+section for more information on the available pool properties.
+.It Fl H
+Scripted mode. Do not display headers, and separate fields by a single tab
+instead of arbitrary space.
+.It Fl p
+Display numbers in parsable (exact) values.
+.It Fl o Ar field
+A comma-separated list of columns to display.
+.Sy name Ns , Ns
+.Sy property Ns , Ns
+.Sy value Ns , Ns
+.Sy source
+is the default value.
+.It Xo
+.Nm
+.Cm history
+.Op Fl il
+.Op Ar pool
+.Ar ...
+.Xc
+.Pp
+Displays the command history of the specified pools or all pools if no pool is
+specified.
+.Bl -tag -width indent
+.It Fl i
+Displays internally logged
+.Tn ZFS
+events in addition to user initiated events.
+.It Fl l
+Displays log records in long format, which in addition to standard format
+includes, the user name, the hostname, and the zone in which the operation was
+performed.
+.El
+.It Xo
+.Nm
+.Cm import
+.Op Fl d Ar dir | Fl c Ar cachefile
+.Op Fl D
+.Xc
+.Pp
+Lists pools available to import. If the
+.Fl d
+option is not specified, this command searches for devices in
+.Qq Pa /dev .
+The
+.Fl d
+option can be specified multiple times, and all directories are searched. If
+the device appears to be part of an exported pool, this command displays a
+summary of the pool with the name of the pool, a numeric identifier, as well as
+the
+.No vdev
+layout and current health of the device for each device or file.
+Destroyed pools, pools that were previously destroyed with the
+.Qq Nm Cm destroy
+command, are not listed unless the
+.Fl D
+option is specified.
+.Pp
+The numeric identifier is unique, and can be used instead of the pool name when
+multiple exported pools of the same name are available.
+.Bl -tag -width indent
+.It Fl c Ar cachefile
+Reads configuration from the given
+.Ar cachefile
+that was created with the
+.Qq Sy cachefile
+pool property. This
+.Ar cachefile
+is used instead of searching for devices.
+.It Fl d Ar dir
+Searches for devices or files in
+.Ar dir .
+The
+.Fl d
+option can be specified multiple times.
+.It Fl D
+Lists destroyed pools only.
+.El
+.It Xo
+.Nm
+.Cm import
+.Op Fl o Ar mntopts
+.Op Fl o Ar property Ns = Ns Ar value
+.Ar ...
+.Op Fl d Ar dir | Fl c Ar cachefile
+.Op Fl D
+.Op Fl f
+.Op Fl m
+.Op Fl N
+.Op Fl R Ar root
+.Op Fl F Op Fl n
+.Fl a
+.Xc
+.Pp
+Imports all pools found in the search directories. Identical to the previous
+command, except that all pools with a sufficient number of devices available
+are imported. Destroyed pools, pools that were previously destroyed with the
+.Qq Nm Cm destroy
+command, will not be imported unless the
+.Fl D
+option is specified.
+.Bl -tag -width indent
+.It Fl o Ar mntopts
+Comma-separated list of mount options to use when mounting datasets within the
+pool. See
+.Xr zfs 8
+for a description of dataset properties and mount options.
+.It Fl o Ar property Ns = Ns Ar value
+Sets the specified property on the imported pool. See the
+.Qq Sx Properties
+section for more information on the available pool properties.
+.It Fl c Ar cachefile
+Reads configuration from the given
+.Ar cachefile
+that was created with the
+.Qq Sy cachefile
+pool property. This
+.Ar cachefile
+is used instead of searching for devices.
+.It Fl d Ar dir
+Searches for devices or files in
+.Ar dir .
+The
+.Fl d
+option can be specified multiple times. This option is incompatible with the
+.Fl c
+option.
+.It Fl D
+Imports destroyed pools only. The
+.Fl f
+option is also required.
+.It Fl f
+Forces import, even if the pool appears to be potentially active.
+.It Fl m
+Allows a pool to import when there is a missing log device. Recent transactions
+can be lost because the log device will be discarded.
+.It Fl N
+Import the pool without mounting any file systems.
+.It Fl R Ar root
+Sets the
+.Qq Sy cachefile
+property to
+.Qq Cm none
+and the
+.Qq Sy altroot
+property to
+.Qq Ar root
+.It Fl F
+Recovery mode for a non-importable pool. Attempt to return the pool to an
+importable state by discarding the last few transactions. Not all damaged pools
+can be recovered by using this option. If successful, the data from the
+discarded transactions is irretrievably lost. This option is ignored if the
+pool is importable or already imported.
+.It Fl n
+Used with the
+.Fl F
+recovery option. Determines whether a non-importable pool can be made
+importable again, but does not actually perform the pool recovery. For more
+details about pool recovery mode, see the
+.Fl F
+option, above.
+.It Fl a
+Searches for and imports all pools found.
+.El
+.It Xo
+.Nm
+.Cm import
+.Op Fl o Ar mntopts
+.Op Fl o Ar property Ns = Ns Ar value
+.Ar ...
+.Op Fl d Ar dir | Fl c Ar cachefile
+.Op Fl D
+.Op Fl f
+.Op Fl m
+.Op Fl N
+.Op Fl R Ar root
+.Op Fl t
+.Op Fl F Op Fl n
+.Ar pool | id
+.Op Ar newpool
+.Xc
+.Pp
+Imports a specific pool. A pool can be identified by its name or the numeric
+identifier. If
+.Ar newpool
+is specified, the pool is imported using the name
+.Ar newpool .
+Otherwise, it is imported with the same name as its exported name.
+.Pp
+If a device is removed from a system without running
+.Qq Nm Cm export
+first, the device appears as potentially active. It cannot be determined if
+this was a failed export, or whether the device is really in use from another
+host. To import a pool in this state, the
+.Fl f
+option is required.
+.Bl -tag -width indent
+.It Fl o Ar mntopts
+Comma-separated list of mount options to use when mounting datasets within the
+pool. See
+.Xr zfs 8
+for a description of dataset properties and mount options.
+.It Fl o Ar property Ns = Ns Ar value
+Sets the specified property on the imported pool. See the
+.Qq Sx Properties
+section for more information on the available pool properties.
+.It Fl c Ar cachefile
+Reads configuration from the given
+.Ar cachefile
+that was created with the
+.Qq Sy cachefile
+pool property. This
+.Ar cachefile
+is used instead of searching for devices.
+.It Fl d Ar dir
+Searches for devices or files in
+.Ar dir .
+The
+.Fl d
+option can be specified multiple times. This option is incompatible with the
+.Fl c
+option.
+.It Fl D
+Imports destroyed pools only. The
+.Fl f
+option is also required.
+.It Fl f
+Forces import, even if the pool appears to be potentially active.
+.It Fl m
+Allows a pool to import when there is a missing log device. Recent transactions
+can be lost because the log device will be discarded.
+.It Fl N
+Import the pool without mounting any file systems.
+.It Fl R Ar root
+Equivalent to
+.Qq Fl o Cm cachefile=none,altroot= Ns Pa root
+.It Fl t
+Used with
+.Ar newpool .
+Specifies that
+.Ar newpool
+is temporary.
+Temporary pool names last until export.
+Ensures that the original pool name will be used in all label updates and
+therefore is retained upon export.
+Will also set
+.Sy cachefile
+property to
+.Sy none
+when not explicitly specified.
+.It Fl F
+Recovery mode for a non-importable pool. Attempt to return the pool to an
+importable state by discarding the last few transactions. Not all damaged pools
+can be recovered by using this option. If successful, the data from the
+discarded transactions is irretrievably lost. This option is ignored if the
+pool is importable or already imported.
+.It Fl n
+Used with the
+.Fl F
+recovery option. Determines whether a non-importable pool can be made
+importable again, but does not actually perform the pool recovery. For more
+details about pool recovery mode, see the
+.Fl F
+option, above.
+.It Fl -rewind-to-checkpoint
+Rewinds pool to the checkpointed state.
+Once the pool is imported with this flag there is no way to undo the rewind.
+All changes and data that were written after the checkpoint are lost!
+The only exception is when the
+.Sy readonly
+mounting option is enabled.
+In this case, the checkpointed state of the pool is opened and an
+administrator can see how the pool would look like if they were
+to fully rewind.
+.El
+.It Xo
+.Nm
+.Cm initialize
+.Op Fl cs
+.Ar pool
+.Op Ar device Ns ...
+.Xc
+Begins initializing by writing to all unallocated regions on the specified
+devices, or all eligible devices in the pool if no individual devices are
+specified.
+Only leaf data or log devices may be initialized.
+.Bl -tag -width Ds
+.It Fl c, -cancel
+Cancel initializing on the specified devices, or all eligible devices if none
+are specified.
+If one or more target devices are invalid or are not currently being
+initialized, the command will fail and no cancellation will occur on any device.
+.It Fl s -suspend
+Suspend initializing on the specified devices, or all eligible devices if none
+are specified.
+If one or more target devices are invalid or are not currently being
+initialized, the command will fail and no suspension will occur on any device.
+Initializing can then be resumed by running
+.Nm zpool Cm initialize
+with no flags on the relevant target devices.
+.El
+.It Xo
+.Nm
+.Cm iostat
+.Op Fl T Cm d Ns | Ns Cm u
+.Op Fl gLPv
+.Op Ar pool
+.Ar ...
+.Op Ar interval Op Ar count
+.Xc
+.Pp
+Displays
+.Tn I/O
+statistics for the given pools. When given an interval, the statistics are
+printed every
+.Ar interval
+seconds until
+.Sy Ctrl-C
+is pressed. If no
+.Ar pools
+are specified, statistics for every pool in the system is shown. If
+.Ar count
+is specified, the command exits after
+.Ar count
+reports are printed.
+.Bl -tag -width indent
+.It Fl T Cm d Ns | Ns Cm u
+Print a timestamp.
+.Pp
+Use modifier
+.Cm d
+for standard date format. See
+.Xr date 1 .
+Use modifier
+.Cm u
+for unixtime
+.Pq equals Qq Ic date +%s .
+.It Fl g
+Display vdev GUIDs instead of the normal device names.
+These GUIDs can be used in place of device names for the zpool
+detach/offline/remove/replace commands.
+.It Fl L
+Display real paths for vdevs resolving all symbolic links.
+This can be used to look up the current block device name regardless of the
+.Pa /dev/disk/
+path used to open it.
+.It Fl P
+Display full paths for vdevs instead of only the last component of
+the path.
+This can be used in conjunction with the
+.Fl L
+flag.
+.It Fl v
+Verbose statistics.
+Reports usage statistics for individual vdevs within the
+pool, in addition to the pool-wide statistics.
+.El
+.It Xo
+.Nm
+.Cm labelclear
+.Op Fl f
+.Ar device
+.Xc
+.Pp
+Removes
+.Tn ZFS
+label information from the specified
+.Ar device .
+The
+.Ar device
+must not be part of an active pool configuration.
+.Bl -tag -width indent
+.It Fl f
+Treat exported or foreign devices as inactive.
+.El
+.It Xo
+.Nm
+.Cm list
+.Op Fl HgLpPv
+.Op Fl o Ar property Ns Op , Ns Ar ...
+.Op Fl T Cm d Ns | Ns Cm u
+.Op Ar pool
+.Ar ...
+.Op Ar inverval Op Ar count
+.Xc
+.Pp
+Lists the given pools along with a health status and space usage. If no
+.Ar pools
+are specified, all pools in the system are listed.
+.Pp
+When given an interval, the output is printed every
+.Ar interval
+seconds until
+.Sy Ctrl-C
+is pressed. If
+.Ar count
+is specified, the command exits after
+.Ar count
+reports are printed.
+.Bl -tag -width indent
+.It Fl T Cm d Ns | Ns Cm u
+Print a timestamp.
+.Pp
+Use modifier
+.Cm d
+for standard date format. See
+.Xr date 1 .
+Use modifier
+.Cm u
+for unixtime
+.Pq equals Qq Ic date +%s .
+.It Fl g
+Display vdev GUIDs instead of the normal device names.
+These GUIDs can be used in place of device names for the zpool
+detach/offline/remove/replace commands.
+.It Fl H
+Scripted mode. Do not display headers, and separate fields by a single tab
+instead of arbitrary space.
+.It Fl L
+Display real paths for vdevs resolving all symbolic links.
+This can be used to look up the current block device name regardless of the
+/dev/disk/ path used to open it.
+.It Fl p
+Display numbers in parsable
+.Pq exact
+values.
+.It Fl P
+Display full paths for vdevs instead of only the last component of
+the path.
+This can be used in conjunction with the
+.Fl L
+flag.
+.It Fl v
+Verbose statistics. Reports usage statistics for individual
+.Em vdevs
+within
+the pool, in addition to the pool-wide statistics.
+.It Fl o Ar property Ns Op , Ns Ar ...
+Comma-separated list of properties to display. See the
+.Qq Sx Properties
+section for a list of valid properties. The default list is
+.Sy name ,
+.Sy size ,
+.Sy allocated ,
+.Sy free ,
+.Sy checkpoint ,
+.Sy expandsize ,
+.Sy fragmentation ,
+.Sy capacity ,
+.Sy dedupratio ,
+.Sy health ,
+.Sy altroot .
+.It Fl T Cm d Ns | Ns Cm u
+Print a timestamp.
+.Pp
+Use modifier
+.Cm d
+for standard date format. See
+.Xr date 1 .
+Use modifier
+.Cm u
+for unixtime
+.Pq equals Qq Ic date +%s .
+.El
+.It Xo
+.Nm
+.Cm offline
+.Op Fl t
+.Ar pool device ...
+.Xc
+.Pp
+Takes the specified physical device offline. While the
+.Ar device
+is offline, no attempt is made to read or write to the device.
+.Bl -tag -width indent
+.It Fl t
+Temporary. Upon reboot, the specified physical device reverts to its previous
+state.
+.El
+.It Xo
+.Nm
+.Cm online
+.Op Fl e
+.Ar pool device ...
+.Xc
+.Pp
+Brings the specified physical device online.
+.Pp
+This command is not applicable to spares or cache devices.
+.Bl -tag -width indent
+.It Fl e
+Expand the device to use all available space. If the device is part of a mirror
+or
+.No raidz
+then all devices must be expanded before the new space will become
+available to the pool.
+.El
+.It Xo
+.Nm
+.Cm reguid
+.Ar pool
+.Xc
+.Pp
+Generates a new unique identifier for the pool. You must ensure that all
+devices in this pool are online and healthy before performing this action.
+.It Xo
+.Nm
+.Cm remove
+.Op Fl np
+.Ar pool device ...
+.Xc
+.Pp
+Removes the specified device from the pool.
+This command currently only supports removing hot spares, cache, log
+devices and mirrored top-level vdevs (mirror of leaf devices); but not raidz.
+.Pp
+Removing a top-level vdev reduces the total amount of space in the storage pool.
+The specified device will be evacuated by copying all allocated space from it to
+the other devices in the pool.
+In this case, the
+.Nm zpool Cm remove
+command initiates the removal and returns, while the evacuation continues in
+the background.
+The removal progress can be monitored with
+.Nm zpool Cm status.
+This feature must be enabled to be used, see
+.Xr zpool-features 7
+.Pp
+A mirrored top-level device (log or data) can be removed by specifying the
+top-level mirror for the same.
+Non-log devices or data devices that are part of a mirrored configuration can
+be removed using the
+.Qq Nm Cm detach
+command.
+.Bl -tag -width Ds
+.It Fl n
+Do not actually perform the removal ("no-op").
+Instead, print the estimated amount of memory that will be used by the
+mapping table after the removal completes.
+This is nonzero only for top-level vdevs.
+.El
+.Bl -tag -width Ds
+.It Fl p
+Used in conjunction with the
+.Fl n
+flag, displays numbers as parsable (exact) values.
+.El
+.It Xo
+.Nm
+.Cm remove
+.Fl s
+.Ar pool
+.Xc
+.Pp
+Stops and cancels an in-progress removal of a top-level vdev.
+.It Xo
+.Nm
+.Cm reopen
+.Ar pool
+.Xc
+.Pp
+Reopen all the vdevs associated with the pool.
+.It Xo
+.Nm
+.Cm replace
+.Op Fl f
+.Ar pool device
+.Op Ar new_device
+.Xc
+.Pp
+Replaces
+.Ar old_device
+with
+.Ar new_device .
+This is equivalent to attaching
+.Ar new_device ,
+waiting for it to resilver, and then detaching
+.Ar old_device .
+.Pp
+The size of
+.Ar new_device
+must be greater than or equal to the minimum size
+of all the devices in a mirror or
+.No raidz
+configuration.
+.Pp
+.Ar new_device
+is required if the pool is not redundant. If
+.Ar new_device
+is not specified, it defaults to
+.Ar old_device .
+This form of replacement is useful after an existing disk has failed and has
+been physically replaced. In this case, the new disk may have the same
+.Pa /dev
+path as the old device, even though it is actually a different disk.
+.Tn ZFS
+recognizes this.
+.Bl -tag -width indent
+.It Fl f
+Forces use of
+.Ar new_device ,
+even if its appears to be in use. Not all devices can be overridden in this
+manner.
+.El
+.It Xo
+.Nm
+.Cm scrub
+.Op Fl s | Fl p
+.Ar pool ...
+.Xc
+.Pp
+Begins a scrub or resumes a paused scrub.
+The scrub examines all data in the specified pools to verify that it checksums
+correctly.
+For replicated
+.Pq mirror or raidz
+devices, ZFS automatically repairs any damage discovered during the scrub.
+The
+.Nm zpool Cm status
+command reports the progress of the scrub and summarizes the results of the
+scrub upon completion.
+.Pp
+Scrubbing and resilvering are very similar operations.
+The difference is that resilvering only examines data that ZFS knows to be out
+of date
+.Po
+for example, when attaching a new device to a mirror or replacing an existing
+device
+.Pc ,
+whereas scrubbing examines all data to discover silent errors due to hardware
+faults or disk failure.
+.Pp
+Because scrubbing and resilvering are I/O-intensive operations, ZFS only allows
+one at a time.
+If a scrub is paused, the
+.Nm zpool Cm scrub
+resumes it.
+If a resilver is in progress, ZFS does not allow a scrub to be started until the
+resilver completes.
+.Bl -tag -width Ds
+.It Fl s
+Stop scrubbing.
+.El
+.Bl -tag -width Ds
+.It Fl p
+Pause scrubbing.
+Scrub pause state and progress are periodically synced to disk.
+If the system is restarted or pool is exported during a paused scrub,
+even after import, scrub will remain paused until it is resumed.
+Once resumed the scrub will pick up from the place where it was last
+checkpointed to disk.
+To resume a paused scrub issue
+.Nm zpool Cm scrub
+again.
+.El
+.It Xo
+.Nm
+.Cm set
+.Ar property Ns = Ns Ar value pool
+.Xc
+.Pp
+Sets the given property on the specified pool. See the
+.Qq Sx Properties
+section for more information on what properties can be set and acceptable
+values.
+.It Xo
+.Nm
+.Cm split
+.Op Fl gLnP
+.Op Fl R Ar altroot
+.Op Fl o Ar mntopts
+.Op Fl o Ar property Ns = Ns Ar value
+.Ar pool newpool
+.Op Ar device ...
+.Xc
+.Pp
+Splits off one disk from each mirrored top-level
+.No vdev
+in a pool and creates a new pool from the split-off disks. The original pool
+must be made up of one or more mirrors and must not be in the process of
+resilvering. The
+.Cm split
+subcommand chooses the last device in each mirror
+.No vdev
+unless overridden by a device specification on the command line.
+.Pp
+When using a
+.Ar device
+argument,
+.Cm split
+includes the specified device(s) in a new pool and, should any devices remain
+unspecified, assigns the last device in each mirror
+.No vdev
+to that pool, as it does normally. If you are uncertain about the outcome of a
+.Cm split
+command, use the
+.Fl n
+("dry-run") option to ensure your command will have the effect you intend.
+.Bl -tag -width indent
+.It Fl R Ar altroot
+Automatically import the newly created pool after splitting, using the
+specified
+.Ar altroot
+parameter for the new pool's alternate root. See the
+.Sy altroot
+description in the
+.Qq Sx Properties
+section, above.
+.It Fl g
+Display vdev GUIDs instead of the normal device names.
+These GUIDs can be used in place of device names for the zpool
+detach/offline/remove/replace commands.
+.It Fl L
+Display real paths for vdevs resolving all symbolic links.
+This can be used to look up the current block device name regardless of the
+.Pa /dev/disk/
+path used to open it.
+.It Fl n
+Displays the configuration that would be created without actually splitting the
+pool. The actual pool split could still fail due to insufficient privileges or
+device status.
+.It Fl o Ar mntopts
+Comma-separated list of mount options to use when mounting datasets within the
+pool. See
+.Xr zfs 8
+for a description of dataset properties and mount options. Valid only in
+conjunction with the
+.Fl R
+option.
+.It Fl o Ar property Ns = Ns Ar value
+Sets the specified property on the new pool. See the
+.Qq Sx Properties
+section, above, for more information on the available pool properties.
+.It Fl P
+Display full paths for vdevs instead of only the last component of
+the path.
+This can be used in conjunction with the
+.Fl L
+flag.
+.El
+.It Xo
+.Nm
+.Cm status
+.Op Fl DgLPvx
+.Op Fl T Cm d Ns | Ns Cm u
+.Op Ar pool
+.Ar ...
+.Op Ar interval Op Ar count
+.Xc
+.Pp
+Displays the detailed health status for the given pools. If no
+.Ar pool
+is specified, then the status of each pool in the system is displayed. For more
+information on pool and device health, see the
+.Qq Sx Device Failure and Recovery
+section.
+.Pp
+When given an interval, the output is printed every
+.Ar interval
+seconds until
+.Sy Ctrl-C
+is pressed. If
+.Ar count
+is specified, the command exits after
+.Ar count
+reports are printed.
+.Pp
+If a scrub or resilver is in progress, this command reports the percentage
+done and the estimated time to completion. Both of these are only approximate,
+because the amount of data in the pool and the other workloads on the system
+can change.
+.Bl -tag -width indent
+.It Fl D
+Display a histogram of deduplication statistics, showing the allocated
+.Pq physically present on disk
+and referenced
+.Pq logically referenced in the pool
+block counts and sizes by reference count.
+.It Fl g
+Display vdev GUIDs instead of the normal device names.
+These GUIDs can be used in place of device names for the zpool
+detach/offline/remove/replace commands.
+.It Fl L
+Display real paths for vdevs resolving all symbolic links.
+This can be used to look up the current block device name regardless of the
+.Pa /dev/disk/
+path used to open it.
+.It Fl P
+Display full paths for vdevs instead of only the last component of
+the path.
+This can be used in conjunction with the
+.Fl L
+flag.
+.It Fl T Cm d Ns | Ns Cm u
+Print a timestamp.
+.Pp
+Use modifier
+.Cm d
+for standard date format. See
+.Xr date 1 .
+Use modifier
+.Cm u
+for unixtime
+.Pq equals Qq Ic date +%s .
+.It Fl v
+Displays verbose data error information, printing out a complete list of all
+data errors since the last complete pool scrub.
+.It Fl x
+Only display status for pools that are exhibiting errors or are otherwise
+unavailable.
+Warnings about pools not using the latest on-disk format, having non-native
+block size or disabled features will not be included.
+.El
+.It Xo
+.Nm
+.Cm sync
+.Oo Ar pool Oc Ns ...
+.Xc
+Forces all in-core dirty data to be written to the primary pool storage and
+not the ZIL.
+It will also update administrative information including quota reporting.
+Without arguments,
+.Nm zpool Cm sync
+will sync all pools on the system.
+Otherwise, it will only sync the specified
+.Ar pool .
+.It Xo
+.Nm
+.Cm upgrade
+.Op Fl v
+.Xc
+.Pp
+Displays pools which do not have all supported features enabled and pools
+formatted using a legacy
+.Tn ZFS
+version number.
+These pools can continue to be used, but some features may not be available.
+Use
+.Nm Cm upgrade Fl a
+to enable all features on all pools.
+.Bl -tag -width indent
+.It Fl v
+Displays legacy
+.Tn ZFS
+versions supported by the current software.
+See
+.Xr zpool-features 7
+for a description of feature flags features supported by the current software.
+.El
+.It Xo
+.Nm
+.Cm upgrade
+.Op Fl V Ar version
+.Fl a | Ar pool ...
+.Xc
+.Pp
+Enables all supported features on the given pool.
+Once this is done, the pool will no longer be accessible on systems that do
+not support feature flags.
+See
+.Xr zpool-features 7
+for details on compatibility with systems that support feature flags, but do
+not support all features enabled on the pool.
+.Bl -tag -width indent
+.It Fl a
+Enables all supported features on all pools.
+.It Fl V Ar version
+Upgrade to the specified legacy version. If the
+.Fl V
+flag is specified, no features will be enabled on the pool.
+This option can only be used to increase version number up to the last
+supported legacy version number.
+.El
+.El
+.Sh EXIT STATUS
+The following exit values are returned:
+.Bl -tag -offset 2n -width 2n
+.It 0
+Successful completion.
+.It 1
+An error occurred.
+.It 2
+Invalid command line options were specified.
+.El
+.Sh ENVIRONMENT VARIABLES
+.Bl -tag -width "ZPOOL_VDEV_NAME_FOLLOW_LINKS"
+.It Ev ZPOOL_VDEV_NAME_GUID
+Cause
+.Nm zpool
+subcommands to output vdev guids by default.
+This behavior is identical to the
+.Nm zpool status -g
+command line option.
+.It Ev ZPOOL_VDEV_NAME_FOLLOW_LINKS
+Cause
+.Nm zpool
+subcommands to follow links for vdev names by default.
+This behavior is identical to the
+.Nm zpool status -L
+command line option.
+.It Ev ZPOOL_VDEV_NAME_PATH
+Cause
+.Nm zpool
+subcommands to output full vdev path names by default.
+This behavior is identical to the
+.Nm zpool status -P
+command line option.
+.El
+.Sh EXAMPLES
+.Bl -tag -width 0n
+.It Sy Example 1 No Creating a RAID-Z Storage Pool
+.Pp
+The following command creates a pool with a single
+.No raidz
+root
+.No vdev
+that consists of six disks.
+.Bd -literal -offset 2n
+.Li # Ic zpool create tank raidz da0 da1 da2 da3 da4 da5
+.Ed
+.It Sy Example 2 No Creating a Mirrored Storage Pool
+.Pp
+The following command creates a pool with two mirrors, where each mirror
+contains two disks.
+.Bd -literal -offset 2n
+.Li # Ic zpool create tank mirror da0 da1 mirror da2 da3
+.Ed
+.It Sy Example 3 No Creating a Tn ZFS No Storage Pool by Using Partitions
+.Pp
+The following command creates an unmirrored pool using two GPT partitions.
+.Bd -literal -offset 2n
+.Li # Ic zpool create tank da0p3 da1p3
+.Ed
+.It Sy Example 4 No Creating a Tn ZFS No Storage Pool by Using Files
+.Pp
+The following command creates an unmirrored pool using files. While not
+recommended, a pool based on files can be useful for experimental purposes.
+.Bd -literal -offset 2n
+.Li # Ic zpool create tank /path/to/file/a /path/to/file/b
+.Ed
+.It Sy Example 5 No Adding a Mirror to a Tn ZFS No Storage Pool
+.Pp
+The following command adds two mirrored disks to the pool
+.Em tank ,
+assuming the pool is already made up of two-way mirrors. The additional space
+is immediately available to any datasets within the pool.
+.Bd -literal -offset 2n
+.Li # Ic zpool add tank mirror da2 da3
+.Ed
+.It Sy Example 6 No Listing Available Tn ZFS No Storage Pools
+.Pp
+The following command lists all available pools on the system.
+.Bd -literal -offset 2n
+.Li # Ic zpool list
+NAME SIZE ALLOC FREE FRAG EXPANDSZ CAP DEDUP HEALTH ALTROOT
+pool 2.70T 473G 2.24T 33% - 17% 1.00x ONLINE -
+test 1.98G 89.5K 1.98G 48% - 0% 1.00x ONLINE -
+.Ed
+.It Sy Example 7 No Listing All Properties for a Pool
+.Pp
+The following command lists all the properties for a pool.
+.Bd -literal -offset 2n
+.Li # Ic zpool get all pool
+pool size 2.70T -
+pool capacity 17% -
+pool altroot - default
+pool health ONLINE -
+pool guid 2501120270416322443 default
+pool version 28 default
+pool bootfs pool/root local
+pool delegation on default
+pool autoreplace off default
+pool cachefile - default
+pool failmode wait default
+pool listsnapshots off default
+pool autoexpand off default
+pool dedupditto 0 default
+pool dedupratio 1.00x -
+pool free 2.24T -
+pool allocated 473G -
+pool readonly off -
+.Ed
+.It Sy Example 8 No Destroying a Tn ZFS No Storage Pool
+.Pp
+The following command destroys the pool
+.Qq Em tank
+and any datasets contained within.
+.Bd -literal -offset 2n
+.Li # Ic zpool destroy -f tank
+.Ed
+.It Sy Example 9 No Exporting a Tn ZFS No Storage Pool
+.Pp
+The following command exports the devices in pool
+.Em tank
+so that they can be relocated or later imported.
+.Bd -literal -offset 2n
+.Li # Ic zpool export tank
+.Ed
+.It Sy Example 10 No Importing a Tn ZFS No Storage Pool
+.Pp
+The following command displays available pools, and then imports the pool
+.Qq Em tank
+for use on the system.
+.Pp
+The results from this command are similar to the following:
+.Bd -literal -offset 2n
+.Li # Ic zpool import
+
+ pool: tank
+ id: 15451357997522795478
+ state: ONLINE
+action: The pool can be imported using its name or numeric identifier.
+config:
+
+ tank ONLINE
+ mirror ONLINE
+ da0 ONLINE
+ da1 ONLINE
+.Ed
+.It Xo
+.Sy Example 11
+Upgrading All
+.Tn ZFS
+Storage Pools to the Current Version
+.Xc
+.Pp
+The following command upgrades all
+.Tn ZFS
+Storage pools to the current version of
+the software.
+.Bd -literal -offset 2n
+.Li # Ic zpool upgrade -a
+This system is currently running ZFS pool version 28.
+.Ed
+.It Sy Example 12 No Managing Hot Spares
+.Pp
+The following command creates a new pool with an available hot spare:
+.Bd -literal -offset 2n
+.Li # Ic zpool create tank mirror da0 da1 spare da2
+.Ed
+.Pp
+If one of the disks were to fail, the pool would be reduced to the degraded
+state. The failed device can be replaced using the following command:
+.Bd -literal -offset 2n
+.Li # Ic zpool replace tank da0 da2
+.Ed
+.Pp
+Once the data has been resilvered, the spare is automatically removed and is
+made available should another device fails. The hot spare can be permanently
+removed from the pool using the following command:
+.Bd -literal -offset 2n
+.Li # Ic zpool remove tank da2
+.Ed
+.It Xo
+.Sy Example 13
+Creating a
+.Tn ZFS
+Pool with Mirrored Separate Intent Logs
+.Xc
+.Pp
+The following command creates a
+.Tn ZFS
+storage pool consisting of two, two-way
+mirrors and mirrored log devices:
+.Bd -literal -offset 2n
+.Li # Ic zpool create pool mirror da0 da1 mirror da2 da3 log mirror da4 da5
+.Ed
+.It Sy Example 14 No Adding Cache Devices to a Tn ZFS No Pool
+.Pp
+The following command adds two disks for use as cache devices to a
+.Tn ZFS
+storage pool:
+.Bd -literal -offset 2n
+.Li # Ic zpool add pool cache da2 da3
+.Ed
+.Pp
+Once added, the cache devices gradually fill with content from main memory.
+Depending on the size of your cache devices, it could take over an hour for
+them to fill. Capacity and reads can be monitored using the
+.Cm iostat
+subcommand as follows:
+.Bd -literal -offset 2n
+.Li # Ic zpool iostat -v pool 5
+.Ed
+.It Xo
+.Sy Example 15
+Displaying expanded space on a device
+.Xc
+.Pp
+The following command dipslays the detailed information for the
+.Em data
+pool.
+This pool is comprised of a single
+.Em raidz
+vdev where one of its
+devices increased its capacity by 10GB.
+In this example, the pool will not
+be able to utilized this extra capacity until all the devices under the
+.Em raidz
+vdev have been expanded.
+.Bd -literal -offset 2n
+.Li # Ic zpool list -v data
+NAME SIZE ALLOC FREE FRAG EXPANDSZ CAP DEDUP HEALTH ALTROOT
+data 23.9G 14.6G 9.30G 48% - 61% 1.00x ONLINE -
+ raidz1 23.9G 14.6G 9.30G 48% -
+ ada0 - - - - -
+ ada1 - - - - 10G
+ ada2 - - - - -
+.Ed
+.It Xo
+.Sy Example 16
+Removing a Mirrored top-level (Log or Data) Device
+.Xc
+.Pp
+The following commands remove the mirrored log device
+.Sy mirror-2
+and mirrored top-level data device
+.Sy mirror-1 .
+.Pp
+Given this configuration:
+.Bd -literal -offset 2n
+ pool: tank
+ state: ONLINE
+ scrub: none requested
+ config:
+
+ NAME STATE READ WRITE CKSUM
+ tank ONLINE 0 0 0
+ mirror-0 ONLINE 0 0 0
+ da0 ONLINE 0 0 0
+ da1 ONLINE 0 0 0
+ mirror-1 ONLINE 0 0 0
+ da2 ONLINE 0 0 0
+ da3 ONLINE 0 0 0
+ logs
+ mirror-2 ONLINE 0 0 0
+ da4 ONLINE 0 0 0
+ da5 ONLINE 0 0 0
+.Ed
+.Pp
+The command to remove the mirrored log
+.Em mirror-2
+is:
+.Bd -literal -offset 2n
+.Li # Ic zpool remove tank mirror-2
+.Ed
+.Pp
+The command to remove the mirrored data
+.Em mirror-1
+is:
+.Bd -literal -offset 2n
+.Li # Ic zpool remove tank mirror-1
+.Ed
+.It Xo
+.Sy Example 17
+Recovering a Faulted
+.Tn ZFS
+Pool
+.Xc
+.Pp
+If a pool is faulted but recoverable, a message indicating this state is
+provided by
+.Qq Nm Cm status
+if the pool was cached (see the
+.Fl c Ar cachefile
+argument above), or as part of the error output from a failed
+.Qq Nm Cm import
+of the pool.
+.Pp
+Recover a cached pool with the
+.Qq Nm Cm clear
+command:
+.Bd -literal -offset 2n
+.Li # Ic zpool clear -F data
+Pool data returned to its state as of Tue Sep 08 13:23:35 2009.
+Discarded approximately 29 seconds of transactions.
+.Ed
+.Pp
+If the pool configuration was not cached, use
+.Qq Nm Cm import
+with the recovery mode flag:
+.Bd -literal -offset 2n
+.Li # Ic zpool import -F data
+Pool data returned to its state as of Tue Sep 08 13:23:35 2009.
+Discarded approximately 29 seconds of transactions.
+.Ed
+.El
+.Sh SEE ALSO
+.Xr zpool-features 7 ,
+.Xr zfs 8 ,
+.Xr zfsd 8
+.Sh AUTHORS
+This manual page is a
+.Xr mdoc 7
+reimplementation of the
+.Tn OpenSolaris
+manual page
+.Em zpool(1M) ,
+modified and customized for
+.Fx
+and licensed under the Common Development and Distribution License
+.Pq Tn CDDL .
+.Pp
+The
+.Xr mdoc 7
+implementation of this manual page was initially written by
+.An Martin Matuska Aq mm@FreeBSD.org .
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_iter.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_iter.c
new file mode 100644
index 000000000000..2f7de933ed41
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_iter.c
@@ -0,0 +1,255 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
+ */
+
+#include <solaris.h>
+#include <libintl.h>
+#include <libuutil.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <libzfs.h>
+
+#include "zpool_util.h"
+
+/*
+ * Private interface for iterating over pools specified on the command line.
+ * Most consumers will call for_each_pool, but in order to support iostat, we
+ * allow fined grained control through the zpool_list_t interface.
+ */
+
+typedef struct zpool_node {
+ zpool_handle_t *zn_handle;
+ uu_avl_node_t zn_avlnode;
+ int zn_mark;
+} zpool_node_t;
+
+struct zpool_list {
+ boolean_t zl_findall;
+ uu_avl_t *zl_avl;
+ uu_avl_pool_t *zl_pool;
+ zprop_list_t **zl_proplist;
+};
+
+/* ARGSUSED */
+static int
+zpool_compare(const void *larg, const void *rarg, void *unused)
+{
+ zpool_handle_t *l = ((zpool_node_t *)larg)->zn_handle;
+ zpool_handle_t *r = ((zpool_node_t *)rarg)->zn_handle;
+ const char *lname = zpool_get_name(l);
+ const char *rname = zpool_get_name(r);
+
+ return (strcmp(lname, rname));
+}
+
+/*
+ * Callback function for pool_list_get(). Adds the given pool to the AVL tree
+ * of known pools.
+ */
+static int
+add_pool(zpool_handle_t *zhp, void *data)
+{
+ zpool_list_t *zlp = data;
+ zpool_node_t *node = safe_malloc(sizeof (zpool_node_t));
+ uu_avl_index_t idx;
+
+ node->zn_handle = zhp;
+ uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool);
+ if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) {
+ if (zlp->zl_proplist &&
+ zpool_expand_proplist(zhp, zlp->zl_proplist) != 0) {
+ zpool_close(zhp);
+ free(node);
+ return (-1);
+ }
+ uu_avl_insert(zlp->zl_avl, node, idx);
+ } else {
+ zpool_close(zhp);
+ free(node);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Create a list of pools based on the given arguments. If we're given no
+ * arguments, then iterate over all pools in the system and add them to the AVL
+ * tree. Otherwise, add only those pool explicitly specified on the command
+ * line.
+ */
+zpool_list_t *
+pool_list_get(int argc, char **argv, zprop_list_t **proplist, int *err)
+{
+ zpool_list_t *zlp;
+
+ zlp = safe_malloc(sizeof (zpool_list_t));
+
+ zlp->zl_pool = uu_avl_pool_create("zfs_pool", sizeof (zpool_node_t),
+ offsetof(zpool_node_t, zn_avlnode), zpool_compare, UU_DEFAULT);
+
+ if (zlp->zl_pool == NULL)
+ zpool_no_memory();
+
+ if ((zlp->zl_avl = uu_avl_create(zlp->zl_pool, NULL,
+ UU_DEFAULT)) == NULL)
+ zpool_no_memory();
+
+ zlp->zl_proplist = proplist;
+
+ if (argc == 0) {
+ (void) zpool_iter(g_zfs, add_pool, zlp);
+ zlp->zl_findall = B_TRUE;
+ } else {
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ zpool_handle_t *zhp;
+
+ if ((zhp = zpool_open_canfail(g_zfs, argv[i])) !=
+ NULL) {
+ if (add_pool(zhp, zlp) != 0)
+ *err = B_TRUE;
+ } else {
+ *err = B_TRUE;
+ }
+ }
+ }
+
+ return (zlp);
+}
+
+/*
+ * Search for any new pools, adding them to the list. We only add pools when no
+ * options were given on the command line. Otherwise, we keep the list fixed as
+ * those that were explicitly specified.
+ */
+void
+pool_list_update(zpool_list_t *zlp)
+{
+ if (zlp->zl_findall)
+ (void) zpool_iter(g_zfs, add_pool, zlp);
+}
+
+/*
+ * Iterate over all pools in the list, executing the callback for each
+ */
+int
+pool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func,
+ void *data)
+{
+ zpool_node_t *node, *next_node;
+ int ret = 0;
+
+ for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next_node) {
+ next_node = uu_avl_next(zlp->zl_avl, node);
+ if (zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL ||
+ unavail)
+ ret |= func(node->zn_handle, data);
+ }
+
+ return (ret);
+}
+
+/*
+ * Remove the given pool from the list. When running iostat, we want to remove
+ * those pools that no longer exist.
+ */
+void
+pool_list_remove(zpool_list_t *zlp, zpool_handle_t *zhp)
+{
+ zpool_node_t search, *node;
+
+ search.zn_handle = zhp;
+ if ((node = uu_avl_find(zlp->zl_avl, &search, NULL, NULL)) != NULL) {
+ uu_avl_remove(zlp->zl_avl, node);
+ zpool_close(node->zn_handle);
+ free(node);
+ }
+}
+
+/*
+ * Free all the handles associated with this list.
+ */
+void
+pool_list_free(zpool_list_t *zlp)
+{
+ uu_avl_walk_t *walk;
+ zpool_node_t *node;
+
+ if ((walk = uu_avl_walk_start(zlp->zl_avl, UU_WALK_ROBUST)) == NULL) {
+ (void) fprintf(stderr,
+ gettext("internal error: out of memory"));
+ exit(1);
+ }
+
+ while ((node = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_remove(zlp->zl_avl, node);
+ zpool_close(node->zn_handle);
+ free(node);
+ }
+
+ uu_avl_walk_end(walk);
+ uu_avl_destroy(zlp->zl_avl);
+ uu_avl_pool_destroy(zlp->zl_pool);
+
+ free(zlp);
+}
+
+/*
+ * Returns the number of elements in the pool list.
+ */
+int
+pool_list_count(zpool_list_t *zlp)
+{
+ return (uu_avl_numnodes(zlp->zl_avl));
+}
+
+/*
+ * High level function which iterates over all pools given on the command line,
+ * using the pool_list_* interfaces.
+ */
+int
+for_each_pool(int argc, char **argv, boolean_t unavail,
+ zprop_list_t **proplist, zpool_iter_f func, void *data)
+{
+ zpool_list_t *list;
+ int ret = 0;
+
+ if ((list = pool_list_get(argc, argv, proplist, &ret)) == NULL)
+ return (1);
+
+ if (pool_list_iter(list, unavail, func, data) != 0)
+ ret = 1;
+
+ pool_list_free(list);
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
new file mode 100644
index 000000000000..d4e0a73ade67
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
@@ -0,0 +1,6728 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
+ * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
+ * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
+ * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright (c) 2017 Datto Inc.
+ * Copyright (c) 2017, Intel Corporation.
+ */
+
+#include <solaris.h>
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <libuutil.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <priv.h>
+#include <pwd.h>
+#include <zone.h>
+#include <sys/time.h>
+#include <zfs_prop.h>
+#include <sys/fs/zfs.h>
+#include <sys/stat.h>
+#include <sys/debug.h>
+
+#include <libzfs.h>
+
+#include "zpool_util.h"
+#include "zfs_comutil.h"
+#include "zfeature_common.h"
+
+#include "statcommon.h"
+
+static int zpool_do_create(int, char **);
+static int zpool_do_destroy(int, char **);
+
+static int zpool_do_add(int, char **);
+static int zpool_do_remove(int, char **);
+static int zpool_do_labelclear(int, char **);
+
+static int zpool_do_checkpoint(int, char **);
+
+static int zpool_do_list(int, char **);
+static int zpool_do_iostat(int, char **);
+static int zpool_do_status(int, char **);
+
+static int zpool_do_online(int, char **);
+static int zpool_do_offline(int, char **);
+static int zpool_do_clear(int, char **);
+static int zpool_do_reopen(int, char **);
+
+static int zpool_do_reguid(int, char **);
+
+static int zpool_do_attach(int, char **);
+static int zpool_do_detach(int, char **);
+static int zpool_do_replace(int, char **);
+static int zpool_do_split(int, char **);
+
+static int zpool_do_initialize(int, char **);
+static int zpool_do_scrub(int, char **);
+
+static int zpool_do_import(int, char **);
+static int zpool_do_export(int, char **);
+
+static int zpool_do_upgrade(int, char **);
+
+static int zpool_do_history(int, char **);
+
+static int zpool_do_get(int, char **);
+static int zpool_do_set(int, char **);
+
+static int zpool_do_sync(int, char **);
+
+/*
+ * These libumem hooks provide a reasonable set of defaults for the allocator's
+ * debugging facilities.
+ */
+
+#ifdef DEBUG
+const char *
+_umem_debug_init(void)
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+#endif
+
+typedef enum {
+ HELP_ADD,
+ HELP_ATTACH,
+ HELP_CLEAR,
+ HELP_CREATE,
+ HELP_CHECKPOINT,
+ HELP_DESTROY,
+ HELP_DETACH,
+ HELP_EXPORT,
+ HELP_HISTORY,
+ HELP_IMPORT,
+ HELP_IOSTAT,
+ HELP_LABELCLEAR,
+ HELP_LIST,
+ HELP_OFFLINE,
+ HELP_ONLINE,
+ HELP_REPLACE,
+ HELP_REMOVE,
+ HELP_INITIALIZE,
+ HELP_SCRUB,
+ HELP_STATUS,
+ HELP_UPGRADE,
+ HELP_GET,
+ HELP_SET,
+ HELP_SPLIT,
+ HELP_SYNC,
+ HELP_REGUID,
+ HELP_REOPEN
+} zpool_help_t;
+
+
+typedef struct zpool_command {
+ const char *name;
+ int (*func)(int, char **);
+ zpool_help_t usage;
+} zpool_command_t;
+
+/*
+ * Master command table. Each ZFS command has a name, associated function, and
+ * usage message. The usage messages need to be internationalized, so we have
+ * to have a function to return the usage message based on a command index.
+ *
+ * These commands are organized according to how they are displayed in the usage
+ * message. An empty command (one with a NULL name) indicates an empty line in
+ * the generic usage message.
+ */
+static zpool_command_t command_table[] = {
+ { "create", zpool_do_create, HELP_CREATE },
+ { "destroy", zpool_do_destroy, HELP_DESTROY },
+ { NULL },
+ { "add", zpool_do_add, HELP_ADD },
+ { "remove", zpool_do_remove, HELP_REMOVE },
+ { NULL },
+ { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR },
+ { NULL },
+ { "checkpoint", zpool_do_checkpoint, HELP_CHECKPOINT },
+ { NULL },
+ { "list", zpool_do_list, HELP_LIST },
+ { "iostat", zpool_do_iostat, HELP_IOSTAT },
+ { "status", zpool_do_status, HELP_STATUS },
+ { NULL },
+ { "online", zpool_do_online, HELP_ONLINE },
+ { "offline", zpool_do_offline, HELP_OFFLINE },
+ { "clear", zpool_do_clear, HELP_CLEAR },
+ { "reopen", zpool_do_reopen, HELP_REOPEN },
+ { NULL },
+ { "attach", zpool_do_attach, HELP_ATTACH },
+ { "detach", zpool_do_detach, HELP_DETACH },
+ { "replace", zpool_do_replace, HELP_REPLACE },
+ { "split", zpool_do_split, HELP_SPLIT },
+ { NULL },
+ { "initialize", zpool_do_initialize, HELP_INITIALIZE },
+ { "scrub", zpool_do_scrub, HELP_SCRUB },
+ { NULL },
+ { "import", zpool_do_import, HELP_IMPORT },
+ { "export", zpool_do_export, HELP_EXPORT },
+ { "upgrade", zpool_do_upgrade, HELP_UPGRADE },
+ { "reguid", zpool_do_reguid, HELP_REGUID },
+ { NULL },
+ { "history", zpool_do_history, HELP_HISTORY },
+ { "get", zpool_do_get, HELP_GET },
+ { "set", zpool_do_set, HELP_SET },
+ { "sync", zpool_do_sync, HELP_SYNC },
+};
+
+#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
+
+#define VDEV_ALLOC_CLASS_LOGS "logs"
+
+static zpool_command_t *current_command;
+static char history_str[HIS_MAX_RECORD_LEN];
+static boolean_t log_history = B_TRUE;
+static uint_t timestamp_fmt = NODATE;
+
+static const char *
+get_usage(zpool_help_t idx)
+{
+ switch (idx) {
+ case HELP_ADD:
+ return (gettext("\tadd [-fgLnP] <pool> <vdev> ...\n"));
+ case HELP_ATTACH:
+ return (gettext("\tattach [-f] <pool> <device> "
+ "<new-device>\n"));
+ case HELP_CLEAR:
+ return (gettext("\tclear [-nF] <pool> [device]\n"));
+ case HELP_CREATE:
+ return (gettext("\tcreate [-fnd] [-B] "
+ "[-o property=value] ... \n"
+ "\t [-O file-system-property=value] ...\n"
+ "\t [-m mountpoint] [-R root] [-t tempname] "
+ "<pool> <vdev> ...\n"));
+ case HELP_CHECKPOINT:
+ return (gettext("\tcheckpoint [--discard] <pool> ...\n"));
+ case HELP_DESTROY:
+ return (gettext("\tdestroy [-f] <pool>\n"));
+ case HELP_DETACH:
+ return (gettext("\tdetach <pool> <device>\n"));
+ case HELP_EXPORT:
+ return (gettext("\texport [-f] <pool> ...\n"));
+ case HELP_HISTORY:
+ return (gettext("\thistory [-il] [<pool>] ...\n"));
+ case HELP_IMPORT:
+ return (gettext("\timport [-d dir] [-D]\n"
+ "\timport [-o mntopts] [-o property=value] ... \n"
+ "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
+ "[-R root] [-F [-n]] -a\n"
+ "\timport [-o mntopts] [-o property=value] ... \n"
+ "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
+ "[-R root] [-F [-n]] [-t]\n"
+ "\t [--rewind-to-checkpoint] <pool | id> [newpool]\n"));
+ case HELP_IOSTAT:
+ return (gettext("\tiostat [-gLPv] [-T d|u] [pool] ... "
+ "[interval [count]]\n"));
+ case HELP_LABELCLEAR:
+ return (gettext("\tlabelclear [-f] <vdev>\n"));
+ case HELP_LIST:
+ return (gettext("\tlist [-gHLpPv] [-o property[,...]] "
+ "[-T d|u] [pool] ... [interval [count]]\n"));
+ case HELP_OFFLINE:
+ return (gettext("\toffline [-t] <pool> <device> ...\n"));
+ case HELP_ONLINE:
+ return (gettext("\tonline [-e] <pool> <device> ...\n"));
+ case HELP_REPLACE:
+ return (gettext("\treplace [-f] <pool> <device> "
+ "[new-device]\n"));
+ case HELP_REMOVE:
+ return (gettext("\tremove [-nps] <pool> <device> ...\n"));
+ case HELP_REOPEN:
+ return (gettext("\treopen <pool>\n"));
+ case HELP_INITIALIZE:
+ return (gettext("\tinitialize [-cs] <pool> [<device> ...]\n"));
+ case HELP_SCRUB:
+ return (gettext("\tscrub [-s | -p] <pool> ...\n"));
+ case HELP_STATUS:
+ return (gettext("\tstatus [-DgLPvx] [-T d|u] [pool] ... "
+ "[interval [count]]\n"));
+ case HELP_UPGRADE:
+ return (gettext("\tupgrade [-v]\n"
+ "\tupgrade [-V version] <-a | pool ...>\n"));
+ case HELP_GET:
+ return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
+ "<\"all\" | property[,...]> <pool> ...\n"));
+ case HELP_SET:
+ return (gettext("\tset <property=value> <pool> \n"));
+ case HELP_SPLIT:
+ return (gettext("\tsplit [-gLnP] [-R altroot] [-o mntopts]\n"
+ "\t [-o property=value] <pool> <newpool> "
+ "[<device> ...]\n"));
+ case HELP_REGUID:
+ return (gettext("\treguid <pool>\n"));
+ case HELP_SYNC:
+ return (gettext("\tsync [pool] ...\n"));
+ }
+
+ abort();
+ /* NOTREACHED */
+}
+
+
+/*
+ * Callback routine that will print out a pool property value.
+ */
+static int
+print_prop_cb(int prop, void *cb)
+{
+ FILE *fp = cb;
+
+ (void) fprintf(fp, "\t%-19s ", zpool_prop_to_name(prop));
+
+ if (zpool_prop_readonly(prop))
+ (void) fprintf(fp, " NO ");
+ else
+ (void) fprintf(fp, " YES ");
+
+ if (zpool_prop_values(prop) == NULL)
+ (void) fprintf(fp, "-\n");
+ else
+ (void) fprintf(fp, "%s\n", zpool_prop_values(prop));
+
+ return (ZPROP_CONT);
+}
+
+/*
+ * Display usage message. If we're inside a command, display only the usage for
+ * that command. Otherwise, iterate over the entire command table and display
+ * a complete usage message.
+ */
+void
+usage(boolean_t requested)
+{
+ FILE *fp = requested ? stdout : stderr;
+
+ if (current_command == NULL) {
+ int i;
+
+ (void) fprintf(fp, gettext("usage: zpool command args ...\n"));
+ (void) fprintf(fp,
+ gettext("where 'command' is one of the following:\n\n"));
+
+ for (i = 0; i < NCOMMAND; i++) {
+ if (command_table[i].name == NULL)
+ (void) fprintf(fp, "\n");
+ else
+ (void) fprintf(fp, "%s",
+ get_usage(command_table[i].usage));
+ }
+ } else {
+ (void) fprintf(fp, gettext("usage:\n"));
+ (void) fprintf(fp, "%s", get_usage(current_command->usage));
+ }
+
+ if (current_command != NULL &&
+ ((strcmp(current_command->name, "set") == 0) ||
+ (strcmp(current_command->name, "get") == 0) ||
+ (strcmp(current_command->name, "list") == 0))) {
+
+ (void) fprintf(fp,
+ gettext("\nthe following properties are supported:\n"));
+
+ (void) fprintf(fp, "\n\t%-19s %s %s\n\n",
+ "PROPERTY", "EDIT", "VALUES");
+
+ /* Iterate over all properties */
+ (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
+ ZFS_TYPE_POOL);
+
+ (void) fprintf(fp, "\t%-19s ", "feature@...");
+ (void) fprintf(fp, "YES disabled | enabled | active\n");
+
+ (void) fprintf(fp, gettext("\nThe feature@ properties must be "
+ "appended with a feature name.\nSee zpool-features(7).\n"));
+ }
+
+ /*
+ * See comments at end of main().
+ */
+ if (getenv("ZFS_ABORT") != NULL) {
+ (void) printf("dumping core by request\n");
+ abort();
+ }
+
+ exit(requested ? 0 : 2);
+}
+
+/*
+ * print a pool vdev config for dry runs
+ */
+static void
+print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
+ const char *match, int name_flags)
+{
+ nvlist_t **child;
+ uint_t c, children;
+ char *vname;
+ boolean_t printed = B_FALSE;
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0) {
+ if (name != NULL)
+ (void) printf("\t%*s%s\n", indent, "", name);
+ return;
+ }
+
+ for (c = 0; c < children; c++) {
+ uint64_t is_log = B_FALSE;
+ char *class = "";
+
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &is_log);
+ if (is_log)
+ class = VDEV_ALLOC_BIAS_LOG;
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, &class);
+ if (strcmp(match, class) != 0)
+ continue;
+
+ if (!printed && name != NULL) {
+ (void) printf("\t%*s%s\n", indent, "", name);
+ printed = B_TRUE;
+ }
+ vname = zpool_vdev_name(g_zfs, zhp, child[c], name_flags);
+ print_vdev_tree(zhp, vname, child[c], indent + 2, "",
+ name_flags);
+ free(vname);
+ }
+}
+
+static boolean_t
+prop_list_contains_feature(nvlist_t *proplist)
+{
+ nvpair_t *nvp;
+ for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp;
+ nvp = nvlist_next_nvpair(proplist, nvp)) {
+ if (zpool_prop_feature(nvpair_name(nvp)))
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Add a property pair (name, string-value) into a property nvlist.
+ */
+static int
+add_prop_list(const char *propname, char *propval, nvlist_t **props,
+ boolean_t poolprop)
+{
+ zpool_prop_t prop = ZPROP_INVAL;
+ zfs_prop_t fprop;
+ nvlist_t *proplist;
+ const char *normnm;
+ char *strval;
+
+ if (*props == NULL &&
+ nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
+ (void) fprintf(stderr,
+ gettext("internal error: out of memory\n"));
+ return (1);
+ }
+
+ proplist = *props;
+
+ if (poolprop) {
+ const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
+
+ if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
+ !zpool_prop_feature(propname)) {
+ (void) fprintf(stderr, gettext("property '%s' is "
+ "not a valid pool property\n"), propname);
+ return (2);
+ }
+
+ /*
+ * feature@ properties and version should not be specified
+ * at the same time.
+ */
+ if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) &&
+ nvlist_exists(proplist, vname)) ||
+ (prop == ZPOOL_PROP_VERSION &&
+ prop_list_contains_feature(proplist))) {
+ (void) fprintf(stderr, gettext("'feature@' and "
+ "'version' properties cannot be specified "
+ "together\n"));
+ return (2);
+ }
+
+
+ if (zpool_prop_feature(propname))
+ normnm = propname;
+ else
+ normnm = zpool_prop_to_name(prop);
+ } else {
+ if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
+ normnm = zfs_prop_to_name(fprop);
+ } else {
+ normnm = propname;
+ }
+ }
+
+ if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
+ prop != ZPOOL_PROP_CACHEFILE) {
+ (void) fprintf(stderr, gettext("property '%s' "
+ "specified multiple times\n"), propname);
+ return (2);
+ }
+
+ if (nvlist_add_string(proplist, normnm, propval) != 0) {
+ (void) fprintf(stderr, gettext("internal "
+ "error: out of memory\n"));
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Set a default property pair (name, string-value) in a property nvlist
+ */
+static int
+add_prop_list_default(const char *propname, char *propval, nvlist_t **props,
+ boolean_t poolprop)
+{
+ char *pval;
+
+ if (nvlist_lookup_string(*props, propname, &pval) == 0)
+ return (0);
+
+ return (add_prop_list(propname, propval, props, poolprop));
+}
+
+/*
+ * zpool add [-fgLnP] [-o property=value] <pool> <vdev> ...
+ *
+ * -f Force addition of devices, even if they appear in use
+ * -g Display guid for individual vdev name.
+ * -L Follow links when resolving vdev path name.
+ * -n Do not add the devices, but display the resulting layout if
+ * they were to be added.
+ * -P Display full path for vdev name.
+ *
+ * Adds the given vdevs to 'pool'. As with create, the bulk of this work is
+ * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
+ * libzfs.
+ */
+int
+zpool_do_add(int argc, char **argv)
+{
+ boolean_t force = B_FALSE;
+ boolean_t dryrun = B_FALSE;
+ int name_flags = 0;
+ int c;
+ nvlist_t *nvroot;
+ char *poolname;
+ zpool_boot_label_t boot_type;
+ uint64_t boot_size;
+ int ret;
+ zpool_handle_t *zhp;
+ nvlist_t *config;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "fgLnP")) != -1) {
+ switch (c) {
+ case 'f':
+ force = B_TRUE;
+ break;
+ case 'g':
+ name_flags |= VDEV_NAME_GUID;
+ break;
+ case 'L':
+ name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ break;
+ case 'n':
+ dryrun = B_TRUE;
+ break;
+ case 'P':
+ name_flags |= VDEV_NAME_PATH;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get pool name and check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing vdev specification\n"));
+ usage(B_FALSE);
+ }
+
+ poolname = argv[0];
+
+ argc--;
+ argv++;
+
+ if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+ return (1);
+
+ if ((config = zpool_get_config(zhp, NULL)) == NULL) {
+ (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
+ poolname);
+ zpool_close(zhp);
+ return (1);
+ }
+
+ if (zpool_is_bootable(zhp))
+ boot_type = ZPOOL_COPY_BOOT_LABEL;
+ else
+ boot_type = ZPOOL_NO_BOOT_LABEL;
+
+ /* pass off to get_vdev_spec for processing */
+ boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
+ nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
+ boot_type, boot_size, argc, argv);
+ if (nvroot == NULL) {
+ zpool_close(zhp);
+ return (1);
+ }
+
+ if (dryrun) {
+ nvlist_t *poolnvroot;
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &poolnvroot) == 0);
+
+ (void) printf(gettext("would update '%s' to the following "
+ "configuration:\n"), zpool_get_name(zhp));
+
+ /* print original main pool and new tree */
+ print_vdev_tree(zhp, poolname, poolnvroot, 0, "",
+ name_flags | VDEV_NAME_TYPE_ID);
+ print_vdev_tree(zhp, NULL, nvroot, 0, "", name_flags);
+
+ /* print other classes: 'dedup', 'special', and 'log' */
+ print_vdev_tree(zhp, "dedup", poolnvroot, 0,
+ VDEV_ALLOC_BIAS_DEDUP, name_flags);
+ print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_DEDUP,
+ name_flags);
+
+ print_vdev_tree(zhp, "special", poolnvroot, 0,
+ VDEV_ALLOC_BIAS_SPECIAL, name_flags);
+ print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_SPECIAL,
+ name_flags);
+
+ print_vdev_tree(zhp, "logs", poolnvroot, 0, VDEV_ALLOC_BIAS_LOG,
+ name_flags);
+ print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_LOG,
+ name_flags);
+
+ ret = 0;
+ } else {
+ ret = (zpool_add(zhp, nvroot) != 0);
+ }
+
+ nvlist_free(nvroot);
+ zpool_close(zhp);
+
+ return (ret);
+}
+
+/*
+ * zpool remove <pool> <vdev> ...
+ *
+ * Removes the given vdev from the pool.
+ */
+int
+zpool_do_remove(int argc, char **argv)
+{
+ char *poolname;
+ int i, ret = 0;
+ zpool_handle_t *zhp;
+ boolean_t stop = B_FALSE;
+ boolean_t noop = B_FALSE;
+ boolean_t parsable = B_FALSE;
+ char c;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "nps")) != -1) {
+ switch (c) {
+ case 'n':
+ noop = B_TRUE;
+ break;
+ case 'p':
+ parsable = B_TRUE;
+ break;
+ case 's':
+ stop = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get pool name and check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name argument\n"));
+ usage(B_FALSE);
+ }
+
+ poolname = argv[0];
+
+ if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+ return (1);
+
+ if (stop && noop) {
+ (void) fprintf(stderr, gettext("stop request ignored\n"));
+ return (0);
+ }
+
+ if (stop) {
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+ if (zpool_vdev_remove_cancel(zhp) != 0)
+ ret = 1;
+ } else {
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing device\n"));
+ usage(B_FALSE);
+ }
+
+ for (i = 1; i < argc; i++) {
+ if (noop) {
+ uint64_t size;
+
+ if (zpool_vdev_indirect_size(zhp, argv[i],
+ &size) != 0) {
+ ret = 1;
+ break;
+ }
+ if (parsable) {
+ (void) printf("%s %llu\n",
+ argv[i], size);
+ } else {
+ char valstr[32];
+ zfs_nicenum(size, valstr,
+ sizeof (valstr));
+ (void) printf("Memory that will be "
+ "used after removing %s: %s\n",
+ argv[i], valstr);
+ }
+ } else {
+ if (zpool_vdev_remove(zhp, argv[i]) != 0)
+ ret = 1;
+ }
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * zpool labelclear [-f] <vdev>
+ *
+ * -f Force clearing the label for the vdevs which are members of
+ * the exported or foreign pools.
+ *
+ * Verifies that the vdev is not active and zeros out the label information
+ * on the device.
+ */
+int
+zpool_do_labelclear(int argc, char **argv)
+{
+ char vdev[MAXPATHLEN];
+ char *name = NULL;
+ struct stat st;
+ int c, fd, ret = 0;
+ nvlist_t *config;
+ pool_state_t state;
+ boolean_t inuse = B_FALSE;
+ boolean_t force = B_FALSE;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "f")) != -1) {
+ switch (c) {
+ case 'f':
+ force = B_TRUE;
+ break;
+ default:
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get vdev name */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing vdev name\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ /*
+ * Check if we were given absolute path and use it as is.
+ * Otherwise if the provided vdev name doesn't point to a file,
+ * try prepending dsk path and appending s0.
+ */
+ (void) strlcpy(vdev, argv[0], sizeof (vdev));
+ if (vdev[0] != '/' && stat(vdev, &st) != 0) {
+ char *s;
+
+ (void) snprintf(vdev, sizeof (vdev), "%s/%s",
+#ifdef illumos
+ ZFS_DISK_ROOT, argv[0]);
+ if ((s = strrchr(argv[0], 's')) == NULL ||
+ !isdigit(*(s + 1)))
+ (void) strlcat(vdev, "s0", sizeof (vdev));
+#else
+ "/dev", argv[0]);
+#endif
+ if (stat(vdev, &st) != 0) {
+ (void) fprintf(stderr, gettext(
+ "failed to find device %s, try specifying absolute "
+ "path instead\n"), argv[0]);
+ return (1);
+ }
+ }
+
+ if ((fd = open(vdev, O_RDWR)) < 0) {
+ (void) fprintf(stderr, gettext("failed to open %s: %s\n"),
+ vdev, strerror(errno));
+ return (1);
+ }
+
+ if (zpool_read_label(fd, &config) != 0) {
+ (void) fprintf(stderr,
+ gettext("failed to read label from %s\n"), vdev);
+ return (1);
+ }
+ nvlist_free(config);
+
+ ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse);
+ if (ret != 0) {
+ (void) fprintf(stderr,
+ gettext("failed to check state for %s\n"), vdev);
+ return (1);
+ }
+
+ if (!inuse)
+ goto wipe_label;
+
+ switch (state) {
+ default:
+ case POOL_STATE_ACTIVE:
+ case POOL_STATE_SPARE:
+ case POOL_STATE_L2CACHE:
+ (void) fprintf(stderr, gettext(
+ "%s is a member (%s) of pool \"%s\"\n"),
+ vdev, zpool_pool_state_to_name(state), name);
+ ret = 1;
+ goto errout;
+
+ case POOL_STATE_EXPORTED:
+ if (force)
+ break;
+ (void) fprintf(stderr, gettext(
+ "use '-f' to override the following error:\n"
+ "%s is a member of exported pool \"%s\"\n"),
+ vdev, name);
+ ret = 1;
+ goto errout;
+
+ case POOL_STATE_POTENTIALLY_ACTIVE:
+ if (force)
+ break;
+ (void) fprintf(stderr, gettext(
+ "use '-f' to override the following error:\n"
+ "%s is a member of potentially active pool \"%s\"\n"),
+ vdev, name);
+ ret = 1;
+ goto errout;
+
+ case POOL_STATE_DESTROYED:
+ /* inuse should never be set for a destroyed pool */
+ assert(0);
+ break;
+ }
+
+wipe_label:
+ ret = zpool_clear_label(fd);
+ if (ret != 0) {
+ (void) fprintf(stderr,
+ gettext("failed to clear label for %s\n"), vdev);
+ }
+
+errout:
+ free(name);
+ (void) close(fd);
+
+ return (ret);
+}
+
+/*
+ * zpool create [-fnd] [-B] [-o property=value] ...
+ * [-O file-system-property=value] ...
+ * [-R root] [-m mountpoint] [-t tempname] <pool> <dev> ...
+ *
+ * -B Create boot partition.
+ * -f Force creation, even if devices appear in use
+ * -n Do not create the pool, but display the resulting layout if it
+ * were to be created.
+ * -R Create a pool under an alternate root
+ * -m Set default mountpoint for the root dataset. By default it's
+ * '/<pool>'
+ * -t Use the temporary name until the pool is exported.
+ * -o Set property=value.
+ * -d Don't automatically enable all supported pool features
+ * (individual features can be enabled with -o).
+ * -O Set fsproperty=value in the pool's root file system
+ *
+ * Creates the named pool according to the given vdev specification. The
+ * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once
+ * we get the nvlist back from get_vdev_spec(), we either print out the contents
+ * (if '-n' was specified), or pass it to libzfs to do the creation.
+ */
+
+#define SYSTEM256 (256 * 1024 * 1024)
+int
+zpool_do_create(int argc, char **argv)
+{
+ boolean_t force = B_FALSE;
+ boolean_t dryrun = B_FALSE;
+ boolean_t enable_all_pool_feat = B_TRUE;
+ zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL;
+ uint64_t boot_size = 0;
+ int c;
+ nvlist_t *nvroot = NULL;
+ char *poolname;
+ char *tname = NULL;
+ int ret = 1;
+ char *altroot = NULL;
+ char *mountpoint = NULL;
+ nvlist_t *fsprops = NULL;
+ nvlist_t *props = NULL;
+ char *propval;
+
+ /* check options */
+ while ((c = getopt(argc, argv, ":fndBR:m:o:O:t:")) != -1) {
+ switch (c) {
+ case 'f':
+ force = B_TRUE;
+ break;
+ case 'n':
+ dryrun = B_TRUE;
+ break;
+ case 'd':
+ enable_all_pool_feat = B_FALSE;
+ break;
+ case 'B':
+#ifdef illumos
+ /*
+ * We should create the system partition.
+ * Also make sure the size is set.
+ */
+ boot_type = ZPOOL_CREATE_BOOT_LABEL;
+ if (boot_size == 0)
+ boot_size = SYSTEM256;
+ break;
+#else
+ (void) fprintf(stderr,
+ gettext("option '%c' is not supported\n"),
+ optopt);
+ goto badusage;
+#endif
+ case 'R':
+ altroot = optarg;
+ if (add_prop_list(zpool_prop_to_name(
+ ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
+ goto errout;
+ if (add_prop_list_default(zpool_prop_to_name(
+ ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+ goto errout;
+ break;
+ case 'm':
+ /* Equivalent to -O mountpoint=optarg */
+ mountpoint = optarg;
+ break;
+ case 'o':
+ if ((propval = strchr(optarg, '=')) == NULL) {
+ (void) fprintf(stderr, gettext("missing "
+ "'=' for -o option\n"));
+ goto errout;
+ }
+ *propval = '\0';
+ propval++;
+
+ if (add_prop_list(optarg, propval, &props, B_TRUE))
+ goto errout;
+
+ /*
+ * Get bootsize value for make_root_vdev().
+ */
+ if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) {
+ if (zfs_nicestrtonum(g_zfs, propval,
+ &boot_size) < 0 || boot_size == 0) {
+ (void) fprintf(stderr,
+ gettext("bad boot partition size "
+ "'%s': %s\n"), propval,
+ libzfs_error_description(g_zfs));
+ goto errout;
+ }
+ }
+
+ /*
+ * If the user is creating a pool that doesn't support
+ * feature flags, don't enable any features.
+ */
+ if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
+ char *end;
+ u_longlong_t ver;
+
+ ver = strtoull(propval, &end, 10);
+ if (*end == '\0' &&
+ ver < SPA_VERSION_FEATURES) {
+ enable_all_pool_feat = B_FALSE;
+ }
+ }
+ if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT)
+ altroot = propval;
+ break;
+ case 'O':
+ if ((propval = strchr(optarg, '=')) == NULL) {
+ (void) fprintf(stderr, gettext("missing "
+ "'=' for -O option\n"));
+ goto errout;
+ }
+ *propval = '\0';
+ propval++;
+
+ /*
+ * Mountpoints are checked and then added later.
+ * Uniquely among properties, they can be specified
+ * more than once, to avoid conflict with -m.
+ */
+ if (0 == strcmp(optarg,
+ zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) {
+ mountpoint = propval;
+ } else if (add_prop_list(optarg, propval, &fsprops,
+ B_FALSE)) {
+ goto errout;
+ }
+ break;
+ case 't':
+ /*
+ * Sanity check temporary pool name.
+ */
+ if (strchr(optarg, '/') != NULL) {
+ (void) fprintf(stderr, gettext("cannot create "
+ "'%s': invalid character '/' in temporary "
+ "name\n"), optarg);
+ (void) fprintf(stderr, gettext("use 'zfs "
+ "create' to create a dataset\n"));
+ goto errout;
+ }
+
+ if (add_prop_list(zpool_prop_to_name(
+ ZPOOL_PROP_TNAME), optarg, &props, B_TRUE))
+ goto errout;
+ if (add_prop_list_default(zpool_prop_to_name(
+ ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+ goto errout;
+ tname = optarg;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ goto badusage;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ goto badusage;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get pool name and check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name argument\n"));
+ goto badusage;
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing vdev specification\n"));
+ goto badusage;
+ }
+
+ poolname = argv[0];
+
+ /*
+ * As a special case, check for use of '/' in the name, and direct the
+ * user to use 'zfs create' instead.
+ */
+ if (strchr(poolname, '/') != NULL) {
+ (void) fprintf(stderr, gettext("cannot create '%s': invalid "
+ "character '/' in pool name\n"), poolname);
+ (void) fprintf(stderr, gettext("use 'zfs create' to "
+ "create a dataset\n"));
+ goto errout;
+ }
+
+ /*
+ * Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used,
+ * and not set otherwise.
+ */
+ if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
+ const char *propname;
+ char *strptr, *buf = NULL;
+ int rv;
+
+ propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
+ if (nvlist_lookup_string(props, propname, &strptr) != 0) {
+ (void) asprintf(&buf, "%" PRIu64, boot_size);
+ if (buf == NULL) {
+ (void) fprintf(stderr,
+ gettext("internal error: out of memory\n"));
+ goto errout;
+ }
+ rv = add_prop_list(propname, buf, &props, B_TRUE);
+ free(buf);
+ if (rv != 0)
+ goto errout;
+ }
+ } else {
+ const char *propname;
+ char *strptr;
+
+ propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
+ if (nvlist_lookup_string(props, propname, &strptr) == 0) {
+ (void) fprintf(stderr, gettext("error: setting boot "
+ "partition size requires option '-B'\n"));
+ goto errout;
+ }
+ }
+
+ /* pass off to get_vdev_spec for bulk processing */
+ nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
+ boot_type, boot_size, argc - 1, argv + 1);
+ if (nvroot == NULL)
+ goto errout;
+
+ /* make_root_vdev() allows 0 toplevel children if there are spares */
+ if (!zfs_allocatable_devs(nvroot)) {
+ (void) fprintf(stderr, gettext("invalid vdev "
+ "specification: at least one toplevel vdev must be "
+ "specified\n"));
+ goto errout;
+ }
+
+ if (altroot != NULL && altroot[0] != '/') {
+ (void) fprintf(stderr, gettext("invalid alternate root '%s': "
+ "must be an absolute path\n"), altroot);
+ goto errout;
+ }
+
+ /*
+ * Check the validity of the mountpoint and direct the user to use the
+ * '-m' mountpoint option if it looks like its in use.
+ * Ignore the checks if the '-f' option is given.
+ */
+ if (!force && (mountpoint == NULL ||
+ (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
+ strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) {
+ char buf[MAXPATHLEN];
+ DIR *dirp;
+
+ if (mountpoint && mountpoint[0] != '/') {
+ (void) fprintf(stderr, gettext("invalid mountpoint "
+ "'%s': must be an absolute path, 'legacy', or "
+ "'none'\n"), mountpoint);
+ goto errout;
+ }
+
+ if (mountpoint == NULL) {
+ if (altroot != NULL)
+ (void) snprintf(buf, sizeof (buf), "%s/%s",
+ altroot, poolname);
+ else
+ (void) snprintf(buf, sizeof (buf), "/%s",
+ poolname);
+ } else {
+ if (altroot != NULL)
+ (void) snprintf(buf, sizeof (buf), "%s%s",
+ altroot, mountpoint);
+ else
+ (void) snprintf(buf, sizeof (buf), "%s",
+ mountpoint);
+ }
+
+ if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
+ (void) fprintf(stderr, gettext("mountpoint '%s' : "
+ "%s\n"), buf, strerror(errno));
+ (void) fprintf(stderr, gettext("use '-m' "
+ "option to provide a different default\n"));
+ goto errout;
+ } else if (dirp) {
+ int count = 0;
+
+ while (count < 3 && readdir(dirp) != NULL)
+ count++;
+ (void) closedir(dirp);
+
+ if (count > 2) {
+ (void) fprintf(stderr, gettext("mountpoint "
+ "'%s' exists and is not empty\n"), buf);
+ (void) fprintf(stderr, gettext("use '-m' "
+ "option to provide a "
+ "different default\n"));
+ goto errout;
+ }
+ }
+ }
+
+ /*
+ * Now that the mountpoint's validity has been checked, ensure that
+ * the property is set appropriately prior to creating the pool.
+ */
+ if (mountpoint != NULL) {
+ ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
+ mountpoint, &fsprops, B_FALSE);
+ if (ret != 0)
+ goto errout;
+ }
+
+ ret = 1;
+ if (dryrun) {
+ /*
+ * For a dry run invocation, print out a basic message and run
+ * through all the vdevs in the list and print out in an
+ * appropriate hierarchy.
+ */
+ (void) printf(gettext("would create '%s' with the "
+ "following layout:\n\n"), poolname);
+
+ print_vdev_tree(NULL, poolname, nvroot, 0, "", 0);
+ print_vdev_tree(NULL, "dedup", nvroot, 0,
+ VDEV_ALLOC_BIAS_DEDUP, 0);
+ print_vdev_tree(NULL, "special", nvroot, 0,
+ VDEV_ALLOC_BIAS_SPECIAL, 0);
+ print_vdev_tree(NULL, "logs", nvroot, 0,
+ VDEV_ALLOC_BIAS_LOG, 0);
+
+ ret = 0;
+ } else {
+ /*
+ * Hand off to libzfs.
+ */
+ if (enable_all_pool_feat) {
+ spa_feature_t i;
+ for (i = 0; i < SPA_FEATURES; i++) {
+ char propname[MAXPATHLEN];
+ zfeature_info_t *feat = &spa_feature_table[i];
+
+ (void) snprintf(propname, sizeof (propname),
+ "feature@%s", feat->fi_uname);
+
+ /*
+ * Skip feature if user specified it manually
+ * on the command line.
+ */
+ if (nvlist_exists(props, propname))
+ continue;
+
+ ret = add_prop_list(propname,
+ ZFS_FEATURE_ENABLED, &props, B_TRUE);
+ if (ret != 0)
+ goto errout;
+ }
+ }
+
+ ret = 1;
+ if (zpool_create(g_zfs, poolname,
+ nvroot, props, fsprops) == 0) {
+ zfs_handle_t *pool = zfs_open(g_zfs,
+ tname ? tname : poolname, ZFS_TYPE_FILESYSTEM);
+ if (pool != NULL) {
+ if (zfs_mount(pool, NULL, 0) == 0)
+ ret = zfs_shareall(pool);
+ zfs_close(pool);
+ }
+ } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
+ (void) fprintf(stderr, gettext("pool name may have "
+ "been omitted\n"));
+ }
+ }
+
+errout:
+ nvlist_free(nvroot);
+ nvlist_free(fsprops);
+ nvlist_free(props);
+ return (ret);
+badusage:
+ nvlist_free(fsprops);
+ nvlist_free(props);
+ usage(B_FALSE);
+ return (2);
+}
+
+/*
+ * zpool destroy <pool>
+ *
+ * -f Forcefully unmount any datasets
+ *
+ * Destroy the given pool. Automatically unmounts any datasets in the pool.
+ */
+int
+zpool_do_destroy(int argc, char **argv)
+{
+ boolean_t force = B_FALSE;
+ int c;
+ char *pool;
+ zpool_handle_t *zhp;
+ int ret;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "f")) != -1) {
+ switch (c) {
+ case 'f':
+ force = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool argument\n"));
+ usage(B_FALSE);
+ }
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ pool = argv[0];
+
+ if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
+ /*
+ * As a special case, check for use of '/' in the name, and
+ * direct the user to use 'zfs destroy' instead.
+ */
+ if (strchr(pool, '/') != NULL)
+ (void) fprintf(stderr, gettext("use 'zfs destroy' to "
+ "destroy a dataset\n"));
+ return (1);
+ }
+
+ if (zpool_disable_datasets(zhp, force) != 0) {
+ (void) fprintf(stderr, gettext("could not destroy '%s': "
+ "could not unmount datasets\n"), zpool_get_name(zhp));
+ return (1);
+ }
+
+ /* The history must be logged as part of the export */
+ log_history = B_FALSE;
+
+ ret = (zpool_destroy(zhp, history_str) != 0);
+
+ zpool_close(zhp);
+
+ return (ret);
+}
+
+/*
+ * zpool export [-f] <pool> ...
+ *
+ * -f Forcefully unmount datasets
+ *
+ * Export the given pools. By default, the command will attempt to cleanly
+ * unmount any active datasets within the pool. If the '-f' flag is specified,
+ * then the datasets will be forcefully unmounted.
+ */
+int
+zpool_do_export(int argc, char **argv)
+{
+ boolean_t force = B_FALSE;
+ boolean_t hardforce = B_FALSE;
+ int c;
+ zpool_handle_t *zhp;
+ int ret;
+ int i;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "fF")) != -1) {
+ switch (c) {
+ case 'f':
+ force = B_TRUE;
+ break;
+ case 'F':
+ hardforce = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool argument\n"));
+ usage(B_FALSE);
+ }
+
+ ret = 0;
+ for (i = 0; i < argc; i++) {
+ if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
+ ret = 1;
+ continue;
+ }
+
+ if (zpool_disable_datasets(zhp, force) != 0) {
+ ret = 1;
+ zpool_close(zhp);
+ continue;
+ }
+
+ /* The history must be logged as part of the export */
+ log_history = B_FALSE;
+
+ if (hardforce) {
+ if (zpool_export_force(zhp, history_str) != 0)
+ ret = 1;
+ } else if (zpool_export(zhp, force, history_str) != 0) {
+ ret = 1;
+ }
+
+ zpool_close(zhp);
+ }
+
+ return (ret);
+}
+
+/*
+ * Given a vdev configuration, determine the maximum width needed for the device
+ * name column.
+ */
+static int
+max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max,
+ int name_flags)
+{
+ char *name;
+ nvlist_t **child;
+ uint_t c, children;
+ int ret;
+
+ name = zpool_vdev_name(g_zfs, zhp, nv, name_flags | VDEV_NAME_TYPE_ID);
+ if (strlen(name) + depth > max)
+ max = strlen(name) + depth;
+
+ free(name);
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++)
+ if ((ret = max_width(zhp, child[c], depth + 2,
+ max, name_flags)) > max)
+ max = ret;
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++)
+ if ((ret = max_width(zhp, child[c], depth + 2,
+ max, name_flags)) > max)
+ max = ret;
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++)
+ if ((ret = max_width(zhp, child[c], depth + 2,
+ max, name_flags)) > max)
+ max = ret;
+ }
+
+ return (max);
+}
+
+typedef struct spare_cbdata {
+ uint64_t cb_guid;
+ zpool_handle_t *cb_zhp;
+} spare_cbdata_t;
+
+static boolean_t
+find_vdev(nvlist_t *nv, uint64_t search)
+{
+ uint64_t guid;
+ nvlist_t **child;
+ uint_t c, children;
+
+ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
+ search == guid)
+ return (B_TRUE);
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++)
+ if (find_vdev(child[c], search))
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+static int
+find_spare(zpool_handle_t *zhp, void *data)
+{
+ spare_cbdata_t *cbp = data;
+ nvlist_t *config, *nvroot;
+
+ config = zpool_get_config(zhp, NULL);
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+
+ if (find_vdev(nvroot, cbp->cb_guid)) {
+ cbp->cb_zhp = zhp;
+ return (1);
+ }
+
+ zpool_close(zhp);
+ return (0);
+}
+
+typedef struct status_cbdata {
+ int cb_count;
+ int cb_name_flags;
+ int cb_namewidth;
+ boolean_t cb_allpools;
+ boolean_t cb_verbose;
+ boolean_t cb_explain;
+ boolean_t cb_first;
+ boolean_t cb_dedup_stats;
+ boolean_t cb_print_status;
+} status_cbdata_t;
+
+/*
+ * Print out configuration state as requested by status_callback.
+ */
+static void
+print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
+ nvlist_t *nv, int depth, boolean_t isspare)
+{
+ nvlist_t **child;
+ uint_t c, vsc, children;
+ pool_scan_stat_t *ps = NULL;
+ vdev_stat_t *vs;
+ char rbuf[6], wbuf[6], cbuf[6];
+ char *vname;
+ uint64_t notpresent;
+ uint64_t ashift;
+ spare_cbdata_t spare_cb;
+ const char *state;
+ char *type;
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0)
+ children = 0;
+
+ verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &vsc) == 0);
+
+ verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+
+ if (strcmp(type, VDEV_TYPE_INDIRECT) == 0)
+ return;
+
+ state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
+ if (isspare) {
+ /*
+ * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
+ * online drives.
+ */
+ if (vs->vs_aux == VDEV_AUX_SPARED)
+ state = "INUSE";
+ else if (vs->vs_state == VDEV_STATE_HEALTHY)
+ state = "AVAIL";
+ }
+
+ (void) printf("\t%*s%-*s %-8s", depth, "", cb->cb_namewidth - depth,
+ name, state);
+
+ if (!isspare) {
+ zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
+ zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
+ zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
+ (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
+ }
+
+ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
+ &notpresent) == 0 ||
+ vs->vs_state <= VDEV_STATE_CANT_OPEN) {
+ char *path;
+ if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0)
+ (void) printf(" was %s", path);
+ } else if (vs->vs_aux != 0) {
+ (void) printf(" ");
+
+ switch (vs->vs_aux) {
+ case VDEV_AUX_OPEN_FAILED:
+ (void) printf(gettext("cannot open"));
+ break;
+
+ case VDEV_AUX_BAD_GUID_SUM:
+ (void) printf(gettext("missing device"));
+ break;
+
+ case VDEV_AUX_NO_REPLICAS:
+ (void) printf(gettext("insufficient replicas"));
+ break;
+
+ case VDEV_AUX_VERSION_NEWER:
+ (void) printf(gettext("newer version"));
+ break;
+
+ case VDEV_AUX_UNSUP_FEAT:
+ (void) printf(gettext("unsupported feature(s)"));
+ break;
+
+ case VDEV_AUX_ASHIFT_TOO_BIG:
+ (void) printf(gettext("unsupported minimum blocksize"));
+ break;
+
+ case VDEV_AUX_SPARED:
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
+ &spare_cb.cb_guid) == 0);
+ if (zpool_iter(g_zfs, find_spare, &spare_cb) == 1) {
+ if (strcmp(zpool_get_name(spare_cb.cb_zhp),
+ zpool_get_name(zhp)) == 0)
+ (void) printf(gettext("currently in "
+ "use"));
+ else
+ (void) printf(gettext("in use by "
+ "pool '%s'"),
+ zpool_get_name(spare_cb.cb_zhp));
+ zpool_close(spare_cb.cb_zhp);
+ } else {
+ (void) printf(gettext("currently in use"));
+ }
+ break;
+
+ case VDEV_AUX_ERR_EXCEEDED:
+ (void) printf(gettext("too many errors"));
+ break;
+
+ case VDEV_AUX_IO_FAILURE:
+ (void) printf(gettext("experienced I/O failures"));
+ break;
+
+ case VDEV_AUX_BAD_LOG:
+ (void) printf(gettext("bad intent log"));
+ break;
+
+ case VDEV_AUX_EXTERNAL:
+ (void) printf(gettext("external device fault"));
+ break;
+
+ case VDEV_AUX_SPLIT_POOL:
+ (void) printf(gettext("split into new pool"));
+ break;
+
+ case VDEV_AUX_ACTIVE:
+ (void) printf(gettext("currently in use"));
+ break;
+
+ case VDEV_AUX_CHILDREN_OFFLINE:
+ (void) printf(gettext("all children offline"));
+ break;
+
+ default:
+ (void) printf(gettext("corrupted data"));
+ break;
+ }
+ } else if (children == 0 && !isspare &&
+ VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
+ vs->vs_configured_ashift < vs->vs_physical_ashift) {
+ (void) printf(
+ gettext(" block size: %dB configured, %dB native"),
+ 1 << vs->vs_configured_ashift, 1 << vs->vs_physical_ashift);
+ }
+
+ (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
+ (uint64_t **)&ps, &c);
+
+ if (ps != NULL && ps->pss_state == DSS_SCANNING &&
+ vs->vs_scan_processed != 0 && children == 0) {
+ (void) printf(gettext(" (%s)"),
+ (ps->pss_func == POOL_SCAN_RESILVER) ?
+ "resilvering" : "repairing");
+ }
+
+ if ((vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE ||
+ vs->vs_initialize_state == VDEV_INITIALIZE_SUSPENDED ||
+ vs->vs_initialize_state == VDEV_INITIALIZE_COMPLETE) &&
+ !vs->vs_scan_removing) {
+ char zbuf[1024];
+ char tbuf[256];
+ struct tm zaction_ts;
+
+ time_t t = vs->vs_initialize_action_time;
+ int initialize_pct = 100;
+ if (vs->vs_initialize_state != VDEV_INITIALIZE_COMPLETE) {
+ initialize_pct = (vs->vs_initialize_bytes_done * 100 /
+ (vs->vs_initialize_bytes_est + 1));
+ }
+
+ (void) localtime_r(&t, &zaction_ts);
+ (void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
+
+ switch (vs->vs_initialize_state) {
+ case VDEV_INITIALIZE_SUSPENDED:
+ (void) snprintf(zbuf, sizeof (zbuf),
+ ", suspended, started at %s", tbuf);
+ break;
+ case VDEV_INITIALIZE_ACTIVE:
+ (void) snprintf(zbuf, sizeof (zbuf),
+ ", started at %s", tbuf);
+ break;
+ case VDEV_INITIALIZE_COMPLETE:
+ (void) snprintf(zbuf, sizeof (zbuf),
+ ", completed at %s", tbuf);
+ break;
+ }
+
+ (void) printf(gettext(" (%d%% initialized%s)"),
+ initialize_pct, zbuf);
+ }
+
+ (void) printf("\n");
+
+ for (c = 0; c < children; c++) {
+ uint64_t islog = B_FALSE, ishole = B_FALSE;
+
+ /* Don't print logs or holes here */
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &islog);
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
+ &ishole);
+ if (islog || ishole)
+ continue;
+ /* Only print normal classes here */
+ if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags | VDEV_NAME_TYPE_ID);
+ print_status_config(zhp, cb, vname, child[c], depth + 2,
+ isspare);
+ free(vname);
+ }
+}
+
+/*
+ * Print the configuration of an exported pool. Iterate over all vdevs in the
+ * pool, printing out the name and status for each one.
+ */
+static void
+print_import_config(status_cbdata_t *cb, const char *name, nvlist_t *nv,
+ int depth)
+{
+ nvlist_t **child;
+ uint_t c, children;
+ vdev_stat_t *vs;
+ char *type, *vname;
+
+ verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+ if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
+ strcmp(type, VDEV_TYPE_HOLE) == 0)
+ return;
+
+ verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &c) == 0);
+
+ (void) printf("\t%*s%-*s", depth, "", cb->cb_namewidth - depth, name);
+ (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
+
+ if (vs->vs_aux != 0) {
+ (void) printf(" ");
+
+ switch (vs->vs_aux) {
+ case VDEV_AUX_OPEN_FAILED:
+ (void) printf(gettext("cannot open"));
+ break;
+
+ case VDEV_AUX_BAD_GUID_SUM:
+ (void) printf(gettext("missing device"));
+ break;
+
+ case VDEV_AUX_NO_REPLICAS:
+ (void) printf(gettext("insufficient replicas"));
+ break;
+
+ case VDEV_AUX_VERSION_NEWER:
+ (void) printf(gettext("newer version"));
+ break;
+
+ case VDEV_AUX_UNSUP_FEAT:
+ (void) printf(gettext("unsupported feature(s)"));
+ break;
+
+ case VDEV_AUX_ERR_EXCEEDED:
+ (void) printf(gettext("too many errors"));
+ break;
+
+ case VDEV_AUX_ACTIVE:
+ (void) printf(gettext("currently in use"));
+ break;
+
+ case VDEV_AUX_CHILDREN_OFFLINE:
+ (void) printf(gettext("all children offline"));
+ break;
+
+ default:
+ (void) printf(gettext("corrupted data"));
+ break;
+ }
+ }
+ (void) printf("\n");
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0)
+ return;
+
+ for (c = 0; c < children; c++) {
+ uint64_t is_log = B_FALSE;
+
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &is_log);
+ if (is_log)
+ continue;
+ if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, NULL, child[c],
+ cb->cb_name_flags | VDEV_NAME_TYPE_ID);
+ print_import_config(cb, vname, child[c], depth + 2);
+ free(vname);
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+ &child, &children) == 0) {
+ (void) printf(gettext("\tcache\n"));
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, NULL, child[c],
+ cb->cb_name_flags);
+ (void) printf("\t %s\n", vname);
+ free(vname);
+ }
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+ &child, &children) == 0) {
+ (void) printf(gettext("\tspares\n"));
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, NULL, child[c],
+ cb->cb_name_flags);
+ (void) printf("\t %s\n", vname);
+ free(vname);
+ }
+ }
+}
+
+/*
+ * Print specialized class vdevs.
+ *
+ * These are recorded as top level vdevs in the main pool child array
+ * but with "is_log" set to 1 or an "alloc_bias" string. We use either
+ * print_status_config() or print_import_config() to print the top level
+ * class vdevs then any of their children (eg mirrored slogs) are printed
+ * recursively - which works because only the top level vdev is marked.
+ */
+static void
+print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
+ const char *class)
+{
+ uint_t c, children;
+ nvlist_t **child;
+ boolean_t printed = B_FALSE;
+
+ assert(zhp != NULL || !cb->cb_verbose);
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
+ &children) != 0)
+ return;
+
+ for (c = 0; c < children; c++) {
+ uint64_t is_log = B_FALSE;
+ char *bias = NULL;
+ char *type = NULL;
+
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &is_log);
+
+ if (is_log) {
+ bias = VDEV_ALLOC_CLASS_LOGS;
+ } else {
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_TYPE, &type);
+ }
+
+ if (bias == NULL || strcmp(bias, class) != 0)
+ continue;
+ if (!is_log && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
+ continue;
+
+ if (!printed) {
+ (void) printf("\t%s\t\n", gettext(class));
+ printed = B_TRUE;
+ }
+
+ char *name = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags | VDEV_NAME_TYPE_ID);
+ if (cb->cb_print_status)
+ print_status_config(zhp, cb, name, child[c], 2,
+ B_FALSE);
+ else
+ print_import_config(cb, name, child[c], 2);
+ free(name);
+ }
+}
+
+/*
+ * Display the status for the given pool.
+ */
+static void
+show_import(nvlist_t *config)
+{
+ uint64_t pool_state;
+ vdev_stat_t *vs;
+ char *name;
+ uint64_t guid;
+ uint64_t hostid = 0;
+ char *msgid;
+ char *hostname = "unknown";
+ nvlist_t *nvroot, *nvinfo;
+ int reason;
+ const char *health;
+ uint_t vsc;
+ char *comment;
+ status_cbdata_t cb = { 0 };
+
+ verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+ &name) == 0);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+ &guid) == 0);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+ &pool_state) == 0);
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+
+ verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &vsc) == 0);
+ health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
+
+ reason = zpool_import_status(config, &msgid);
+
+ (void) printf(gettext(" pool: %s\n"), name);
+ (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
+ (void) printf(gettext(" state: %s"), health);
+ if (pool_state == POOL_STATE_DESTROYED)
+ (void) printf(gettext(" (DESTROYED)"));
+ (void) printf("\n");
+
+ switch (reason) {
+ case ZPOOL_STATUS_MISSING_DEV_R:
+ case ZPOOL_STATUS_MISSING_DEV_NR:
+ case ZPOOL_STATUS_BAD_GUID_SUM:
+ (void) printf(gettext(" status: One or more devices are "
+ "missing from the system.\n"));
+ break;
+
+ case ZPOOL_STATUS_CORRUPT_LABEL_R:
+ case ZPOOL_STATUS_CORRUPT_LABEL_NR:
+ (void) printf(gettext(" status: One or more devices contains "
+ "corrupted data.\n"));
+ break;
+
+ case ZPOOL_STATUS_CORRUPT_DATA:
+ (void) printf(
+ gettext(" status: The pool data is corrupted.\n"));
+ break;
+
+ case ZPOOL_STATUS_OFFLINE_DEV:
+ (void) printf(gettext(" status: One or more devices "
+ "are offlined.\n"));
+ break;
+
+ case ZPOOL_STATUS_CORRUPT_POOL:
+ (void) printf(gettext(" status: The pool metadata is "
+ "corrupted.\n"));
+ break;
+
+ case ZPOOL_STATUS_VERSION_OLDER:
+ (void) printf(gettext(" status: The pool is formatted using a "
+ "legacy on-disk version.\n"));
+ break;
+
+ case ZPOOL_STATUS_VERSION_NEWER:
+ (void) printf(gettext(" status: The pool is formatted using an "
+ "incompatible version.\n"));
+ break;
+
+ case ZPOOL_STATUS_FEAT_DISABLED:
+ (void) printf(gettext(" status: Some supported features are "
+ "not enabled on the pool.\n"));
+ break;
+
+ case ZPOOL_STATUS_UNSUP_FEAT_READ:
+ (void) printf(gettext("status: The pool uses the following "
+ "feature(s) not supported on this system:\n"));
+ zpool_print_unsup_feat(config);
+ break;
+
+ case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
+ (void) printf(gettext("status: The pool can only be accessed "
+ "in read-only mode on this system. It\n\tcannot be "
+ "accessed in read-write mode because it uses the "
+ "following\n\tfeature(s) not supported on this system:\n"));
+ zpool_print_unsup_feat(config);
+ break;
+
+ case ZPOOL_STATUS_HOSTID_ACTIVE:
+ (void) printf(gettext(" status: The pool is currently "
+ "imported by another system.\n"));
+ break;
+
+ case ZPOOL_STATUS_HOSTID_REQUIRED:
+ (void) printf(gettext(" status: The pool has the "
+ "multihost property on. It cannot\n\tbe safely imported "
+ "when the system hostid is not set.\n"));
+ break;
+
+ case ZPOOL_STATUS_HOSTID_MISMATCH:
+ (void) printf(gettext(" status: The pool was last accessed by "
+ "another system.\n"));
+ break;
+
+ case ZPOOL_STATUS_FAULTED_DEV_R:
+ case ZPOOL_STATUS_FAULTED_DEV_NR:
+ (void) printf(gettext(" status: One or more devices are "
+ "faulted.\n"));
+ break;
+
+ case ZPOOL_STATUS_BAD_LOG:
+ (void) printf(gettext(" status: An intent log record cannot be "
+ "read.\n"));
+ break;
+
+ case ZPOOL_STATUS_RESILVERING:
+ (void) printf(gettext(" status: One or more devices were being "
+ "resilvered.\n"));
+ break;
+
+ case ZPOOL_STATUS_NON_NATIVE_ASHIFT:
+ (void) printf(gettext("status: One or more devices were "
+ "configured to use a non-native block size.\n"
+ "\tExpect reduced performance.\n"));
+ break;
+
+ default:
+ /*
+ * No other status can be seen when importing pools.
+ */
+ assert(reason == ZPOOL_STATUS_OK);
+ }
+
+ /*
+ * Print out an action according to the overall state of the pool.
+ */
+ if (vs->vs_state == VDEV_STATE_HEALTHY) {
+ if (reason == ZPOOL_STATUS_VERSION_OLDER ||
+ reason == ZPOOL_STATUS_FEAT_DISABLED) {
+ (void) printf(gettext(" action: The pool can be "
+ "imported using its name or numeric identifier, "
+ "though\n\tsome features will not be available "
+ "without an explicit 'zpool upgrade'.\n"));
+ } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
+ (void) printf(gettext(" action: The pool can be "
+ "imported using its name or numeric "
+ "identifier and\n\tthe '-f' flag.\n"));
+ } else {
+ (void) printf(gettext(" action: The pool can be "
+ "imported using its name or numeric "
+ "identifier.\n"));
+ }
+ } else if (vs->vs_state == VDEV_STATE_DEGRADED) {
+ (void) printf(gettext(" action: The pool can be imported "
+ "despite missing or damaged devices. The\n\tfault "
+ "tolerance of the pool may be compromised if imported.\n"));
+ } else {
+ switch (reason) {
+ case ZPOOL_STATUS_VERSION_NEWER:
+ (void) printf(gettext(" action: The pool cannot be "
+ "imported. Access the pool on a system running "
+ "newer\n\tsoftware, or recreate the pool from "
+ "backup.\n"));
+ break;
+ case ZPOOL_STATUS_UNSUP_FEAT_READ:
+ (void) printf(gettext("action: The pool cannot be "
+ "imported. Access the pool on a system that "
+ "supports\n\tthe required feature(s), or recreate "
+ "the pool from backup.\n"));
+ break;
+ case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
+ (void) printf(gettext("action: The pool cannot be "
+ "imported in read-write mode. Import the pool "
+ "with\n"
+ "\t\"-o readonly=on\", access the pool on a system "
+ "that supports the\n\trequired feature(s), or "
+ "recreate the pool from backup.\n"));
+ break;
+ case ZPOOL_STATUS_MISSING_DEV_R:
+ case ZPOOL_STATUS_MISSING_DEV_NR:
+ case ZPOOL_STATUS_BAD_GUID_SUM:
+ (void) printf(gettext(" action: The pool cannot be "
+ "imported. Attach the missing\n\tdevices and try "
+ "again.\n"));
+ break;
+ case ZPOOL_STATUS_HOSTID_ACTIVE:
+ VERIFY0(nvlist_lookup_nvlist(config,
+ ZPOOL_CONFIG_LOAD_INFO, &nvinfo));
+
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
+ hostname = fnvlist_lookup_string(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME);
+
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTID))
+ hostid = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID);
+
+ (void) printf(gettext(" action: The pool must be "
+ "exported from %s (hostid=%lx)\n\tbefore it "
+ "can be safely imported.\n"), hostname,
+ (unsigned long) hostid);
+ break;
+ case ZPOOL_STATUS_HOSTID_REQUIRED:
+ (void) printf(gettext(" action: Check the SMF "
+ "svc:/system/hostid service.\n"));
+ break;
+ default:
+ (void) printf(gettext(" action: The pool cannot be "
+ "imported due to damaged devices or data.\n"));
+ }
+ }
+
+ /* Print the comment attached to the pool. */
+ if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
+ (void) printf(gettext("comment: %s\n"), comment);
+
+ /*
+ * If the state is "closed" or "can't open", and the aux state
+ * is "corrupt data":
+ */
+ if (((vs->vs_state == VDEV_STATE_CLOSED) ||
+ (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
+ (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
+ if (pool_state == POOL_STATE_DESTROYED)
+ (void) printf(gettext("\tThe pool was destroyed, "
+ "but can be imported using the '-Df' flags.\n"));
+ else if (pool_state != POOL_STATE_EXPORTED)
+ (void) printf(gettext("\tThe pool may be active on "
+ "another system, but can be imported using\n\t"
+ "the '-f' flag.\n"));
+ }
+
+ if (msgid != NULL)
+ (void) printf(gettext(" see: http://illumos.org/msg/%s\n"),
+ msgid);
+
+ (void) printf(gettext(" config:\n\n"));
+
+ cb.cb_namewidth = max_width(NULL, nvroot, 0, 0, 0);
+ if (cb.cb_namewidth < 10)
+ cb.cb_namewidth = 10;
+
+ print_import_config(&cb, name, nvroot, 0);
+
+ print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_DEDUP);
+ print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
+ print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_CLASS_LOGS);
+
+ if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
+ (void) printf(gettext("\n\tAdditional devices are known to "
+ "be part of this pool, though their\n\texact "
+ "configuration cannot be determined.\n"));
+ }
+}
+
+static boolean_t
+zfs_force_import_required(nvlist_t *config)
+{
+ uint64_t state;
+ uint64_t hostid = 0;
+ nvlist_t *nvinfo;
+
+ state = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE);
+ (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
+
+ if (state != POOL_STATE_EXPORTED && hostid != get_system_hostid())
+ return (B_TRUE);
+
+ nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_STATE)) {
+ mmp_state_t mmp_state = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_STATE);
+
+ if (mmp_state != MMP_STATE_INACTIVE)
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Perform the import for the given configuration. This passes the heavy
+ * lifting off to zpool_import_props(), and then mounts the datasets contained
+ * within the pool.
+ */
+static int
+do_import(nvlist_t *config, const char *newname, const char *mntopts,
+ nvlist_t *props, int flags)
+{
+ zpool_handle_t *zhp;
+ char *name;
+ uint64_t version;
+
+ name = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
+ version = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION);
+
+ if (!SPA_VERSION_IS_SUPPORTED(version)) {
+ (void) fprintf(stderr, gettext("cannot import '%s': pool "
+ "is formatted using an unsupported ZFS version\n"), name);
+ return (1);
+ } else if (zfs_force_import_required(config) &&
+ !(flags & ZFS_IMPORT_ANY_HOST)) {
+ mmp_state_t mmp_state = MMP_STATE_INACTIVE;
+ nvlist_t *nvinfo;
+
+ nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_STATE))
+ mmp_state = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_STATE);
+
+ if (mmp_state == MMP_STATE_ACTIVE) {
+ char *hostname = "<unknown>";
+ uint64_t hostid = 0;
+
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
+ hostname = fnvlist_lookup_string(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME);
+
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTID))
+ hostid = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID);
+
+ (void) fprintf(stderr, gettext("cannot import '%s': "
+ "pool is imported on %s (hostid: "
+ "0x%lx)\nExport the pool on the other system, "
+ "then run 'zpool import'.\n"),
+ name, hostname, (unsigned long) hostid);
+ } else if (mmp_state == MMP_STATE_NO_HOSTID) {
+ (void) fprintf(stderr, gettext("Cannot import '%s': "
+ "pool has the multihost property on and the\n"
+ "system's hostid is not set.\n"), name);
+ } else {
+ char *hostname = "<unknown>";
+ uint64_t timestamp = 0;
+ uint64_t hostid = 0;
+
+ if (nvlist_exists(config, ZPOOL_CONFIG_HOSTNAME))
+ hostname = fnvlist_lookup_string(config,
+ ZPOOL_CONFIG_HOSTNAME);
+
+ if (nvlist_exists(config, ZPOOL_CONFIG_TIMESTAMP))
+ timestamp = fnvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_TIMESTAMP);
+
+ if (nvlist_exists(config, ZPOOL_CONFIG_HOSTID))
+ hostid = fnvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_HOSTID);
+
+ (void) fprintf(stderr, gettext("cannot import '%s': "
+ "pool was previously in use from another system.\n"
+ "Last accessed by %s (hostid=%lx) at %s"
+ "The pool can be imported, use 'zpool import -f' "
+ "to import the pool.\n"), name, hostname,
+ (unsigned long)hostid, ctime((time_t *)&timestamp));
+
+ }
+
+ return (1);
+ }
+
+ if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
+ return (1);
+
+ if (newname != NULL)
+ name = (char *)newname;
+
+ if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
+ return (1);
+
+ if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
+ !(flags & ZFS_IMPORT_ONLY) &&
+ zpool_enable_datasets(zhp, mntopts, 0) != 0) {
+ zpool_close(zhp);
+ return (1);
+ }
+
+ zpool_close(zhp);
+ return (0);
+}
+
+/*
+ * zpool checkpoint <pool>
+ * checkpoint --discard <pool>
+ *
+ * -d Discard the checkpoint from a checkpointed
+ * --discard pool.
+ *
+ * Checkpoints the specified pool, by taking a "snapshot" of its
+ * current state. A pool can only have one checkpoint at a time.
+ */
+int
+zpool_do_checkpoint(int argc, char **argv)
+{
+ boolean_t discard;
+ char *pool;
+ zpool_handle_t *zhp;
+ int c, err;
+
+ struct option long_options[] = {
+ {"discard", no_argument, NULL, 'd'},
+ {0, 0, 0, 0}
+ };
+
+ discard = B_FALSE;
+ while ((c = getopt_long(argc, argv, ":d", long_options, NULL)) != -1) {
+ switch (c) {
+ case 'd':
+ discard = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool argument\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ pool = argv[0];
+
+ if ((zhp = zpool_open(g_zfs, pool)) == NULL) {
+ /* As a special case, check for use of '/' in the name */
+ if (strchr(pool, '/') != NULL)
+ (void) fprintf(stderr, gettext("'zpool checkpoint' "
+ "doesn't work on datasets. To save the state "
+ "of a dataset from a specific point in time "
+ "please use 'zfs snapshot'\n"));
+ return (1);
+ }
+
+ if (discard)
+ err = (zpool_discard_checkpoint(zhp) != 0);
+ else
+ err = (zpool_checkpoint(zhp) != 0);
+
+ zpool_close(zhp);
+
+ return (err);
+}
+
+#define CHECKPOINT_OPT 1024
+
+/*
+ * zpool import [-d dir] [-D]
+ * import [-o mntopts] [-o prop=value] ... [-R root] [-D]
+ * [-d dir | -c cachefile] [-f] -a
+ * import [-o mntopts] [-o prop=value] ... [-R root] [-D]
+ * [-d dir | -c cachefile] [-f] [-n] [-F] [-t]
+ * <pool | id> [newpool]
+ *
+ * -c Read pool information from a cachefile instead of searching
+ * devices.
+ *
+ * -d Scan in a specific directory, other than /dev/dsk. More than
+ * one directory can be specified using multiple '-d' options.
+ *
+ * -D Scan for previously destroyed pools or import all or only
+ * specified destroyed pools.
+ *
+ * -R Temporarily import the pool, with all mountpoints relative to
+ * the given root. The pool will remain exported when the machine
+ * is rebooted.
+ *
+ * -V Import even in the presence of faulted vdevs. This is an
+ * intentionally undocumented option for testing purposes, and
+ * treats the pool configuration as complete, leaving any bad
+ * vdevs in the FAULTED state. In other words, it does verbatim
+ * import.
+ *
+ * -f Force import, even if it appears that the pool is active.
+ *
+ * -F Attempt rewind if necessary.
+ *
+ * -n See if rewind would work, but don't actually rewind.
+ *
+ * -N Import the pool but don't mount datasets.
+ *
+ * -t Use newpool as a temporary pool name instead of renaming
+ * the pool.
+ *
+ * -T Specify a starting txg to use for import. This option is
+ * intentionally undocumented option for testing purposes.
+ *
+ * -a Import all pools found.
+ *
+ * -o Set property=value and/or temporary mount options (without '=').
+ *
+ * --rewind-to-checkpoint
+ * Import the pool and revert back to the checkpoint.
+ *
+ * The import command scans for pools to import, and import pools based on pool
+ * name and GUID. The pool can also be renamed as part of the import process.
+ */
+int
+zpool_do_import(int argc, char **argv)
+{
+ char **searchdirs = NULL;
+ int nsearch = 0;
+ int c;
+ int err = 0;
+ nvlist_t *pools = NULL;
+ boolean_t do_all = B_FALSE;
+ boolean_t do_destroyed = B_FALSE;
+ char *mntopts = NULL;
+ nvpair_t *elem;
+ nvlist_t *config;
+ uint64_t searchguid = 0;
+ char *searchname = NULL;
+ char *propval;
+ nvlist_t *found_config;
+ nvlist_t *policy = NULL;
+ nvlist_t *props = NULL;
+ boolean_t first;
+ int flags = ZFS_IMPORT_NORMAL;
+ uint32_t rewind_policy = ZPOOL_NO_REWIND;
+ boolean_t dryrun = B_FALSE;
+ boolean_t do_rewind = B_FALSE;
+ boolean_t xtreme_rewind = B_FALSE;
+ uint64_t pool_state, txg = -1ULL;
+ char *cachefile = NULL;
+ importargs_t idata = { 0 };
+ char *endptr;
+
+
+ struct option long_options[] = {
+ {"rewind-to-checkpoint", no_argument, NULL, CHECKPOINT_OPT},
+ {0, 0, 0, 0}
+ };
+
+ /* check options */
+ while ((c = getopt_long(argc, argv, ":aCc:d:DEfFmnNo:rR:tT:VX",
+ long_options, NULL)) != -1) {
+ switch (c) {
+ case 'a':
+ do_all = B_TRUE;
+ break;
+ case 'c':
+ cachefile = optarg;
+ break;
+ case 'd':
+ if (searchdirs == NULL) {
+ searchdirs = safe_malloc(sizeof (char *));
+ } else {
+ char **tmp = safe_malloc((nsearch + 1) *
+ sizeof (char *));
+ bcopy(searchdirs, tmp, nsearch *
+ sizeof (char *));
+ free(searchdirs);
+ searchdirs = tmp;
+ }
+ searchdirs[nsearch++] = optarg;
+ break;
+ case 'D':
+ do_destroyed = B_TRUE;
+ break;
+ case 'f':
+ flags |= ZFS_IMPORT_ANY_HOST;
+ break;
+ case 'F':
+ do_rewind = B_TRUE;
+ break;
+ case 'm':
+ flags |= ZFS_IMPORT_MISSING_LOG;
+ break;
+ case 'n':
+ dryrun = B_TRUE;
+ break;
+ case 'N':
+ flags |= ZFS_IMPORT_ONLY;
+ break;
+ case 'o':
+ if ((propval = strchr(optarg, '=')) != NULL) {
+ *propval = '\0';
+ propval++;
+ if (add_prop_list(optarg, propval,
+ &props, B_TRUE))
+ goto error;
+ } else {
+ mntopts = optarg;
+ }
+ break;
+ case 'R':
+ if (add_prop_list(zpool_prop_to_name(
+ ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
+ goto error;
+ if (add_prop_list_default(zpool_prop_to_name(
+ ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+ goto error;
+ break;
+ case 't':
+ flags |= ZFS_IMPORT_TEMP_NAME;
+ if (add_prop_list_default(zpool_prop_to_name(
+ ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+ goto error;
+ break;
+ case 'T':
+ errno = 0;
+ txg = strtoull(optarg, &endptr, 0);
+ if (errno != 0 || *endptr != '\0') {
+ (void) fprintf(stderr,
+ gettext("invalid txg value\n"));
+ usage(B_FALSE);
+ }
+ rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
+ break;
+ case 'V':
+ flags |= ZFS_IMPORT_VERBATIM;
+ break;
+ case 'X':
+ xtreme_rewind = B_TRUE;
+ break;
+ case CHECKPOINT_OPT:
+ flags |= ZFS_IMPORT_CHECKPOINT;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (cachefile && nsearch != 0) {
+ (void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
+ usage(B_FALSE);
+ }
+
+ if ((dryrun || xtreme_rewind) && !do_rewind) {
+ (void) fprintf(stderr,
+ gettext("-n or -X only meaningful with -F\n"));
+ usage(B_FALSE);
+ }
+ if (dryrun)
+ rewind_policy = ZPOOL_TRY_REWIND;
+ else if (do_rewind)
+ rewind_policy = ZPOOL_DO_REWIND;
+ if (xtreme_rewind)
+ rewind_policy |= ZPOOL_EXTREME_REWIND;
+
+ /* In the future, we can capture further policy and include it here */
+ if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
+ nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, txg) != 0 ||
+ nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY,
+ rewind_policy) != 0)
+ goto error;
+
+ if (searchdirs == NULL) {
+ searchdirs = safe_malloc(sizeof (char *));
+ searchdirs[0] = "/dev";
+ nsearch = 1;
+ }
+
+ /* check argument count */
+ if (do_all) {
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+ } else {
+ if (argc > 2) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ /*
+ * Check for the SYS_CONFIG privilege. We do this explicitly
+ * here because otherwise any attempt to discover pools will
+ * silently fail.
+ */
+ if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
+ (void) fprintf(stderr, gettext("cannot "
+ "discover pools: permission denied\n"));
+ free(searchdirs);
+ nvlist_free(policy);
+ return (1);
+ }
+ }
+
+ /*
+ * Depending on the arguments given, we do one of the following:
+ *
+ * <none> Iterate through all pools and display information about
+ * each one.
+ *
+ * -a Iterate through all pools and try to import each one.
+ *
+ * <id> Find the pool that corresponds to the given GUID/pool
+ * name and import that one.
+ *
+ * -D Above options applies only to destroyed pools.
+ */
+ if (argc != 0) {
+ char *endptr;
+
+ errno = 0;
+ searchguid = strtoull(argv[0], &endptr, 10);
+ if (errno != 0 || *endptr != '\0') {
+ searchname = argv[0];
+ searchguid = 0;
+ }
+ found_config = NULL;
+
+ /*
+ * User specified a name or guid. Ensure it's unique.
+ */
+ idata.unique = B_TRUE;
+ }
+
+
+ idata.path = searchdirs;
+ idata.paths = nsearch;
+ idata.poolname = searchname;
+ idata.guid = searchguid;
+ idata.cachefile = cachefile;
+ idata.policy = policy;
+
+ pools = zpool_search_import(g_zfs, &idata);
+
+ if (pools != NULL && idata.exists &&
+ (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
+ (void) fprintf(stderr, gettext("cannot import '%s': "
+ "a pool with that name already exists\n"),
+ argv[0]);
+ (void) fprintf(stderr, gettext("use the form 'zpool import "
+ "[-t] <pool | id> <newpool>' to give it a new temporary "
+ "or permanent name\n"));
+ err = 1;
+ } else if (pools == NULL && idata.exists) {
+ (void) fprintf(stderr, gettext("cannot import '%s': "
+ "a pool with that name is already created/imported,\n"),
+ argv[0]);
+ (void) fprintf(stderr, gettext("and no additional pools "
+ "with that name were found\n"));
+ err = 1;
+ } else if (pools == NULL) {
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("cannot import '%s': "
+ "no such pool available\n"), argv[0]);
+ }
+ err = 1;
+ }
+
+ if (err == 1) {
+ free(searchdirs);
+ nvlist_free(policy);
+ return (1);
+ }
+
+ /*
+ * At this point we have a list of import candidate configs. Even if
+ * we were searching by pool name or guid, we still need to
+ * post-process the list to deal with pool state and possible
+ * duplicate names.
+ */
+ err = 0;
+ elem = NULL;
+ first = B_TRUE;
+ while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
+
+ verify(nvpair_value_nvlist(elem, &config) == 0);
+
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+ &pool_state) == 0);
+ if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
+ continue;
+ if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
+ continue;
+
+ verify(nvlist_add_nvlist(config, ZPOOL_LOAD_POLICY,
+ policy) == 0);
+
+ if (argc == 0) {
+ if (first)
+ first = B_FALSE;
+ else if (!do_all)
+ (void) printf("\n");
+
+ if (do_all) {
+ err |= do_import(config, NULL, mntopts,
+ props, flags);
+ } else {
+ show_import(config);
+ }
+ } else if (searchname != NULL) {
+ char *name;
+
+ /*
+ * We are searching for a pool based on name.
+ */
+ verify(nvlist_lookup_string(config,
+ ZPOOL_CONFIG_POOL_NAME, &name) == 0);
+
+ if (strcmp(name, searchname) == 0) {
+ if (found_config != NULL) {
+ (void) fprintf(stderr, gettext(
+ "cannot import '%s': more than "
+ "one matching pool\n"), searchname);
+ (void) fprintf(stderr, gettext(
+ "import by numeric ID instead\n"));
+ err = B_TRUE;
+ }
+ found_config = config;
+ }
+ } else {
+ uint64_t guid;
+
+ /*
+ * Search for a pool by guid.
+ */
+ verify(nvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
+
+ if (guid == searchguid)
+ found_config = config;
+ }
+ }
+
+ /*
+ * If we were searching for a specific pool, verify that we found a
+ * pool, and then do the import.
+ */
+ if (argc != 0 && err == 0) {
+ if (found_config == NULL) {
+ (void) fprintf(stderr, gettext("cannot import '%s': "
+ "no such pool available\n"), argv[0]);
+ err = B_TRUE;
+ } else {
+ err |= do_import(found_config, argc == 1 ? NULL :
+ argv[1], mntopts, props, flags);
+ }
+ }
+
+ /*
+ * If we were just looking for pools, report an error if none were
+ * found.
+ */
+ if (argc == 0 && first)
+ (void) fprintf(stderr,
+ gettext("no pools available to import\n"));
+
+error:
+ nvlist_free(props);
+ nvlist_free(pools);
+ nvlist_free(policy);
+ free(searchdirs);
+
+ return (err ? 1 : 0);
+}
+
+/*
+ * zpool sync [-f] [pool] ...
+ *
+ * -f (undocumented) force uberblock (and config including zpool cache file)
+ * update.
+ *
+ * Sync the specified pool(s).
+ * Without arguments "zpool sync" will sync all pools.
+ * This command initiates TXG sync(s) and will return after the TXG(s) commit.
+ *
+ */
+static int
+zpool_do_sync(int argc, char **argv)
+{
+ int ret;
+ boolean_t force = B_FALSE;
+
+ /* check options */
+ while ((ret = getopt(argc, argv, "f")) != -1) {
+ switch (ret) {
+ case 'f':
+ force = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* if argc == 0 we will execute zpool_sync_one on all pools */
+ ret = for_each_pool(argc, argv, B_FALSE, NULL, zpool_sync_one, &force);
+
+ return (ret);
+}
+
+typedef struct iostat_cbdata {
+ boolean_t cb_verbose;
+ int cb_name_flags;
+ int cb_namewidth;
+ int cb_iteration;
+ boolean_t cb_scripted;
+ zpool_list_t *cb_list;
+} iostat_cbdata_t;
+
+static void
+print_iostat_separator(iostat_cbdata_t *cb)
+{
+ int i = 0;
+
+ for (i = 0; i < cb->cb_namewidth; i++)
+ (void) printf("-");
+ (void) printf(" ----- ----- ----- ----- ----- -----\n");
+}
+
+static void
+print_iostat_header(iostat_cbdata_t *cb)
+{
+ (void) printf("%*s capacity operations bandwidth\n",
+ cb->cb_namewidth, "");
+ (void) printf("%-*s alloc free read write read write\n",
+ cb->cb_namewidth, "pool");
+ print_iostat_separator(cb);
+}
+
+/*
+ * Display a single statistic.
+ */
+static void
+print_one_stat(uint64_t value)
+{
+ char buf[64];
+
+ zfs_nicenum(value, buf, sizeof (buf));
+ (void) printf(" %5s", buf);
+}
+
+static const char *class_name[] = {
+ VDEV_ALLOC_BIAS_DEDUP,
+ VDEV_ALLOC_BIAS_SPECIAL,
+ VDEV_ALLOC_CLASS_LOGS
+};
+
+/*
+ * Print out all the statistics for the given vdev. This can either be the
+ * toplevel configuration, or called recursively. If 'name' is NULL, then this
+ * is a verbose output, and we don't want to display the toplevel pool stats.
+ *
+ * Returns the number of stat lines printed.
+ */
+static unsigned int
+print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
+ nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
+{
+ nvlist_t **oldchild, **newchild;
+ uint_t c, children;
+ vdev_stat_t *oldvs, *newvs;
+ vdev_stat_t zerovs = { 0 };
+ char *vname;
+ int ret = 0;
+ uint64_t tdelta;
+ double scale;
+
+ if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
+ return (ret);
+
+ if (oldnv != NULL) {
+ verify(nvlist_lookup_uint64_array(oldnv,
+ ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
+ } else {
+ oldvs = &zerovs;
+ }
+
+ verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&newvs, &c) == 0);
+
+ if (strlen(name) + depth > cb->cb_namewidth)
+ (void) printf("%*s%s", depth, "", name);
+ else
+ (void) printf("%*s%s%*s", depth, "", name,
+ (int)(cb->cb_namewidth - strlen(name) - depth), "");
+
+ tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
+
+ if (tdelta == 0)
+ scale = 1.0;
+ else
+ scale = (double)NANOSEC / tdelta;
+
+ /* only toplevel vdevs have capacity stats */
+ if (newvs->vs_space == 0) {
+ (void) printf(" - -");
+ } else {
+ print_one_stat(newvs->vs_alloc);
+ print_one_stat(newvs->vs_space - newvs->vs_alloc);
+ }
+
+ print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
+ oldvs->vs_ops[ZIO_TYPE_READ])));
+
+ print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
+ oldvs->vs_ops[ZIO_TYPE_WRITE])));
+
+ print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
+ oldvs->vs_bytes[ZIO_TYPE_READ])));
+
+ print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
+ oldvs->vs_bytes[ZIO_TYPE_WRITE])));
+
+ (void) printf("\n");
+
+ if (!cb->cb_verbose)
+ return (ret);
+
+ if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
+ &newchild, &children) != 0)
+ return (ret);
+
+ if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
+ &oldchild, &c) != 0)
+ return (ret);
+
+ /*
+ * print normal top-level devices
+ */
+ for (c = 0; c < children; c++) {
+ uint64_t ishole = B_FALSE, islog = B_FALSE;
+
+ (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
+ &ishole);
+
+ (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
+ &islog);
+
+ if (ishole || islog)
+ continue;
+
+ if (nvlist_exists(newchild[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+ cb->cb_name_flags);
+ print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
+ newchild[c], cb, depth + 2);
+ free(vname);
+ }
+
+ /*
+ * print all other top-level devices
+ */
+ for (uint_t n = 0; n < 3; n++) {
+ for (c = 0; c < children; c++) {
+ uint64_t islog = B_FALSE;
+ char *bias = NULL;
+ char *type = NULL;
+
+ (void) nvlist_lookup_uint64(newchild[c],
+ ZPOOL_CONFIG_IS_LOG, &islog);
+ if (islog) {
+ bias = VDEV_ALLOC_CLASS_LOGS;
+ } else {
+ (void) nvlist_lookup_string(newchild[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
+ (void) nvlist_lookup_string(newchild[c],
+ ZPOOL_CONFIG_TYPE, &type);
+ }
+ if (bias == NULL || strcmp(bias, class_name[n]) != 0)
+ continue;
+ if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+ cb->cb_name_flags);
+ ret += print_vdev_stats(zhp, vname, oldnv ?
+ oldchild[c] : NULL, newchild[c], cb, depth + 2);
+ free(vname);
+ }
+
+ }
+
+ /*
+ * Include level 2 ARC devices in iostat output
+ */
+ if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
+ &newchild, &children) != 0)
+ return (ret);
+
+ if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
+ &oldchild, &c) != 0)
+ return (ret);
+
+ if (children > 0) {
+ (void) printf("%-*s - - - - - "
+ "-\n", cb->cb_namewidth, "cache");
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+ cb->cb_name_flags);
+ print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
+ newchild[c], cb, depth + 2);
+ free(vname);
+ }
+ }
+
+ return (ret);
+}
+
+static int
+refresh_iostat(zpool_handle_t *zhp, void *data)
+{
+ iostat_cbdata_t *cb = data;
+ boolean_t missing;
+
+ /*
+ * If the pool has disappeared, remove it from the list and continue.
+ */
+ if (zpool_refresh_stats(zhp, &missing) != 0)
+ return (-1);
+
+ if (missing)
+ pool_list_remove(cb->cb_list, zhp);
+
+ return (0);
+}
+
+/*
+ * Callback to print out the iostats for the given pool.
+ */
+int
+print_iostat(zpool_handle_t *zhp, void *data)
+{
+ iostat_cbdata_t *cb = data;
+ nvlist_t *oldconfig, *newconfig;
+ nvlist_t *oldnvroot, *newnvroot;
+
+ newconfig = zpool_get_config(zhp, &oldconfig);
+
+ if (cb->cb_iteration == 1)
+ oldconfig = NULL;
+
+ verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
+ &newnvroot) == 0);
+
+ if (oldconfig == NULL)
+ oldnvroot = NULL;
+ else
+ verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
+ &oldnvroot) == 0);
+
+ /*
+ * Print out the statistics for the pool.
+ */
+ print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
+
+ if (cb->cb_verbose)
+ print_iostat_separator(cb);
+
+ return (0);
+}
+
+int
+get_namewidth(zpool_handle_t *zhp, void *data)
+{
+ iostat_cbdata_t *cb = data;
+ nvlist_t *config, *nvroot;
+
+ if ((config = zpool_get_config(zhp, NULL)) != NULL) {
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ if (!cb->cb_verbose)
+ cb->cb_namewidth = strlen(zpool_get_name(zhp));
+ else
+ cb->cb_namewidth = max_width(zhp, nvroot, 0,
+ cb->cb_namewidth, cb->cb_name_flags);
+ }
+
+ /*
+ * The width must fall into the range [10,38]. The upper limit is the
+ * maximum we can have and still fit in 80 columns.
+ */
+ if (cb->cb_namewidth < 10)
+ cb->cb_namewidth = 10;
+ if (cb->cb_namewidth > 38)
+ cb->cb_namewidth = 38;
+
+ return (0);
+}
+
+/*
+ * Parse the input string, get the 'interval' and 'count' value if there is one.
+ */
+static void
+get_interval_count(int *argcp, char **argv, unsigned long *iv,
+ unsigned long *cnt)
+{
+ unsigned long interval = 0, count = 0;
+ int argc = *argcp, errno;
+
+ /*
+ * Determine if the last argument is an integer or a pool name
+ */
+ if (argc > 0 && isdigit(argv[argc - 1][0])) {
+ char *end;
+
+ errno = 0;
+ interval = strtoul(argv[argc - 1], &end, 10);
+
+ if (*end == '\0' && errno == 0) {
+ if (interval == 0) {
+ (void) fprintf(stderr, gettext("interval "
+ "cannot be zero\n"));
+ usage(B_FALSE);
+ }
+ /*
+ * Ignore the last parameter
+ */
+ argc--;
+ } else {
+ /*
+ * If this is not a valid number, just plow on. The
+ * user will get a more informative error message later
+ * on.
+ */
+ interval = 0;
+ }
+ }
+
+ /*
+ * If the last argument is also an integer, then we have both a count
+ * and an interval.
+ */
+ if (argc > 0 && isdigit(argv[argc - 1][0])) {
+ char *end;
+
+ errno = 0;
+ count = interval;
+ interval = strtoul(argv[argc - 1], &end, 10);
+
+ if (*end == '\0' && errno == 0) {
+ if (interval == 0) {
+ (void) fprintf(stderr, gettext("interval "
+ "cannot be zero\n"));
+ usage(B_FALSE);
+ }
+
+ /*
+ * Ignore the last parameter
+ */
+ argc--;
+ } else {
+ interval = 0;
+ }
+ }
+
+ *iv = interval;
+ *cnt = count;
+ *argcp = argc;
+}
+
+static void
+get_timestamp_arg(char c)
+{
+ if (c == 'u')
+ timestamp_fmt = UDATE;
+ else if (c == 'd')
+ timestamp_fmt = DDATE;
+ else
+ usage(B_FALSE);
+}
+
+/*
+ * zpool iostat [-gLPv] [-T d|u] [pool] ... [interval [count]]
+ *
+ * -g Display guid for individual vdev name.
+ * -L Follow links when resolving vdev path name.
+ * -P Display full path for vdev name.
+ * -v Display statistics for individual vdevs
+ * -T Display a timestamp in date(1) or Unix format
+ *
+ * This command can be tricky because we want to be able to deal with pool
+ * creation/destruction as well as vdev configuration changes. The bulk of this
+ * processing is handled by the pool_list_* routines in zpool_iter.c. We rely
+ * on pool_list_update() to detect the addition of new pools. Configuration
+ * changes are all handled within libzfs.
+ */
+int
+zpool_do_iostat(int argc, char **argv)
+{
+ int c;
+ int ret;
+ int npools;
+ unsigned long interval = 0, count = 0;
+ zpool_list_t *list;
+ boolean_t verbose = B_FALSE;
+ boolean_t guid = B_FALSE;
+ boolean_t follow_links = B_FALSE;
+ boolean_t full_name = B_FALSE;
+ iostat_cbdata_t cb = { 0 };
+
+ /* check options */
+ while ((c = getopt(argc, argv, "gLPT:v")) != -1) {
+ switch (c) {
+ case 'g':
+ guid = B_TRUE;
+ break;
+ case 'L':
+ follow_links = B_TRUE;
+ break;
+ case 'P':
+ full_name = B_TRUE;
+ break;
+ case 'T':
+ get_timestamp_arg(*optarg);
+ break;
+ case 'v':
+ verbose = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ get_interval_count(&argc, argv, &interval, &count);
+
+ /*
+ * Construct the list of all interesting pools.
+ */
+ ret = 0;
+ if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
+ return (1);
+
+ if (pool_list_count(list) == 0 && argc != 0) {
+ pool_list_free(list);
+ return (1);
+ }
+
+ if (pool_list_count(list) == 0 && interval == 0) {
+ pool_list_free(list);
+ (void) fprintf(stderr, gettext("no pools available\n"));
+ return (1);
+ }
+
+ /*
+ * Enter the main iostat loop.
+ */
+ cb.cb_list = list;
+ cb.cb_verbose = verbose;
+ if (guid)
+ cb.cb_name_flags |= VDEV_NAME_GUID;
+ if (follow_links)
+ cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ if (full_name)
+ cb.cb_name_flags |= VDEV_NAME_PATH;
+ cb.cb_iteration = 0;
+ cb.cb_namewidth = 0;
+
+ for (;;) {
+ pool_list_update(list);
+
+ if ((npools = pool_list_count(list)) == 0)
+ break;
+
+ /*
+ * Refresh all statistics. This is done as an explicit step
+ * before calculating the maximum name width, so that any
+ * configuration changes are properly accounted for.
+ */
+ (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
+
+ /*
+ * Iterate over all pools to determine the maximum width
+ * for the pool / device name column across all pools.
+ */
+ cb.cb_namewidth = 0;
+ (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
+
+ if (timestamp_fmt != NODATE)
+ print_timestamp(timestamp_fmt);
+
+ /*
+ * If it's the first time, or verbose mode, print the header.
+ */
+ if (++cb.cb_iteration == 1 || verbose)
+ print_iostat_header(&cb);
+
+ (void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
+
+ /*
+ * If there's more than one pool, and we're not in verbose mode
+ * (which prints a separator for us), then print a separator.
+ */
+ if (npools > 1 && !verbose)
+ print_iostat_separator(&cb);
+
+ if (verbose)
+ (void) printf("\n");
+
+ /*
+ * Flush the output so that redirection to a file isn't buffered
+ * indefinitely.
+ */
+ (void) fflush(stdout);
+
+ if (interval == 0)
+ break;
+
+ if (count != 0 && --count == 0)
+ break;
+
+ (void) sleep(interval);
+ }
+
+ pool_list_free(list);
+
+ return (ret);
+}
+
+typedef struct list_cbdata {
+ boolean_t cb_verbose;
+ int cb_name_flags;
+ int cb_namewidth;
+ boolean_t cb_scripted;
+ zprop_list_t *cb_proplist;
+ boolean_t cb_literal;
+} list_cbdata_t;
+
+
+/*
+ * Given a list of columns to display, output appropriate headers for each one.
+ */
+static void
+print_header(list_cbdata_t *cb)
+{
+ zprop_list_t *pl = cb->cb_proplist;
+ char headerbuf[ZPOOL_MAXPROPLEN];
+ const char *header;
+ boolean_t first = B_TRUE;
+ boolean_t right_justify;
+ size_t width = 0;
+
+ for (; pl != NULL; pl = pl->pl_next) {
+ width = pl->pl_width;
+ if (first && cb->cb_verbose) {
+ /*
+ * Reset the width to accommodate the verbose listing
+ * of devices.
+ */
+ width = cb->cb_namewidth;
+ }
+
+ if (!first)
+ (void) printf(" ");
+ else
+ first = B_FALSE;
+
+ right_justify = B_FALSE;
+ if (pl->pl_prop != ZPROP_INVAL) {
+ header = zpool_prop_column_name(pl->pl_prop);
+ right_justify = zpool_prop_align_right(pl->pl_prop);
+ } else {
+ int i;
+
+ for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
+ headerbuf[i] = toupper(pl->pl_user_prop[i]);
+ headerbuf[i] = '\0';
+ header = headerbuf;
+ }
+
+ if (pl->pl_next == NULL && !right_justify)
+ (void) printf("%s", header);
+ else if (right_justify)
+ (void) printf("%*s", width, header);
+ else
+ (void) printf("%-*s", width, header);
+
+ }
+
+ (void) printf("\n");
+}
+
+/*
+ * Given a pool and a list of properties, print out all the properties according
+ * to the described layout. Used by zpool_do_list().
+ */
+static void
+print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
+{
+ zprop_list_t *pl = cb->cb_proplist;
+ boolean_t first = B_TRUE;
+ char property[ZPOOL_MAXPROPLEN];
+ char *propstr;
+ boolean_t right_justify;
+ size_t width;
+
+ for (; pl != NULL; pl = pl->pl_next) {
+
+ width = pl->pl_width;
+ if (first && cb->cb_verbose) {
+ /*
+ * Reset the width to accommodate the verbose listing
+ * of devices.
+ */
+ width = cb->cb_namewidth;
+ }
+
+ if (!first) {
+ if (cb->cb_scripted)
+ (void) printf("\t");
+ else
+ (void) printf(" ");
+ } else {
+ first = B_FALSE;
+ }
+
+ right_justify = B_FALSE;
+ if (pl->pl_prop != ZPROP_INVAL) {
+ if (zpool_get_prop(zhp, pl->pl_prop, property,
+ sizeof (property), NULL, cb->cb_literal) != 0)
+ propstr = "-";
+ else
+ propstr = property;
+
+ right_justify = zpool_prop_align_right(pl->pl_prop);
+ } else if ((zpool_prop_feature(pl->pl_user_prop) ||
+ zpool_prop_unsupported(pl->pl_user_prop)) &&
+ zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
+ sizeof (property)) == 0) {
+ propstr = property;
+ } else {
+ propstr = "-";
+ }
+
+
+ /*
+ * If this is being called in scripted mode, or if this is the
+ * last column and it is left-justified, don't include a width
+ * format specifier.
+ */
+ if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
+ (void) printf("%s", propstr);
+ else if (right_justify)
+ (void) printf("%*s", width, propstr);
+ else
+ (void) printf("%-*s", width, propstr);
+ }
+
+ (void) printf("\n");
+}
+
+static void
+print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
+ boolean_t valid)
+{
+ char propval[64];
+ boolean_t fixed;
+ size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
+
+ switch (prop) {
+ case ZPOOL_PROP_EXPANDSZ:
+ case ZPOOL_PROP_CHECKPOINT:
+ if (value == 0)
+ (void) strlcpy(propval, "-", sizeof (propval));
+ else
+ zfs_nicenum(value, propval, sizeof (propval));
+ break;
+ case ZPOOL_PROP_FRAGMENTATION:
+ if (value == ZFS_FRAG_INVALID) {
+ (void) strlcpy(propval, "-", sizeof (propval));
+ } else {
+ (void) snprintf(propval, sizeof (propval), "%llu%%",
+ value);
+ }
+ break;
+ case ZPOOL_PROP_CAPACITY:
+ (void) snprintf(propval, sizeof (propval),
+ value < 1000 ? "%1.2f%%" : value < 10000 ?
+ "%2.1f%%" : "%3.0f%%", value / 100.0);
+ break;
+ default:
+ zfs_nicenum(value, propval, sizeof (propval));
+ }
+
+ if (!valid)
+ (void) strlcpy(propval, "-", sizeof (propval));
+
+ if (scripted)
+ (void) printf("\t%s", propval);
+ else
+ (void) printf(" %*s", width, propval);
+}
+
+/*
+ * print static default line per vdev
+ */
+void
+print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
+ list_cbdata_t *cb, int depth)
+{
+ nvlist_t **child;
+ vdev_stat_t *vs;
+ uint_t c, children;
+ char *vname;
+ boolean_t scripted = cb->cb_scripted;
+ uint64_t islog = B_FALSE;
+ char *dashes = "%-*s - - - - - -\n";
+
+ verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &c) == 0);
+
+ if (name != NULL) {
+ boolean_t toplevel = (vs->vs_space != 0);
+ uint64_t cap;
+
+ if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
+ return;
+
+ if (scripted)
+ (void) printf("\t%s", name);
+ else if (strlen(name) + depth > cb->cb_namewidth)
+ (void) printf("%*s%s", depth, "", name);
+ else
+ (void) printf("%*s%s%*s", depth, "", name,
+ (int)(cb->cb_namewidth - strlen(name) - depth), "");
+
+ /*
+ * Print the properties for the individual vdevs. Some
+ * properties are only applicable to toplevel vdevs. The
+ * 'toplevel' boolean value is passed to the print_one_column()
+ * to indicate that the value is valid.
+ */
+ print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted,
+ toplevel);
+ print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted,
+ toplevel);
+ print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
+ scripted, toplevel);
+ print_one_column(ZPOOL_PROP_CHECKPOINT,
+ vs->vs_checkpoint_space, scripted, toplevel);
+ print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted,
+ B_TRUE);
+ print_one_column(ZPOOL_PROP_FRAGMENTATION,
+ vs->vs_fragmentation, scripted,
+ (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel));
+ cap = (vs->vs_space == 0) ? 0 :
+ (vs->vs_alloc * 10000 / vs->vs_space);
+ print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel);
+ (void) printf("\n");
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0)
+ return;
+
+ /* list the normal vdevs first */
+ for (c = 0; c < children; c++) {
+ uint64_t ishole = B_FALSE;
+
+ if (nvlist_lookup_uint64(child[c],
+ ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
+ continue;
+
+ if (nvlist_lookup_uint64(child[c],
+ ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog)
+ continue;
+
+ if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags);
+ print_list_stats(zhp, vname, child[c], cb, depth + 2);
+ free(vname);
+ }
+
+ /* list the classes: 'logs', 'dedup', and 'special' */
+ for (uint_t n = 0; n < 3; n++) {
+ boolean_t printed = B_FALSE;
+
+ for (c = 0; c < children; c++) {
+ char *bias = NULL;
+ char *type = NULL;
+
+ if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &islog) == 0 && islog) {
+ bias = VDEV_ALLOC_CLASS_LOGS;
+ } else {
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_TYPE, &type);
+ }
+ if (bias == NULL || strcmp(bias, class_name[n]) != 0)
+ continue;
+ if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
+ continue;
+
+ if (!printed) {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) printf(dashes, cb->cb_namewidth,
+ class_name[n]);
+ printed = B_TRUE;
+ }
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags);
+ print_list_stats(zhp, vname, child[c], cb, depth + 2);
+ free(vname);
+ }
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+ &child, &children) == 0 && children > 0) {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) printf(dashes, cb->cb_namewidth, "cache");
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags);
+ print_list_stats(zhp, vname, child[c], cb, depth + 2);
+ free(vname);
+ }
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
+ &children) == 0 && children > 0) {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) printf(dashes, cb->cb_namewidth, "spare");
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags);
+ print_list_stats(zhp, vname, child[c], cb, depth + 2);
+ free(vname);
+ }
+ }
+}
+
+/*
+ * Generic callback function to list a pool.
+ */
+int
+list_callback(zpool_handle_t *zhp, void *data)
+{
+ list_cbdata_t *cbp = data;
+ nvlist_t *config;
+ nvlist_t *nvroot;
+
+ config = zpool_get_config(zhp, NULL);
+
+ if (cbp->cb_verbose) {
+ config = zpool_get_config(zhp, NULL);
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ }
+
+ if (cbp->cb_verbose)
+ cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
+ cbp->cb_name_flags);
+
+ print_pool(zhp, cbp);
+
+ if (cbp->cb_verbose)
+ print_list_stats(zhp, NULL, nvroot, cbp, 0);
+
+ return (0);
+}
+
+/*
+ * zpool list [-gHLP] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
+ *
+ * -g Display guid for individual vdev name.
+ * -H Scripted mode. Don't display headers, and separate properties
+ * by a single tab.
+ * -L Follow links when resolving vdev path name.
+ * -o List of properties to display. Defaults to
+ * "name,size,allocated,free,expandsize,fragmentation,capacity,"
+ * "dedupratio,health,altroot"
+ * -p Diplay values in parsable (exact) format.
+ * -P Display full path for vdev name.
+ * -T Display a timestamp in date(1) or Unix format
+ *
+ * List all pools in the system, whether or not they're healthy. Output space
+ * statistics for each one, as well as health status summary.
+ */
+int
+zpool_do_list(int argc, char **argv)
+{
+ int c;
+ int ret;
+ list_cbdata_t cb = { 0 };
+ static char default_props[] =
+ "name,size,allocated,free,checkpoint,expandsize,fragmentation,"
+ "capacity,dedupratio,health,altroot";
+ char *props = default_props;
+ unsigned long interval = 0, count = 0;
+ zpool_list_t *list;
+ boolean_t first = B_TRUE;
+
+ /* check options */
+ while ((c = getopt(argc, argv, ":gHLo:pPT:v")) != -1) {
+ switch (c) {
+ case 'g':
+ cb.cb_name_flags |= VDEV_NAME_GUID;
+ break;
+ case 'H':
+ cb.cb_scripted = B_TRUE;
+ break;
+ case 'L':
+ cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ break;
+ case 'o':
+ props = optarg;
+ break;
+ case 'P':
+ cb.cb_name_flags |= VDEV_NAME_PATH;
+ break;
+ case 'p':
+ cb.cb_literal = B_TRUE;
+ break;
+ case 'T':
+ get_timestamp_arg(*optarg);
+ break;
+ case 'v':
+ cb.cb_verbose = B_TRUE;
+ cb.cb_namewidth = 8; /* 8 until precalc is avail */
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ get_interval_count(&argc, argv, &interval, &count);
+
+ if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
+ usage(B_FALSE);
+
+ for (;;) {
+ if ((list = pool_list_get(argc, argv, &cb.cb_proplist,
+ &ret)) == NULL)
+ return (1);
+
+ if (pool_list_count(list) == 0)
+ break;
+
+ cb.cb_namewidth = 0;
+ (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
+
+ if (timestamp_fmt != NODATE)
+ print_timestamp(timestamp_fmt);
+
+ if (!cb.cb_scripted && (first || cb.cb_verbose)) {
+ print_header(&cb);
+ first = B_FALSE;
+ }
+ ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
+
+ if (interval == 0)
+ break;
+
+ if (count != 0 && --count == 0)
+ break;
+
+ pool_list_free(list);
+ (void) sleep(interval);
+ }
+
+ if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
+ (void) printf(gettext("no pools available\n"));
+ ret = 0;
+ }
+
+ pool_list_free(list);
+ zprop_free_list(cb.cb_proplist);
+ return (ret);
+}
+
+static int
+zpool_do_attach_or_replace(int argc, char **argv, int replacing)
+{
+ boolean_t force = B_FALSE;
+ int c;
+ nvlist_t *nvroot;
+ char *poolname, *old_disk, *new_disk;
+ zpool_handle_t *zhp;
+ zpool_boot_label_t boot_type;
+ uint64_t boot_size;
+ int ret;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "f")) != -1) {
+ switch (c) {
+ case 'f':
+ force = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get pool name and check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name argument\n"));
+ usage(B_FALSE);
+ }
+
+ poolname = argv[0];
+
+ if (argc < 2) {
+ (void) fprintf(stderr,
+ gettext("missing <device> specification\n"));
+ usage(B_FALSE);
+ }
+
+ old_disk = argv[1];
+
+ if (argc < 3) {
+ if (!replacing) {
+ (void) fprintf(stderr,
+ gettext("missing <new_device> specification\n"));
+ usage(B_FALSE);
+ }
+ new_disk = old_disk;
+ argc -= 1;
+ argv += 1;
+ } else {
+ new_disk = argv[2];
+ argc -= 2;
+ argv += 2;
+ }
+
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+ return (1);
+
+ if (zpool_get_config(zhp, NULL) == NULL) {
+ (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
+ poolname);
+ zpool_close(zhp);
+ return (1);
+ }
+
+ if (zpool_is_bootable(zhp))
+ boot_type = ZPOOL_COPY_BOOT_LABEL;
+ else
+ boot_type = ZPOOL_NO_BOOT_LABEL;
+
+ boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
+ nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
+ boot_type, boot_size, argc, argv);
+ if (nvroot == NULL) {
+ zpool_close(zhp);
+ return (1);
+ }
+
+ ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
+
+ nvlist_free(nvroot);
+ zpool_close(zhp);
+
+ return (ret);
+}
+
+/*
+ * zpool replace [-f] <pool> <device> <new_device>
+ *
+ * -f Force attach, even if <new_device> appears to be in use.
+ *
+ * Replace <device> with <new_device>.
+ */
+/* ARGSUSED */
+int
+zpool_do_replace(int argc, char **argv)
+{
+ return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
+}
+
+/*
+ * zpool attach [-f] <pool> <device> <new_device>
+ *
+ * -f Force attach, even if <new_device> appears to be in use.
+ *
+ * Attach <new_device> to the mirror containing <device>. If <device> is not
+ * part of a mirror, then <device> will be transformed into a mirror of
+ * <device> and <new_device>. In either case, <new_device> will begin life
+ * with a DTL of [0, now], and will immediately begin to resilver itself.
+ */
+int
+zpool_do_attach(int argc, char **argv)
+{
+ return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
+}
+
+/*
+ * zpool detach [-f] <pool> <device>
+ *
+ * -f Force detach of <device>, even if DTLs argue against it
+ * (not supported yet)
+ *
+ * Detach a device from a mirror. The operation will be refused if <device>
+ * is the last device in the mirror, or if the DTLs indicate that this device
+ * has the only valid copy of some data.
+ */
+/* ARGSUSED */
+int
+zpool_do_detach(int argc, char **argv)
+{
+ int c;
+ char *poolname, *path;
+ zpool_handle_t *zhp;
+ int ret;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "f")) != -1) {
+ switch (c) {
+ case 'f':
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get pool name and check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name argument\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc < 2) {
+ (void) fprintf(stderr,
+ gettext("missing <device> specification\n"));
+ usage(B_FALSE);
+ }
+
+ poolname = argv[0];
+ path = argv[1];
+
+ if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+ return (1);
+
+ ret = zpool_vdev_detach(zhp, path);
+
+ zpool_close(zhp);
+
+ return (ret);
+}
+
+/*
+ * zpool split [-gLnP] [-o prop=val] ...
+ * [-o mntopt] ...
+ * [-R altroot] <pool> <newpool> [<device> ...]
+ *
+ * -g Display guid for individual vdev name.
+ * -L Follow links when resolving vdev path name.
+ * -n Do not split the pool, but display the resulting layout if
+ * it were to be split.
+ * -o Set property=value, or set mount options.
+ * -P Display full path for vdev name.
+ * -R Mount the split-off pool under an alternate root.
+ *
+ * Splits the named pool and gives it the new pool name. Devices to be split
+ * off may be listed, provided that no more than one device is specified
+ * per top-level vdev mirror. The newly split pool is left in an exported
+ * state unless -R is specified.
+ *
+ * Restrictions: the top-level of the pool pool must only be made up of
+ * mirrors; all devices in the pool must be healthy; no device may be
+ * undergoing a resilvering operation.
+ */
+int
+zpool_do_split(int argc, char **argv)
+{
+ char *srcpool, *newpool, *propval;
+ char *mntopts = NULL;
+ splitflags_t flags;
+ int c, ret = 0;
+ zpool_handle_t *zhp;
+ nvlist_t *config, *props = NULL;
+
+ flags.dryrun = B_FALSE;
+ flags.import = B_FALSE;
+ flags.name_flags = 0;
+
+ /* check options */
+ while ((c = getopt(argc, argv, ":gLR:no:P")) != -1) {
+ switch (c) {
+ case 'g':
+ flags.name_flags |= VDEV_NAME_GUID;
+ break;
+ case 'L':
+ flags.name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ break;
+ case 'R':
+ flags.import = B_TRUE;
+ if (add_prop_list(
+ zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
+ &props, B_TRUE) != 0) {
+ nvlist_free(props);
+ usage(B_FALSE);
+ }
+ break;
+ case 'n':
+ flags.dryrun = B_TRUE;
+ break;
+ case 'o':
+ if ((propval = strchr(optarg, '=')) != NULL) {
+ *propval = '\0';
+ propval++;
+ if (add_prop_list(optarg, propval,
+ &props, B_TRUE) != 0) {
+ nvlist_free(props);
+ usage(B_FALSE);
+ }
+ } else {
+ mntopts = optarg;
+ }
+ break;
+ case 'P':
+ flags.name_flags |= VDEV_NAME_PATH;
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ break;
+ }
+ }
+
+ if (!flags.import && mntopts != NULL) {
+ (void) fprintf(stderr, gettext("setting mntopts is only "
+ "valid when importing the pool\n"));
+ usage(B_FALSE);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("Missing pool name\n"));
+ usage(B_FALSE);
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("Missing new pool name\n"));
+ usage(B_FALSE);
+ }
+
+ srcpool = argv[0];
+ newpool = argv[1];
+
+ argc -= 2;
+ argv += 2;
+
+ if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
+ return (1);
+
+ config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
+ if (config == NULL) {
+ ret = 1;
+ } else {
+ if (flags.dryrun) {
+ (void) printf(gettext("would create '%s' with the "
+ "following layout:\n\n"), newpool);
+ print_vdev_tree(NULL, newpool, config, 0, "",
+ flags.name_flags);
+ }
+ nvlist_free(config);
+ }
+
+ zpool_close(zhp);
+
+ if (ret != 0 || flags.dryrun || !flags.import)
+ return (ret);
+
+ /*
+ * The split was successful. Now we need to open the new
+ * pool and import it.
+ */
+ if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
+ return (1);
+ if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
+ zpool_enable_datasets(zhp, mntopts, 0) != 0) {
+ ret = 1;
+ (void) fprintf(stderr, gettext("Split was successful, but "
+ "the datasets could not all be mounted\n"));
+ (void) fprintf(stderr, gettext("Try doing '%s' with a "
+ "different altroot\n"), "zpool import");
+ }
+ zpool_close(zhp);
+
+ return (ret);
+}
+
+
+
+/*
+ * zpool online <pool> <device> ...
+ */
+int
+zpool_do_online(int argc, char **argv)
+{
+ int c, i;
+ char *poolname;
+ zpool_handle_t *zhp;
+ int ret = 0;
+ vdev_state_t newstate;
+ int flags = 0;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "et")) != -1) {
+ switch (c) {
+ case 'e':
+ flags |= ZFS_ONLINE_EXPAND;
+ break;
+ case 't':
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get pool name and check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name\n"));
+ usage(B_FALSE);
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing device name\n"));
+ usage(B_FALSE);
+ }
+
+ poolname = argv[0];
+
+ if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+ return (1);
+
+ for (i = 1; i < argc; i++) {
+ if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
+ if (newstate != VDEV_STATE_HEALTHY) {
+ (void) printf(gettext("warning: device '%s' "
+ "onlined, but remains in faulted state\n"),
+ argv[i]);
+ if (newstate == VDEV_STATE_FAULTED)
+ (void) printf(gettext("use 'zpool "
+ "clear' to restore a faulted "
+ "device\n"));
+ else
+ (void) printf(gettext("use 'zpool "
+ "replace' to replace devices "
+ "that are no longer present\n"));
+ }
+ } else {
+ ret = 1;
+ }
+ }
+
+ zpool_close(zhp);
+
+ return (ret);
+}
+
+/*
+ * zpool offline [-ft] <pool> <device> ...
+ *
+ * -f Force the device into the offline state, even if doing
+ * so would appear to compromise pool availability.
+ * (not supported yet)
+ *
+ * -t Only take the device off-line temporarily. The offline
+ * state will not be persistent across reboots.
+ */
+/* ARGSUSED */
+int
+zpool_do_offline(int argc, char **argv)
+{
+ int c, i;
+ char *poolname;
+ zpool_handle_t *zhp;
+ int ret = 0;
+ boolean_t istmp = B_FALSE;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "ft")) != -1) {
+ switch (c) {
+ case 't':
+ istmp = B_TRUE;
+ break;
+ case 'f':
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get pool name and check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name\n"));
+ usage(B_FALSE);
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing device name\n"));
+ usage(B_FALSE);
+ }
+
+ poolname = argv[0];
+
+ if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+ return (1);
+
+ for (i = 1; i < argc; i++) {
+ if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
+ ret = 1;
+ }
+
+ zpool_close(zhp);
+
+ return (ret);
+}
+
+/*
+ * zpool clear <pool> [device]
+ *
+ * Clear all errors associated with a pool or a particular device.
+ */
+int
+zpool_do_clear(int argc, char **argv)
+{
+ int c;
+ int ret = 0;
+ boolean_t dryrun = B_FALSE;
+ boolean_t do_rewind = B_FALSE;
+ boolean_t xtreme_rewind = B_FALSE;
+ uint32_t rewind_policy = ZPOOL_NO_REWIND;
+ nvlist_t *policy = NULL;
+ zpool_handle_t *zhp;
+ char *pool, *device;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "FnX")) != -1) {
+ switch (c) {
+ case 'F':
+ do_rewind = B_TRUE;
+ break;
+ case 'n':
+ dryrun = B_TRUE;
+ break;
+ case 'X':
+ xtreme_rewind = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc > 2) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ if ((dryrun || xtreme_rewind) && !do_rewind) {
+ (void) fprintf(stderr,
+ gettext("-n or -X only meaningful with -F\n"));
+ usage(B_FALSE);
+ }
+ if (dryrun)
+ rewind_policy = ZPOOL_TRY_REWIND;
+ else if (do_rewind)
+ rewind_policy = ZPOOL_DO_REWIND;
+ if (xtreme_rewind)
+ rewind_policy |= ZPOOL_EXTREME_REWIND;
+
+ /* In future, further rewind policy choices can be passed along here */
+ if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
+ nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY,
+ rewind_policy) != 0) {
+ return (1);
+ }
+
+ pool = argv[0];
+ device = argc == 2 ? argv[1] : NULL;
+
+ if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
+ nvlist_free(policy);
+ return (1);
+ }
+
+ if (zpool_clear(zhp, device, policy) != 0)
+ ret = 1;
+
+ zpool_close(zhp);
+
+ nvlist_free(policy);
+
+ return (ret);
+}
+
+/*
+ * zpool reguid <pool>
+ */
+int
+zpool_do_reguid(int argc, char **argv)
+{
+ int c;
+ char *poolname;
+ zpool_handle_t *zhp;
+ int ret = 0;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "")) != -1) {
+ switch (c) {
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get pool name and check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ poolname = argv[0];
+ if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+ return (1);
+
+ ret = zpool_reguid(zhp);
+
+ zpool_close(zhp);
+ return (ret);
+}
+
+
+/*
+ * zpool reopen <pool>
+ *
+ * Reopen the pool so that the kernel can update the sizes of all vdevs.
+ */
+int
+zpool_do_reopen(int argc, char **argv)
+{
+ int c;
+ int ret = 0;
+ zpool_handle_t *zhp;
+ char *pool;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "")) != -1) {
+ switch (c) {
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc--;
+ argv++;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ pool = argv[0];
+ if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
+ return (1);
+
+ ret = zpool_reopen(zhp);
+ zpool_close(zhp);
+ return (ret);
+}
+
+typedef struct scrub_cbdata {
+ int cb_type;
+ int cb_argc;
+ char **cb_argv;
+ pool_scrub_cmd_t cb_scrub_cmd;
+} scrub_cbdata_t;
+
+static boolean_t
+zpool_has_checkpoint(zpool_handle_t *zhp)
+{
+ nvlist_t *config, *nvroot;
+
+ config = zpool_get_config(zhp, NULL);
+
+ if (config != NULL) {
+ pool_checkpoint_stat_t *pcs = NULL;
+ uint_t c;
+
+ nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
+ (void) nvlist_lookup_uint64_array(nvroot,
+ ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c);
+
+ if (pcs == NULL || pcs->pcs_state == CS_NONE)
+ return (B_FALSE);
+
+ assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS ||
+ pcs->pcs_state == CS_CHECKPOINT_DISCARDING);
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+int
+scrub_callback(zpool_handle_t *zhp, void *data)
+{
+ scrub_cbdata_t *cb = data;
+ int err;
+
+ /*
+ * Ignore faulted pools.
+ */
+ if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
+ (void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
+ "currently unavailable\n"), zpool_get_name(zhp));
+ return (1);
+ }
+
+ err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd);
+
+ if (err == 0 && zpool_has_checkpoint(zhp) &&
+ cb->cb_type == POOL_SCAN_SCRUB) {
+ (void) printf(gettext("warning: will not scrub state that "
+ "belongs to the checkpoint of pool '%s'\n"),
+ zpool_get_name(zhp));
+ }
+
+ return (err != 0);
+}
+
+/*
+ * zpool scrub [-s | -p] <pool> ...
+ *
+ * -s Stop. Stops any in-progress scrub.
+ * -p Pause. Pause in-progress scrub.
+ */
+int
+zpool_do_scrub(int argc, char **argv)
+{
+ int c;
+ scrub_cbdata_t cb;
+
+ cb.cb_type = POOL_SCAN_SCRUB;
+ cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "sp")) != -1) {
+ switch (c) {
+ case 's':
+ cb.cb_type = POOL_SCAN_NONE;
+ break;
+ case 'p':
+ cb.cb_scrub_cmd = POOL_SCRUB_PAUSE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ if (cb.cb_type == POOL_SCAN_NONE &&
+ cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) {
+ (void) fprintf(stderr, gettext("invalid option combination: "
+ "-s and -p are mutually exclusive\n"));
+ usage(B_FALSE);
+ }
+
+ cb.cb_argc = argc;
+ cb.cb_argv = argv;
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name argument\n"));
+ usage(B_FALSE);
+ }
+
+ return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
+}
+
+static void
+zpool_collect_leaves(zpool_handle_t *zhp, nvlist_t *nvroot, nvlist_t *res)
+{
+ uint_t children = 0;
+ nvlist_t **child;
+ uint_t i;
+
+ (void) nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &child, &children);
+
+ if (children == 0) {
+ char *path = zpool_vdev_name(g_zfs, zhp, nvroot, B_FALSE);
+ fnvlist_add_boolean(res, path);
+ free(path);
+ return;
+ }
+
+ for (i = 0; i < children; i++) {
+ zpool_collect_leaves(zhp, child[i], res);
+ }
+}
+
+/*
+ * zpool initialize [-cs] <pool> [<vdev> ...]
+ * Initialize all unused blocks in the specified vdevs, or all vdevs in the pool
+ * if none specified.
+ *
+ * -c Cancel. Ends active initializing.
+ * -s Suspend. Initializing can then be restarted with no flags.
+ */
+int
+zpool_do_initialize(int argc, char **argv)
+{
+ int c;
+ char *poolname;
+ zpool_handle_t *zhp;
+ nvlist_t *vdevs;
+ int err = 0;
+
+ struct option long_options[] = {
+ {"cancel", no_argument, NULL, 'c'},
+ {"suspend", no_argument, NULL, 's'},
+ {0, 0, 0, 0}
+ };
+
+ pool_initialize_func_t cmd_type = POOL_INITIALIZE_DO;
+ while ((c = getopt_long(argc, argv, "cs", long_options, NULL)) != -1) {
+ switch (c) {
+ case 'c':
+ if (cmd_type != POOL_INITIALIZE_DO) {
+ (void) fprintf(stderr, gettext("-c cannot be "
+ "combined with other options\n"));
+ usage(B_FALSE);
+ }
+ cmd_type = POOL_INITIALIZE_CANCEL;
+ break;
+ case 's':
+ if (cmd_type != POOL_INITIALIZE_DO) {
+ (void) fprintf(stderr, gettext("-s cannot be "
+ "combined with other options\n"));
+ usage(B_FALSE);
+ }
+ cmd_type = POOL_INITIALIZE_SUSPEND;
+ break;
+ case '?':
+ if (optopt != 0) {
+ (void) fprintf(stderr,
+ gettext("invalid option '%c'\n"), optopt);
+ } else {
+ (void) fprintf(stderr,
+ gettext("invalid option '%s'\n"),
+ argv[optind - 1]);
+ }
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name argument\n"));
+ usage(B_FALSE);
+ return (-1);
+ }
+
+ poolname = argv[0];
+ zhp = zpool_open(g_zfs, poolname);
+ if (zhp == NULL)
+ return (-1);
+
+ vdevs = fnvlist_alloc();
+ if (argc == 1) {
+ /* no individual leaf vdevs specified, so add them all */
+ nvlist_t *config = zpool_get_config(zhp, NULL);
+ nvlist_t *nvroot = fnvlist_lookup_nvlist(config,
+ ZPOOL_CONFIG_VDEV_TREE);
+ zpool_collect_leaves(zhp, nvroot, vdevs);
+ } else {
+ int i;
+ for (i = 1; i < argc; i++) {
+ fnvlist_add_boolean(vdevs, argv[i]);
+ }
+ }
+
+ err = zpool_initialize(zhp, cmd_type, vdevs);
+
+ fnvlist_free(vdevs);
+ zpool_close(zhp);
+
+ return (err);
+}
+
+/*
+ * Print out detailed scrub status.
+ */
+static void
+print_scan_status(pool_scan_stat_t *ps)
+{
+ time_t start, end, pause;
+ uint64_t total_secs_left;
+ uint64_t elapsed, secs_left, mins_left, hours_left, days_left;
+ uint64_t pass_scanned, scanned, pass_issued, issued, total;
+ uint_t scan_rate, issue_rate;
+ double fraction_done;
+ char processed_buf[7], scanned_buf[7], issued_buf[7], total_buf[7];
+ char srate_buf[7], irate_buf[7];
+
+ (void) printf(gettext(" scan: "));
+
+ /* If there's never been a scan, there's not much to say. */
+ if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
+ ps->pss_func >= POOL_SCAN_FUNCS) {
+ (void) printf(gettext("none requested\n"));
+ return;
+ }
+
+ start = ps->pss_start_time;
+ end = ps->pss_end_time;
+ pause = ps->pss_pass_scrub_pause;
+
+ zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
+
+ assert(ps->pss_func == POOL_SCAN_SCRUB ||
+ ps->pss_func == POOL_SCAN_RESILVER);
+
+ /* Scan is finished or canceled. */
+ if (ps->pss_state == DSS_FINISHED) {
+ total_secs_left = end - start;
+ days_left = total_secs_left / 60 / 60 / 24;
+ hours_left = (total_secs_left / 60 / 60) % 24;
+ mins_left = (total_secs_left / 60) % 60;
+ secs_left = (total_secs_left % 60);
+
+ if (ps->pss_func == POOL_SCAN_SCRUB) {
+ (void) printf(gettext("scrub repaired %s "
+ "in %llu days %02llu:%02llu:%02llu "
+ "with %llu errors on %s"), processed_buf,
+ (u_longlong_t)days_left, (u_longlong_t)hours_left,
+ (u_longlong_t)mins_left, (u_longlong_t)secs_left,
+ (u_longlong_t)ps->pss_errors, ctime(&end));
+ } else if (ps->pss_func == POOL_SCAN_RESILVER) {
+ (void) printf(gettext("resilvered %s "
+ "in %llu days %02llu:%02llu:%02llu "
+ "with %llu errors on %s"), processed_buf,
+ (u_longlong_t)days_left, (u_longlong_t)hours_left,
+ (u_longlong_t)mins_left, (u_longlong_t)secs_left,
+ (u_longlong_t)ps->pss_errors, ctime(&end));
+
+ }
+
+ return;
+ } else if (ps->pss_state == DSS_CANCELED) {
+ if (ps->pss_func == POOL_SCAN_SCRUB) {
+ (void) printf(gettext("scrub canceled on %s"),
+ ctime(&end));
+ } else if (ps->pss_func == POOL_SCAN_RESILVER) {
+ (void) printf(gettext("resilver canceled on %s"),
+ ctime(&end));
+ }
+ return;
+ }
+
+ assert(ps->pss_state == DSS_SCANNING);
+
+ /* Scan is in progress. Resilvers can't be paused. */
+ if (ps->pss_func == POOL_SCAN_SCRUB) {
+ if (pause == 0) {
+ (void) printf(gettext("scrub in progress since %s"),
+ ctime(&start));
+ } else {
+ (void) printf(gettext("scrub paused since %s"),
+ ctime(&pause));
+ (void) printf(gettext("\tscrub started on %s"),
+ ctime(&start));
+ }
+ } else if (ps->pss_func == POOL_SCAN_RESILVER) {
+ (void) printf(gettext("resilver in progress since %s"),
+ ctime(&start));
+ }
+
+ scanned = ps->pss_examined;
+ pass_scanned = ps->pss_pass_exam;
+ issued = ps->pss_issued;
+ pass_issued = ps->pss_pass_issued;
+ total = ps->pss_to_examine;
+
+ /* we are only done with a block once we have issued the IO for it */
+ fraction_done = (double)issued / total;
+
+ /* elapsed time for this pass, rounding up to 1 if it's 0 */
+ elapsed = time(NULL) - ps->pss_pass_start;
+ elapsed -= ps->pss_pass_scrub_spent_paused;
+ elapsed = (elapsed != 0) ? elapsed : 1;
+
+ scan_rate = pass_scanned / elapsed;
+ issue_rate = pass_issued / elapsed;
+ total_secs_left = (issue_rate != 0) ?
+ ((total - issued) / issue_rate) : UINT64_MAX;
+
+ days_left = total_secs_left / 60 / 60 / 24;
+ hours_left = (total_secs_left / 60 / 60) % 24;
+ mins_left = (total_secs_left / 60) % 60;
+ secs_left = (total_secs_left % 60);
+
+ /* format all of the numbers we will be reporting */
+ zfs_nicenum(scanned, scanned_buf, sizeof (scanned_buf));
+ zfs_nicenum(issued, issued_buf, sizeof (issued_buf));
+ zfs_nicenum(total, total_buf, sizeof (total_buf));
+ zfs_nicenum(scan_rate, srate_buf, sizeof (srate_buf));
+ zfs_nicenum(issue_rate, irate_buf, sizeof (irate_buf));
+
+ /* doo not print estimated time if we have a paused scrub */
+ if (pause == 0) {
+ (void) printf(gettext("\t%s scanned at %s/s, "
+ "%s issued at %s/s, %s total\n"),
+ scanned_buf, srate_buf, issued_buf, irate_buf, total_buf);
+ } else {
+ (void) printf(gettext("\t%s scanned, %s issued, %s total\n"),
+ scanned_buf, issued_buf, total_buf);
+ }
+
+ if (ps->pss_func == POOL_SCAN_RESILVER) {
+ (void) printf(gettext("\t%s resilvered, %.2f%% done"),
+ processed_buf, 100 * fraction_done);
+ } else if (ps->pss_func == POOL_SCAN_SCRUB) {
+ (void) printf(gettext("\t%s repaired, %.2f%% done"),
+ processed_buf, 100 * fraction_done);
+ }
+
+ if (pause == 0) {
+ if (issue_rate >= 10 * 1024 * 1024) {
+ (void) printf(gettext(", %llu days "
+ "%02llu:%02llu:%02llu to go\n"),
+ (u_longlong_t)days_left, (u_longlong_t)hours_left,
+ (u_longlong_t)mins_left, (u_longlong_t)secs_left);
+ } else {
+ (void) printf(gettext(", no estimated "
+ "completion time\n"));
+ }
+ } else {
+ (void) printf(gettext("\n"));
+ }
+}
+
+/*
+ * As we don't scrub checkpointed blocks, we want to warn the
+ * user that we skipped scanning some blocks if a checkpoint exists
+ * or existed at any time during the scan.
+ */
+static void
+print_checkpoint_scan_warning(pool_scan_stat_t *ps, pool_checkpoint_stat_t *pcs)
+{
+ if (ps == NULL || pcs == NULL)
+ return;
+
+ if (pcs->pcs_state == CS_NONE ||
+ pcs->pcs_state == CS_CHECKPOINT_DISCARDING)
+ return;
+
+ assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS);
+
+ if (ps->pss_state == DSS_NONE)
+ return;
+
+ if ((ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) &&
+ ps->pss_end_time < pcs->pcs_start_time)
+ return;
+
+ if (ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) {
+ (void) printf(gettext(" scan warning: skipped blocks "
+ "that are only referenced by the checkpoint.\n"));
+ } else {
+ assert(ps->pss_state == DSS_SCANNING);
+ (void) printf(gettext(" scan warning: skipping blocks "
+ "that are only referenced by the checkpoint.\n"));
+ }
+}
+
+/*
+ * Print out detailed removal status.
+ */
+static void
+print_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs)
+{
+ char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
+ time_t start, end;
+ nvlist_t *config, *nvroot;
+ nvlist_t **child;
+ uint_t children;
+ char *vdev_name;
+
+ if (prs == NULL || prs->prs_state == DSS_NONE)
+ return;
+
+ /*
+ * Determine name of vdev.
+ */
+ config = zpool_get_config(zhp, NULL);
+ nvroot = fnvlist_lookup_nvlist(config,
+ ZPOOL_CONFIG_VDEV_TREE);
+ verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) == 0);
+ assert(prs->prs_removing_vdev < children);
+ vdev_name = zpool_vdev_name(g_zfs, zhp,
+ child[prs->prs_removing_vdev], B_TRUE);
+
+ (void) printf(gettext("remove: "));
+
+ start = prs->prs_start_time;
+ end = prs->prs_end_time;
+ zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf));
+
+ /*
+ * Removal is finished or canceled.
+ */
+ if (prs->prs_state == DSS_FINISHED) {
+ uint64_t minutes_taken = (end - start) / 60;
+
+ (void) printf(gettext("Removal of vdev %llu copied %s "
+ "in %lluh%um, completed on %s"),
+ (longlong_t)prs->prs_removing_vdev,
+ copied_buf,
+ (u_longlong_t)(minutes_taken / 60),
+ (uint_t)(minutes_taken % 60),
+ ctime((time_t *)&end));
+ } else if (prs->prs_state == DSS_CANCELED) {
+ (void) printf(gettext("Removal of %s canceled on %s"),
+ vdev_name, ctime(&end));
+ } else {
+ uint64_t copied, total, elapsed, mins_left, hours_left;
+ double fraction_done;
+ uint_t rate;
+
+ assert(prs->prs_state == DSS_SCANNING);
+
+ /*
+ * Removal is in progress.
+ */
+ (void) printf(gettext(
+ "Evacuation of %s in progress since %s"),
+ vdev_name, ctime(&start));
+
+ copied = prs->prs_copied > 0 ? prs->prs_copied : 1;
+ total = prs->prs_to_copy;
+ fraction_done = (double)copied / total;
+
+ /* elapsed time for this pass */
+ elapsed = time(NULL) - prs->prs_start_time;
+ elapsed = elapsed > 0 ? elapsed : 1;
+ rate = copied / elapsed;
+ rate = rate > 0 ? rate : 1;
+ mins_left = ((total - copied) / rate) / 60;
+ hours_left = mins_left / 60;
+
+ zfs_nicenum(copied, examined_buf, sizeof (examined_buf));
+ zfs_nicenum(total, total_buf, sizeof (total_buf));
+ zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
+
+ /*
+ * do not print estimated time if hours_left is more than
+ * 30 days
+ */
+ (void) printf(gettext(" %s copied out of %s at %s/s, "
+ "%.2f%% done"),
+ examined_buf, total_buf, rate_buf, 100 * fraction_done);
+ if (hours_left < (30 * 24)) {
+ (void) printf(gettext(", %lluh%um to go\n"),
+ (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
+ } else {
+ (void) printf(gettext(
+ ", (copy is slow, no estimated time)\n"));
+ }
+ }
+
+ if (prs->prs_mapping_memory > 0) {
+ char mem_buf[7];
+ zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf));
+ (void) printf(gettext(" %s memory used for "
+ "removed device mappings\n"),
+ mem_buf);
+ }
+}
+
+static void
+print_checkpoint_status(pool_checkpoint_stat_t *pcs)
+{
+ time_t start;
+ char space_buf[7];
+
+ if (pcs == NULL || pcs->pcs_state == CS_NONE)
+ return;
+
+ (void) printf(gettext("checkpoint: "));
+
+ start = pcs->pcs_start_time;
+ zfs_nicenum(pcs->pcs_space, space_buf, sizeof (space_buf));
+
+ if (pcs->pcs_state == CS_CHECKPOINT_EXISTS) {
+ char *date = ctime(&start);
+
+ /*
+ * ctime() adds a newline at the end of the generated
+ * string, thus the weird format specifier and the
+ * strlen() call used to chop it off from the output.
+ */
+ (void) printf(gettext("created %.*s, consumes %s\n"),
+ strlen(date) - 1, date, space_buf);
+ return;
+ }
+
+ assert(pcs->pcs_state == CS_CHECKPOINT_DISCARDING);
+
+ (void) printf(gettext("discarding, %s remaining.\n"),
+ space_buf);
+}
+
+static void
+print_error_log(zpool_handle_t *zhp)
+{
+ nvlist_t *nverrlist = NULL;
+ nvpair_t *elem;
+ char *pathname;
+ size_t len = MAXPATHLEN * 2;
+
+ if (zpool_get_errlog(zhp, &nverrlist) != 0) {
+ (void) printf("errors: List of errors unavailable "
+ "(insufficient privileges)\n");
+ return;
+ }
+
+ (void) printf("errors: Permanent errors have been "
+ "detected in the following files:\n\n");
+
+ pathname = safe_malloc(len);
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
+ nvlist_t *nv;
+ uint64_t dsobj, obj;
+
+ verify(nvpair_value_nvlist(elem, &nv) == 0);
+ verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
+ &dsobj) == 0);
+ verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
+ &obj) == 0);
+ zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
+ (void) printf("%7s %s\n", "", pathname);
+ }
+ free(pathname);
+ nvlist_free(nverrlist);
+}
+
+static void
+print_spares(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **spares,
+ uint_t nspares)
+{
+ uint_t i;
+ char *name;
+
+ if (nspares == 0)
+ return;
+
+ (void) printf(gettext("\tspares\n"));
+
+ for (i = 0; i < nspares; i++) {
+ name = zpool_vdev_name(g_zfs, zhp, spares[i],
+ cb->cb_name_flags);
+ print_status_config(zhp, cb, name, spares[i], 2, B_TRUE);
+ free(name);
+ }
+}
+
+static void
+print_l2cache(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **l2cache,
+ uint_t nl2cache)
+{
+ uint_t i;
+ char *name;
+
+ if (nl2cache == 0)
+ return;
+
+ (void) printf(gettext("\tcache\n"));
+
+ for (i = 0; i < nl2cache; i++) {
+ name = zpool_vdev_name(g_zfs, zhp, l2cache[i],
+ cb->cb_name_flags);
+ print_status_config(zhp, cb, name, l2cache[i], 2, B_FALSE);
+ free(name);
+ }
+}
+
+static void
+print_dedup_stats(nvlist_t *config)
+{
+ ddt_histogram_t *ddh;
+ ddt_stat_t *dds;
+ ddt_object_t *ddo;
+ uint_t c;
+
+ /*
+ * If the pool was faulted then we may not have been able to
+ * obtain the config. Otherwise, if we have anything in the dedup
+ * table continue processing the stats.
+ */
+ if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
+ (uint64_t **)&ddo, &c) != 0)
+ return;
+
+ (void) printf("\n");
+ (void) printf(gettext(" dedup: "));
+ if (ddo->ddo_count == 0) {
+ (void) printf(gettext("no DDT entries\n"));
+ return;
+ }
+
+ (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
+ (u_longlong_t)ddo->ddo_count,
+ (u_longlong_t)ddo->ddo_dspace,
+ (u_longlong_t)ddo->ddo_mspace);
+
+ verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
+ (uint64_t **)&dds, &c) == 0);
+ verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
+ (uint64_t **)&ddh, &c) == 0);
+ zpool_dump_ddt(dds, ddh);
+}
+
+/*
+ * Display a summary of pool status. Displays a summary such as:
+ *
+ * pool: tank
+ * status: DEGRADED
+ * reason: One or more devices ...
+ * see: http://illumos.org/msg/ZFS-xxxx-01
+ * config:
+ * mirror DEGRADED
+ * c1t0d0 OK
+ * c2t0d0 UNAVAIL
+ *
+ * When given the '-v' option, we print out the complete config. If the '-e'
+ * option is specified, then we print out error rate information as well.
+ */
+int
+status_callback(zpool_handle_t *zhp, void *data)
+{
+ status_cbdata_t *cbp = data;
+ nvlist_t *config, *nvroot;
+ char *msgid;
+ int reason;
+ const char *health;
+ uint_t c;
+ vdev_stat_t *vs;
+
+ config = zpool_get_config(zhp, NULL);
+ reason = zpool_get_status(zhp, &msgid);
+
+ cbp->cb_count++;
+
+ /*
+ * If we were given 'zpool status -x', only report those pools with
+ * problems.
+ */
+ if (cbp->cb_explain &&
+ (reason == ZPOOL_STATUS_OK ||
+ reason == ZPOOL_STATUS_VERSION_OLDER ||
+ reason == ZPOOL_STATUS_NON_NATIVE_ASHIFT ||
+ reason == ZPOOL_STATUS_FEAT_DISABLED)) {
+ if (!cbp->cb_allpools) {
+ (void) printf(gettext("pool '%s' is healthy\n"),
+ zpool_get_name(zhp));
+ if (cbp->cb_first)
+ cbp->cb_first = B_FALSE;
+ }
+ return (0);
+ }
+
+ if (cbp->cb_first)
+ cbp->cb_first = B_FALSE;
+ else
+ (void) printf("\n");
+
+ nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
+ verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &c) == 0);
+ health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
+
+ (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp));
+ (void) printf(gettext(" state: %s\n"), health);
+
+ switch (reason) {
+ case ZPOOL_STATUS_MISSING_DEV_R:
+ (void) printf(gettext("status: One or more devices could not "
+ "be opened. Sufficient replicas exist for\n\tthe pool to "
+ "continue functioning in a degraded state.\n"));
+ (void) printf(gettext("action: Attach the missing device and "
+ "online it using 'zpool online'.\n"));
+ break;
+
+ case ZPOOL_STATUS_MISSING_DEV_NR:
+ (void) printf(gettext("status: One or more devices could not "
+ "be opened. There are insufficient\n\treplicas for the "
+ "pool to continue functioning.\n"));
+ (void) printf(gettext("action: Attach the missing device and "
+ "online it using 'zpool online'.\n"));
+ break;
+
+ case ZPOOL_STATUS_CORRUPT_LABEL_R:
+ (void) printf(gettext("status: One or more devices could not "
+ "be used because the label is missing or\n\tinvalid. "
+ "Sufficient replicas exist for the pool to continue\n\t"
+ "functioning in a degraded state.\n"));
+ (void) printf(gettext("action: Replace the device using "
+ "'zpool replace'.\n"));
+ break;
+
+ case ZPOOL_STATUS_CORRUPT_LABEL_NR:
+ (void) printf(gettext("status: One or more devices could not "
+ "be used because the label is missing \n\tor invalid. "
+ "There are insufficient replicas for the pool to "
+ "continue\n\tfunctioning.\n"));
+ zpool_explain_recover(zpool_get_handle(zhp),
+ zpool_get_name(zhp), reason, config);
+ break;
+
+ case ZPOOL_STATUS_FAILING_DEV:
+ (void) printf(gettext("status: One or more devices has "
+ "experienced an unrecoverable error. An\n\tattempt was "
+ "made to correct the error. Applications are "
+ "unaffected.\n"));
+ (void) printf(gettext("action: Determine if the device needs "
+ "to be replaced, and clear the errors\n\tusing "
+ "'zpool clear' or replace the device with 'zpool "
+ "replace'.\n"));
+ break;
+
+ case ZPOOL_STATUS_OFFLINE_DEV:
+ (void) printf(gettext("status: One or more devices has "
+ "been taken offline by the administrator.\n\tSufficient "
+ "replicas exist for the pool to continue functioning in "
+ "a\n\tdegraded state.\n"));
+ (void) printf(gettext("action: Online the device using "
+ "'zpool online' or replace the device with\n\t'zpool "
+ "replace'.\n"));
+ break;
+
+ case ZPOOL_STATUS_REMOVED_DEV:
+ (void) printf(gettext("status: One or more devices has "
+ "been removed by the administrator.\n\tSufficient "
+ "replicas exist for the pool to continue functioning in "
+ "a\n\tdegraded state.\n"));
+ (void) printf(gettext("action: Online the device using "
+ "'zpool online' or replace the device with\n\t'zpool "
+ "replace'.\n"));
+ break;
+
+ case ZPOOL_STATUS_RESILVERING:
+ (void) printf(gettext("status: One or more devices is "
+ "currently being resilvered. The pool will\n\tcontinue "
+ "to function, possibly in a degraded state.\n"));
+ (void) printf(gettext("action: Wait for the resilver to "
+ "complete.\n"));
+ break;
+
+ case ZPOOL_STATUS_CORRUPT_DATA:
+ (void) printf(gettext("status: One or more devices has "
+ "experienced an error resulting in data\n\tcorruption. "
+ "Applications may be affected.\n"));
+ (void) printf(gettext("action: Restore the file in question "
+ "if possible. Otherwise restore the\n\tentire pool from "
+ "backup.\n"));
+ break;
+
+ case ZPOOL_STATUS_CORRUPT_POOL:
+ (void) printf(gettext("status: The pool metadata is corrupted "
+ "and the pool cannot be opened.\n"));
+ zpool_explain_recover(zpool_get_handle(zhp),
+ zpool_get_name(zhp), reason, config);
+ break;
+
+ case ZPOOL_STATUS_VERSION_OLDER:
+ (void) printf(gettext("status: The pool is formatted using a "
+ "legacy on-disk format. The pool can\n\tstill be used, "
+ "but some features are unavailable.\n"));
+ (void) printf(gettext("action: Upgrade the pool using 'zpool "
+ "upgrade'. Once this is done, the\n\tpool will no longer "
+ "be accessible on software that does not support feature\n"
+ "\tflags.\n"));
+ break;
+
+ case ZPOOL_STATUS_VERSION_NEWER:
+ (void) printf(gettext("status: The pool has been upgraded to a "
+ "newer, incompatible on-disk version.\n\tThe pool cannot "
+ "be accessed on this system.\n"));
+ (void) printf(gettext("action: Access the pool from a system "
+ "running more recent software, or\n\trestore the pool from "
+ "backup.\n"));
+ break;
+
+ case ZPOOL_STATUS_FEAT_DISABLED:
+ (void) printf(gettext("status: Some supported features are not "
+ "enabled on the pool. The pool can\n\tstill be used, but "
+ "some features are unavailable.\n"));
+ (void) printf(gettext("action: Enable all features using "
+ "'zpool upgrade'. Once this is done,\n\tthe pool may no "
+ "longer be accessible by software that does not support\n\t"
+ "the features. See zpool-features(7) for details.\n"));
+ break;
+
+ case ZPOOL_STATUS_UNSUP_FEAT_READ:
+ (void) printf(gettext("status: The pool cannot be accessed on "
+ "this system because it uses the\n\tfollowing feature(s) "
+ "not supported on this system:\n"));
+ zpool_print_unsup_feat(config);
+ (void) printf("\n");
+ (void) printf(gettext("action: Access the pool from a system "
+ "that supports the required feature(s),\n\tor restore the "
+ "pool from backup.\n"));
+ break;
+
+ case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
+ (void) printf(gettext("status: The pool can only be accessed "
+ "in read-only mode on this system. It\n\tcannot be "
+ "accessed in read-write mode because it uses the "
+ "following\n\tfeature(s) not supported on this system:\n"));
+ zpool_print_unsup_feat(config);
+ (void) printf("\n");
+ (void) printf(gettext("action: The pool cannot be accessed in "
+ "read-write mode. Import the pool with\n"
+ "\t\"-o readonly=on\", access the pool from a system that "
+ "supports the\n\trequired feature(s), or restore the "
+ "pool from backup.\n"));
+ break;
+
+ case ZPOOL_STATUS_FAULTED_DEV_R:
+ (void) printf(gettext("status: One or more devices are "
+ "faulted in response to persistent errors.\n\tSufficient "
+ "replicas exist for the pool to continue functioning "
+ "in a\n\tdegraded state.\n"));
+ (void) printf(gettext("action: Replace the faulted device, "
+ "or use 'zpool clear' to mark the device\n\trepaired.\n"));
+ break;
+
+ case ZPOOL_STATUS_FAULTED_DEV_NR:
+ (void) printf(gettext("status: One or more devices are "
+ "faulted in response to persistent errors. There are "
+ "insufficient replicas for the pool to\n\tcontinue "
+ "functioning.\n"));
+ (void) printf(gettext("action: Destroy and re-create the pool "
+ "from a backup source. Manually marking the device\n"
+ "\trepaired using 'zpool clear' may allow some data "
+ "to be recovered.\n"));
+ break;
+
+ case ZPOOL_STATUS_IO_FAILURE_MMP:
+ (void) printf(gettext("status: The pool is suspended because "
+ "multihost writes failed or were delayed;\n\tanother "
+ "system could import the pool undetected.\n"));
+ (void) printf(gettext("action: Make sure the pool's devices "
+ "are connected, then reboot your system and\n\timport the "
+ "pool.\n"));
+ break;
+
+ case ZPOOL_STATUS_IO_FAILURE_WAIT:
+ case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
+ (void) printf(gettext("status: One or more devices are "
+ "faulted in response to IO failures.\n"));
+ (void) printf(gettext("action: Make sure the affected devices "
+ "are connected, then run 'zpool clear'.\n"));
+ break;
+
+ case ZPOOL_STATUS_BAD_LOG:
+ (void) printf(gettext("status: An intent log record "
+ "could not be read.\n"
+ "\tWaiting for adminstrator intervention to fix the "
+ "faulted pool.\n"));
+ (void) printf(gettext("action: Either restore the affected "
+ "device(s) and run 'zpool online',\n"
+ "\tor ignore the intent log records by running "
+ "'zpool clear'.\n"));
+ break;
+
+ case ZPOOL_STATUS_NON_NATIVE_ASHIFT:
+ (void) printf(gettext("status: One or more devices are "
+ "configured to use a non-native block size.\n"
+ "\tExpect reduced performance.\n"));
+ (void) printf(gettext("action: Replace affected devices with "
+ "devices that support the\n\tconfigured block size, or "
+ "migrate data to a properly configured\n\tpool.\n"));
+ break;
+
+ default:
+ /*
+ * The remaining errors can't actually be generated, yet.
+ */
+ assert(reason == ZPOOL_STATUS_OK);
+ }
+
+ if (msgid != NULL)
+ (void) printf(gettext(" see: http://illumos.org/msg/%s\n"),
+ msgid);
+
+ if (config != NULL) {
+ uint64_t nerr;
+ nvlist_t **spares, **l2cache;
+ uint_t nspares, nl2cache;
+ pool_checkpoint_stat_t *pcs = NULL;
+ pool_scan_stat_t *ps = NULL;
+ pool_removal_stat_t *prs = NULL;
+
+ (void) nvlist_lookup_uint64_array(nvroot,
+ ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c);
+ (void) nvlist_lookup_uint64_array(nvroot,
+ ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
+ (void) nvlist_lookup_uint64_array(nvroot,
+ ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c);
+
+ print_scan_status(ps);
+ print_checkpoint_scan_warning(ps, pcs);
+ print_removal_status(zhp, prs);
+ print_checkpoint_status(pcs);
+
+ cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
+ cbp->cb_name_flags);
+ if (cbp->cb_namewidth < 10)
+ cbp->cb_namewidth = 10;
+
+ (void) printf(gettext("config:\n\n"));
+ (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"),
+ cbp->cb_namewidth, "NAME", "STATE", "READ", "WRITE",
+ "CKSUM");
+
+ print_status_config(zhp, cbp, zpool_get_name(zhp), nvroot, 0,
+ B_FALSE);
+
+ print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_DEDUP);
+ print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
+ print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_CLASS_LOGS);
+
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+ &l2cache, &nl2cache) == 0)
+ print_l2cache(zhp, cbp, l2cache, nl2cache);
+
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0)
+ print_spares(zhp, cbp, spares, nspares);
+
+ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
+ &nerr) == 0) {
+ nvlist_t *nverrlist = NULL;
+
+ /*
+ * If the approximate error count is small, get a
+ * precise count by fetching the entire log and
+ * uniquifying the results.
+ */
+ if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
+ zpool_get_errlog(zhp, &nverrlist) == 0) {
+ nvpair_t *elem;
+
+ elem = NULL;
+ nerr = 0;
+ while ((elem = nvlist_next_nvpair(nverrlist,
+ elem)) != NULL) {
+ nerr++;
+ }
+ }
+ nvlist_free(nverrlist);
+
+ (void) printf("\n");
+
+ if (nerr == 0)
+ (void) printf(gettext("errors: No known data "
+ "errors\n"));
+ else if (!cbp->cb_verbose)
+ (void) printf(gettext("errors: %llu data "
+ "errors, use '-v' for a list\n"),
+ (u_longlong_t)nerr);
+ else
+ print_error_log(zhp);
+ }
+
+ if (cbp->cb_dedup_stats)
+ print_dedup_stats(config);
+ } else {
+ (void) printf(gettext("config: The configuration cannot be "
+ "determined.\n"));
+ }
+
+ return (0);
+}
+
+/*
+ * zpool status [-gLPvx] [-T d|u] [pool] ... [interval [count]]
+ *
+ * -g Display guid for individual vdev name.
+ * -L Follow links when resolving vdev path name.
+ * -P Display full path for vdev name.
+ * -v Display complete error logs
+ * -x Display only pools with potential problems
+ * -D Display dedup status (undocumented)
+ * -T Display a timestamp in date(1) or Unix format
+ *
+ * Describes the health status of all pools or some subset.
+ */
+int
+zpool_do_status(int argc, char **argv)
+{
+ int c;
+ int ret;
+ unsigned long interval = 0, count = 0;
+ status_cbdata_t cb = { 0 };
+
+ /* check options */
+ while ((c = getopt(argc, argv, "gLPvxDT:")) != -1) {
+ switch (c) {
+ case 'g':
+ cb.cb_name_flags |= VDEV_NAME_GUID;
+ break;
+ case 'L':
+ cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ break;
+ case 'P':
+ cb.cb_name_flags |= VDEV_NAME_PATH;
+ break;
+ case 'v':
+ cb.cb_verbose = B_TRUE;
+ break;
+ case 'x':
+ cb.cb_explain = B_TRUE;
+ break;
+ case 'D':
+ cb.cb_dedup_stats = B_TRUE;
+ break;
+ case 'T':
+ get_timestamp_arg(*optarg);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ get_interval_count(&argc, argv, &interval, &count);
+
+ if (argc == 0)
+ cb.cb_allpools = B_TRUE;
+
+ cb.cb_first = B_TRUE;
+ cb.cb_print_status = B_TRUE;
+
+ for (;;) {
+ if (timestamp_fmt != NODATE)
+ print_timestamp(timestamp_fmt);
+
+ ret = for_each_pool(argc, argv, B_TRUE, NULL,
+ status_callback, &cb);
+
+ if (argc == 0 && cb.cb_count == 0)
+ (void) printf(gettext("no pools available\n"));
+ else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
+ (void) printf(gettext("all pools are healthy\n"));
+
+ if (ret != 0)
+ return (ret);
+
+ if (interval == 0)
+ break;
+
+ if (count != 0 && --count == 0)
+ break;
+
+ (void) sleep(interval);
+ }
+
+ return (0);
+}
+
+typedef struct upgrade_cbdata {
+ boolean_t cb_first;
+ boolean_t cb_unavail;
+ char cb_poolname[ZFS_MAX_DATASET_NAME_LEN];
+ int cb_argc;
+ uint64_t cb_version;
+ char **cb_argv;
+} upgrade_cbdata_t;
+
+#ifdef __FreeBSD__
+static int
+is_root_pool(zpool_handle_t *zhp)
+{
+ static struct statfs sfs;
+ static char *poolname = NULL;
+ static boolean_t stated = B_FALSE;
+ char *slash;
+
+ if (!stated) {
+ stated = B_TRUE;
+ if (statfs("/", &sfs) == -1) {
+ (void) fprintf(stderr,
+ "Unable to stat root file system: %s.\n",
+ strerror(errno));
+ return (0);
+ }
+ if (strcmp(sfs.f_fstypename, "zfs") != 0)
+ return (0);
+ poolname = sfs.f_mntfromname;
+ if ((slash = strchr(poolname, '/')) != NULL)
+ *slash = '\0';
+ }
+ return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0);
+}
+
+static void
+root_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size)
+{
+
+ if (poolname[0] == '\0' && is_root_pool(zhp))
+ (void) strlcpy(poolname, zpool_get_name(zhp), size);
+}
+#endif /* FreeBSD */
+
+static int
+upgrade_version(zpool_handle_t *zhp, uint64_t version)
+{
+ int ret;
+ nvlist_t *config;
+ uint64_t oldversion;
+
+ config = zpool_get_config(zhp, NULL);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+ &oldversion) == 0);
+
+ assert(SPA_VERSION_IS_SUPPORTED(oldversion));
+ assert(oldversion < version);
+
+ ret = zpool_upgrade(zhp, version);
+ if (ret != 0)
+ return (ret);
+
+ if (version >= SPA_VERSION_FEATURES) {
+ (void) printf(gettext("Successfully upgraded "
+ "'%s' from version %llu to feature flags.\n"),
+ zpool_get_name(zhp), oldversion);
+ } else {
+ (void) printf(gettext("Successfully upgraded "
+ "'%s' from version %llu to version %llu.\n"),
+ zpool_get_name(zhp), oldversion, version);
+ }
+
+ return (0);
+}
+
+static int
+upgrade_enable_all(zpool_handle_t *zhp, int *countp)
+{
+ int i, ret, count;
+ boolean_t firstff = B_TRUE;
+ nvlist_t *enabled = zpool_get_features(zhp);
+
+ count = 0;
+ for (i = 0; i < SPA_FEATURES; i++) {
+ const char *fname = spa_feature_table[i].fi_uname;
+ const char *fguid = spa_feature_table[i].fi_guid;
+ if (!nvlist_exists(enabled, fguid)) {
+ char *propname;
+ verify(-1 != asprintf(&propname, "feature@%s", fname));
+ ret = zpool_set_prop(zhp, propname,
+ ZFS_FEATURE_ENABLED);
+ if (ret != 0) {
+ free(propname);
+ return (ret);
+ }
+ count++;
+
+ if (firstff) {
+ (void) printf(gettext("Enabled the "
+ "following features on '%s':\n"),
+ zpool_get_name(zhp));
+ firstff = B_FALSE;
+ }
+ (void) printf(gettext(" %s\n"), fname);
+ free(propname);
+ }
+ }
+
+ if (countp != NULL)
+ *countp = count;
+ return (0);
+}
+
+static int
+upgrade_cb(zpool_handle_t *zhp, void *arg)
+{
+ upgrade_cbdata_t *cbp = arg;
+ nvlist_t *config;
+ uint64_t version;
+ boolean_t printnl = B_FALSE;
+ int ret;
+
+ if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
+ (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is "
+ "currently unavailable.\n\n"), zpool_get_name(zhp));
+ cbp->cb_unavail = B_TRUE;
+ /* Allow iteration to continue. */
+ return (0);
+ }
+
+ config = zpool_get_config(zhp, NULL);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+ &version) == 0);
+
+ assert(SPA_VERSION_IS_SUPPORTED(version));
+
+ if (version < cbp->cb_version) {
+ cbp->cb_first = B_FALSE;
+ ret = upgrade_version(zhp, cbp->cb_version);
+ if (ret != 0)
+ return (ret);
+#ifdef __FreeBSD__
+ root_pool_upgrade_check(zhp, cbp->cb_poolname,
+ sizeof(cbp->cb_poolname));
+#endif /* __FreeBSD__ */
+ printnl = B_TRUE;
+
+#ifdef illumos
+ /*
+ * If they did "zpool upgrade -a", then we could
+ * be doing ioctls to different pools. We need
+ * to log this history once to each pool, and bypass
+ * the normal history logging that happens in main().
+ */
+ (void) zpool_log_history(g_zfs, history_str);
+ log_history = B_FALSE;
+#endif
+ }
+
+ if (cbp->cb_version >= SPA_VERSION_FEATURES) {
+ int count;
+ ret = upgrade_enable_all(zhp, &count);
+ if (ret != 0)
+ return (ret);
+
+ if (count > 0) {
+ cbp->cb_first = B_FALSE;
+ printnl = B_TRUE;
+#ifdef __FreeBSD__
+ root_pool_upgrade_check(zhp, cbp->cb_poolname,
+ sizeof(cbp->cb_poolname));
+#endif /* __FreeBSD__ */
+ /*
+ * If they did "zpool upgrade -a", then we could
+ * be doing ioctls to different pools. We need
+ * to log this history once to each pool, and bypass
+ * the normal history logging that happens in main().
+ */
+ (void) zpool_log_history(g_zfs, history_str);
+ log_history = B_FALSE;
+ }
+ }
+
+ if (printnl) {
+ (void) printf(gettext("\n"));
+ }
+
+ return (0);
+}
+
+static int
+upgrade_list_unavail(zpool_handle_t *zhp, void *arg)
+{
+ upgrade_cbdata_t *cbp = arg;
+
+ if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
+ if (cbp->cb_first) {
+ (void) fprintf(stderr, gettext("The following pools "
+ "are unavailable and cannot be upgraded as this "
+ "time.\n\n"));
+ (void) fprintf(stderr, gettext("POOL\n"));
+ (void) fprintf(stderr, gettext("------------\n"));
+ cbp->cb_first = B_FALSE;
+ }
+ (void) printf(gettext("%s\n"), zpool_get_name(zhp));
+ cbp->cb_unavail = B_TRUE;
+ }
+ return (0);
+}
+
+static int
+upgrade_list_older_cb(zpool_handle_t *zhp, void *arg)
+{
+ upgrade_cbdata_t *cbp = arg;
+ nvlist_t *config;
+ uint64_t version;
+
+ if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
+ /*
+ * This will have been reported by upgrade_list_unavail so
+ * just allow iteration to continue.
+ */
+ cbp->cb_unavail = B_TRUE;
+ return (0);
+ }
+
+ config = zpool_get_config(zhp, NULL);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+ &version) == 0);
+
+ assert(SPA_VERSION_IS_SUPPORTED(version));
+
+ if (version < SPA_VERSION_FEATURES) {
+ if (cbp->cb_first) {
+ (void) printf(gettext("The following pools are "
+ "formatted with legacy version numbers and can\n"
+ "be upgraded to use feature flags. After "
+ "being upgraded, these pools\nwill no "
+ "longer be accessible by software that does not "
+ "support feature\nflags.\n\n"));
+ (void) printf(gettext("VER POOL\n"));
+ (void) printf(gettext("--- ------------\n"));
+ cbp->cb_first = B_FALSE;
+ }
+
+ (void) printf("%2llu %s\n", (u_longlong_t)version,
+ zpool_get_name(zhp));
+ }
+
+ return (0);
+}
+
+static int
+upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
+{
+ upgrade_cbdata_t *cbp = arg;
+ nvlist_t *config;
+ uint64_t version;
+
+ if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
+ /*
+ * This will have been reported by upgrade_list_unavail so
+ * just allow iteration to continue.
+ */
+ cbp->cb_unavail = B_TRUE;
+ return (0);
+ }
+
+ config = zpool_get_config(zhp, NULL);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+ &version) == 0);
+
+ if (version >= SPA_VERSION_FEATURES) {
+ int i;
+ boolean_t poolfirst = B_TRUE;
+ nvlist_t *enabled = zpool_get_features(zhp);
+
+ for (i = 0; i < SPA_FEATURES; i++) {
+ const char *fguid = spa_feature_table[i].fi_guid;
+ const char *fname = spa_feature_table[i].fi_uname;
+ if (!nvlist_exists(enabled, fguid)) {
+ if (cbp->cb_first) {
+ (void) printf(gettext("\nSome "
+ "supported features are not "
+ "enabled on the following pools. "
+ "Once a\nfeature is enabled the "
+ "pool may become incompatible with "
+ "software\nthat does not support "
+ "the feature. See "
+ "zpool-features(7) for "
+ "details.\n\n"));
+ (void) printf(gettext("POOL "
+ "FEATURE\n"));
+ (void) printf(gettext("------"
+ "---------\n"));
+ cbp->cb_first = B_FALSE;
+ }
+
+ if (poolfirst) {
+ (void) printf(gettext("%s\n"),
+ zpool_get_name(zhp));
+ poolfirst = B_FALSE;
+ }
+
+ (void) printf(gettext(" %s\n"), fname);
+ }
+ }
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+upgrade_one(zpool_handle_t *zhp, void *data)
+{
+ boolean_t printnl = B_FALSE;
+ upgrade_cbdata_t *cbp = data;
+ uint64_t cur_version;
+ int ret;
+
+ if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
+ (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is "
+ "is currently unavailable.\n\n"), zpool_get_name(zhp));
+ cbp->cb_unavail = B_TRUE;
+ return (1);
+ }
+
+ if (strcmp("log", zpool_get_name(zhp)) == 0) {
+ (void) printf(gettext("'log' is now a reserved word\n"
+ "Pool 'log' must be renamed using export and import"
+ " to upgrade.\n\n"));
+ return (1);
+ }
+
+ cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
+ if (cur_version > cbp->cb_version) {
+ (void) printf(gettext("Pool '%s' is already formatted "
+ "using more current version '%llu'.\n\n"),
+ zpool_get_name(zhp), cur_version);
+ return (0);
+ }
+
+ if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) {
+ (void) printf(gettext("Pool '%s' is already formatted "
+ "using version %llu.\n\n"), zpool_get_name(zhp),
+ cbp->cb_version);
+ return (0);
+ }
+
+ if (cur_version != cbp->cb_version) {
+ printnl = B_TRUE;
+ ret = upgrade_version(zhp, cbp->cb_version);
+ if (ret != 0)
+ return (ret);
+#ifdef __FreeBSD__
+ root_pool_upgrade_check(zhp, cbp->cb_poolname,
+ sizeof(cbp->cb_poolname));
+#endif /* __FreeBSD__ */
+ }
+
+ if (cbp->cb_version >= SPA_VERSION_FEATURES) {
+ int count = 0;
+ ret = upgrade_enable_all(zhp, &count);
+ if (ret != 0)
+ return (ret);
+
+ if (count != 0) {
+ printnl = B_TRUE;
+#ifdef __FreeBSD__
+ root_pool_upgrade_check(zhp, cbp->cb_poolname,
+ sizeof(cbp->cb_poolname));
+#endif /* __FreeBSD __*/
+ } else if (cur_version == SPA_VERSION) {
+ (void) printf(gettext("Pool '%s' already has all "
+ "supported features enabled.\n\n"),
+ zpool_get_name(zhp));
+ }
+ }
+
+ if (printnl) {
+ (void) printf(gettext("\n"));
+ }
+
+ return (0);
+}
+
+/*
+ * zpool upgrade
+ * zpool upgrade -v
+ * zpool upgrade [-V version] <-a | pool ...>
+ *
+ * With no arguments, display downrev'd ZFS pool available for upgrade.
+ * Individual pools can be upgraded by specifying the pool, and '-a' will
+ * upgrade all pools.
+ */
+int
+zpool_do_upgrade(int argc, char **argv)
+{
+ int c;
+ upgrade_cbdata_t cb = { 0 };
+ int ret = 0;
+ boolean_t showversions = B_FALSE;
+ boolean_t upgradeall = B_FALSE;
+ char *end;
+
+
+ /* check options */
+ while ((c = getopt(argc, argv, ":avV:")) != -1) {
+ switch (c) {
+ case 'a':
+ upgradeall = B_TRUE;
+ break;
+ case 'v':
+ showversions = B_TRUE;
+ break;
+ case 'V':
+ cb.cb_version = strtoll(optarg, &end, 10);
+ if (*end != '\0' ||
+ !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
+ (void) fprintf(stderr,
+ gettext("invalid version '%s'\n"), optarg);
+ usage(B_FALSE);
+ }
+ break;
+ case ':':
+ (void) fprintf(stderr, gettext("missing argument for "
+ "'%c' option\n"), optopt);
+ usage(B_FALSE);
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ cb.cb_argc = argc;
+ cb.cb_argv = argv;
+ argc -= optind;
+ argv += optind;
+
+ if (cb.cb_version == 0) {
+ cb.cb_version = SPA_VERSION;
+ } else if (!upgradeall && argc == 0) {
+ (void) fprintf(stderr, gettext("-V option is "
+ "incompatible with other arguments\n"));
+ usage(B_FALSE);
+ }
+
+ if (showversions) {
+ if (upgradeall || argc != 0) {
+ (void) fprintf(stderr, gettext("-v option is "
+ "incompatible with other arguments\n"));
+ usage(B_FALSE);
+ }
+ } else if (upgradeall) {
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("-a option should not "
+ "be used along with a pool name\n"));
+ usage(B_FALSE);
+ }
+ }
+
+ (void) printf(gettext("This system supports ZFS pool feature "
+ "flags.\n\n"));
+ if (showversions) {
+ int i;
+
+ (void) printf(gettext("The following features are "
+ "supported:\n\n"));
+ (void) printf(gettext("FEAT DESCRIPTION\n"));
+ (void) printf("----------------------------------------------"
+ "---------------\n");
+ for (i = 0; i < SPA_FEATURES; i++) {
+ zfeature_info_t *fi = &spa_feature_table[i];
+ const char *ro =
+ (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
+ " (read-only compatible)" : "";
+
+ (void) printf("%-37s%s\n", fi->fi_uname, ro);
+ (void) printf(" %s\n", fi->fi_desc);
+ }
+ (void) printf("\n");
+
+ (void) printf(gettext("The following legacy versions are also "
+ "supported:\n\n"));
+ (void) printf(gettext("VER DESCRIPTION\n"));
+ (void) printf("--- -----------------------------------------"
+ "---------------\n");
+ (void) printf(gettext(" 1 Initial ZFS version\n"));
+ (void) printf(gettext(" 2 Ditto blocks "
+ "(replicated metadata)\n"));
+ (void) printf(gettext(" 3 Hot spares and double parity "
+ "RAID-Z\n"));
+ (void) printf(gettext(" 4 zpool history\n"));
+ (void) printf(gettext(" 5 Compression using the gzip "
+ "algorithm\n"));
+ (void) printf(gettext(" 6 bootfs pool property\n"));
+ (void) printf(gettext(" 7 Separate intent log devices\n"));
+ (void) printf(gettext(" 8 Delegated administration\n"));
+ (void) printf(gettext(" 9 refquota and refreservation "
+ "properties\n"));
+ (void) printf(gettext(" 10 Cache devices\n"));
+ (void) printf(gettext(" 11 Improved scrub performance\n"));
+ (void) printf(gettext(" 12 Snapshot properties\n"));
+ (void) printf(gettext(" 13 snapused property\n"));
+ (void) printf(gettext(" 14 passthrough-x aclinherit\n"));
+ (void) printf(gettext(" 15 user/group space accounting\n"));
+ (void) printf(gettext(" 16 stmf property support\n"));
+ (void) printf(gettext(" 17 Triple-parity RAID-Z\n"));
+ (void) printf(gettext(" 18 Snapshot user holds\n"));
+ (void) printf(gettext(" 19 Log device removal\n"));
+ (void) printf(gettext(" 20 Compression using zle "
+ "(zero-length encoding)\n"));
+ (void) printf(gettext(" 21 Deduplication\n"));
+ (void) printf(gettext(" 22 Received properties\n"));
+ (void) printf(gettext(" 23 Slim ZIL\n"));
+ (void) printf(gettext(" 24 System attributes\n"));
+ (void) printf(gettext(" 25 Improved scrub stats\n"));
+ (void) printf(gettext(" 26 Improved snapshot deletion "
+ "performance\n"));
+ (void) printf(gettext(" 27 Improved snapshot creation "
+ "performance\n"));
+ (void) printf(gettext(" 28 Multiple vdev replacements\n"));
+ (void) printf(gettext("\nFor more information on a particular "
+ "version, including supported releases,\n"));
+ (void) printf(gettext("see the ZFS Administration Guide.\n\n"));
+ } else if (argc == 0 && upgradeall) {
+ cb.cb_first = B_TRUE;
+ ret = zpool_iter(g_zfs, upgrade_cb, &cb);
+ if (ret == 0 && cb.cb_first) {
+ if (cb.cb_version == SPA_VERSION) {
+ (void) printf(gettext("All %spools are already "
+ "formatted using feature flags.\n\n"),
+ cb.cb_unavail ? gettext("available ") : "");
+ (void) printf(gettext("Every %sfeature flags "
+ "pool already has all supported features "
+ "enabled.\n"),
+ cb.cb_unavail ? gettext("available ") : "");
+ } else {
+ (void) printf(gettext("All pools are already "
+ "formatted with version %llu or higher.\n"),
+ cb.cb_version);
+ }
+ }
+ } else if (argc == 0) {
+ cb.cb_first = B_TRUE;
+ ret = zpool_iter(g_zfs, upgrade_list_unavail, &cb);
+ assert(ret == 0);
+
+ if (!cb.cb_first) {
+ (void) fprintf(stderr, "\n");
+ }
+
+ cb.cb_first = B_TRUE;
+ ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb);
+ assert(ret == 0);
+
+ if (cb.cb_first) {
+ (void) printf(gettext("All %spools are formatted using "
+ "feature flags.\n\n"), cb.cb_unavail ?
+ gettext("available ") : "");
+ } else {
+ (void) printf(gettext("\nUse 'zpool upgrade -v' "
+ "for a list of available legacy versions.\n"));
+ }
+
+ cb.cb_first = B_TRUE;
+ ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb);
+ assert(ret == 0);
+
+ if (cb.cb_first) {
+ (void) printf(gettext("Every %sfeature flags pool has "
+ "all supported features enabled.\n"),
+ cb.cb_unavail ? gettext("available ") : "");
+ } else {
+ (void) printf(gettext("\n"));
+ }
+ } else {
+ ret = for_each_pool(argc, argv, B_TRUE, NULL,
+ upgrade_one, &cb);
+ }
+
+ if (cb.cb_poolname[0] != '\0') {
+ (void) printf(
+ "If you boot from pool '%s', don't forget to update boot code.\n"
+ "Assuming you use GPT partitioning and da0 is your boot disk\n"
+ "the following command will do it:\n"
+ "\n"
+ "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n",
+ cb.cb_poolname);
+ }
+
+ return (ret);
+}
+
+typedef struct hist_cbdata {
+ boolean_t first;
+ boolean_t longfmt;
+ boolean_t internal;
+} hist_cbdata_t;
+
+/*
+ * Print out the command history for a specific pool.
+ */
+static int
+get_history_one(zpool_handle_t *zhp, void *data)
+{
+ nvlist_t *nvhis;
+ nvlist_t **records;
+ uint_t numrecords;
+ int ret, i;
+ hist_cbdata_t *cb = (hist_cbdata_t *)data;
+
+ cb->first = B_FALSE;
+
+ (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
+
+ if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
+ return (ret);
+
+ verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
+ &records, &numrecords) == 0);
+ for (i = 0; i < numrecords; i++) {
+ nvlist_t *rec = records[i];
+ char tbuf[30] = "";
+
+ if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
+ time_t tsec;
+ struct tm t;
+
+ tsec = fnvlist_lookup_uint64(records[i],
+ ZPOOL_HIST_TIME);
+ (void) localtime_r(&tsec, &t);
+ (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
+ }
+
+ if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
+ (void) printf("%s %s", tbuf,
+ fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
+ } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
+ int ievent =
+ fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
+ if (!cb->internal)
+ continue;
+ if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
+ (void) printf("%s unrecognized record:\n",
+ tbuf);
+ dump_nvlist(rec, 4);
+ continue;
+ }
+ (void) printf("%s [internal %s txg:%lld] %s", tbuf,
+ zfs_history_event_names[ievent],
+ fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
+ fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
+ } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
+ if (!cb->internal)
+ continue;
+ (void) printf("%s [txg:%lld] %s", tbuf,
+ fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
+ fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
+ if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
+ (void) printf(" %s (%llu)",
+ fnvlist_lookup_string(rec,
+ ZPOOL_HIST_DSNAME),
+ fnvlist_lookup_uint64(rec,
+ ZPOOL_HIST_DSID));
+ }
+ (void) printf(" %s", fnvlist_lookup_string(rec,
+ ZPOOL_HIST_INT_STR));
+ } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
+ if (!cb->internal)
+ continue;
+ (void) printf("%s ioctl %s\n", tbuf,
+ fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
+ if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
+ (void) printf(" input:\n");
+ dump_nvlist(fnvlist_lookup_nvlist(rec,
+ ZPOOL_HIST_INPUT_NVL), 8);
+ }
+ if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
+ (void) printf(" output:\n");
+ dump_nvlist(fnvlist_lookup_nvlist(rec,
+ ZPOOL_HIST_OUTPUT_NVL), 8);
+ }
+ if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) {
+ (void) printf(" errno: %lld\n",
+ fnvlist_lookup_int64(rec,
+ ZPOOL_HIST_ERRNO));
+ }
+ } else {
+ if (!cb->internal)
+ continue;
+ (void) printf("%s unrecognized record:\n", tbuf);
+ dump_nvlist(rec, 4);
+ }
+
+ if (!cb->longfmt) {
+ (void) printf("\n");
+ continue;
+ }
+ (void) printf(" [");
+ if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
+ uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
+ struct passwd *pwd = getpwuid(who);
+ (void) printf("user %d ", (int)who);
+ if (pwd != NULL)
+ (void) printf("(%s) ", pwd->pw_name);
+ }
+ if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
+ (void) printf("on %s",
+ fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
+ }
+ if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
+ (void) printf(":%s",
+ fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
+ }
+ (void) printf("]");
+ (void) printf("\n");
+ }
+ (void) printf("\n");
+ nvlist_free(nvhis);
+
+ return (ret);
+}
+
+/*
+ * zpool history <pool>
+ *
+ * Displays the history of commands that modified pools.
+ */
+int
+zpool_do_history(int argc, char **argv)
+{
+ hist_cbdata_t cbdata = { 0 };
+ int ret;
+ int c;
+
+ cbdata.first = B_TRUE;
+ /* check options */
+ while ((c = getopt(argc, argv, "li")) != -1) {
+ switch (c) {
+ case 'l':
+ cbdata.longfmt = B_TRUE;
+ break;
+ case 'i':
+ cbdata.internal = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one,
+ &cbdata);
+
+ if (argc == 0 && cbdata.first == B_TRUE) {
+ (void) printf(gettext("no pools available\n"));
+ return (0);
+ }
+
+ return (ret);
+}
+
+static int
+get_callback(zpool_handle_t *zhp, void *data)
+{
+ zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
+ char value[MAXNAMELEN];
+ zprop_source_t srctype;
+ zprop_list_t *pl;
+
+ for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
+
+ /*
+ * Skip the special fake placeholder. This will also skip
+ * over the name property when 'all' is specified.
+ */
+ if (pl->pl_prop == ZPOOL_PROP_NAME &&
+ pl == cbp->cb_proplist)
+ continue;
+
+ if (pl->pl_prop == ZPROP_INVAL &&
+ (zpool_prop_feature(pl->pl_user_prop) ||
+ zpool_prop_unsupported(pl->pl_user_prop))) {
+ srctype = ZPROP_SRC_LOCAL;
+
+ if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
+ value, sizeof (value)) == 0) {
+ zprop_print_one_property(zpool_get_name(zhp),
+ cbp, pl->pl_user_prop, value, srctype,
+ NULL, NULL);
+ }
+ } else {
+ if (zpool_get_prop(zhp, pl->pl_prop, value,
+ sizeof (value), &srctype, cbp->cb_literal) != 0)
+ continue;
+
+ zprop_print_one_property(zpool_get_name(zhp), cbp,
+ zpool_prop_to_name(pl->pl_prop), value, srctype,
+ NULL, NULL);
+ }
+ }
+ return (0);
+}
+
+/*
+ * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ...
+ *
+ * -H Scripted mode. Don't display headers, and separate properties
+ * by a single tab.
+ * -o List of columns to display. Defaults to
+ * "name,property,value,source".
+ * -p Diplay values in parsable (exact) format.
+ *
+ * Get properties of pools in the system. Output space statistics
+ * for each one as well as other attributes.
+ */
+int
+zpool_do_get(int argc, char **argv)
+{
+ zprop_get_cbdata_t cb = { 0 };
+ zprop_list_t fake_name = { 0 };
+ int ret;
+ int c, i;
+ char *value;
+
+ cb.cb_first = B_TRUE;
+
+ /*
+ * Set up default columns and sources.
+ */
+ cb.cb_sources = ZPROP_SRC_ALL;
+ cb.cb_columns[0] = GET_COL_NAME;
+ cb.cb_columns[1] = GET_COL_PROPERTY;
+ cb.cb_columns[2] = GET_COL_VALUE;
+ cb.cb_columns[3] = GET_COL_SOURCE;
+ cb.cb_type = ZFS_TYPE_POOL;
+
+ /* check options */
+ while ((c = getopt(argc, argv, ":Hpo:")) != -1) {
+ switch (c) {
+ case 'p':
+ cb.cb_literal = B_TRUE;
+ break;
+ case 'H':
+ cb.cb_scripted = B_TRUE;
+ break;
+ case 'o':
+ bzero(&cb.cb_columns, sizeof (cb.cb_columns));
+ i = 0;
+ while (*optarg != '\0') {
+ static char *col_subopts[] =
+ { "name", "property", "value", "source",
+ "all", NULL };
+
+ if (i == ZFS_GET_NCOLS) {
+ (void) fprintf(stderr, gettext("too "
+ "many fields given to -o "
+ "option\n"));
+ usage(B_FALSE);
+ }
+
+ switch (getsubopt(&optarg, col_subopts,
+ &value)) {
+ case 0:
+ cb.cb_columns[i++] = GET_COL_NAME;
+ break;
+ case 1:
+ cb.cb_columns[i++] = GET_COL_PROPERTY;
+ break;
+ case 2:
+ cb.cb_columns[i++] = GET_COL_VALUE;
+ break;
+ case 3:
+ cb.cb_columns[i++] = GET_COL_SOURCE;
+ break;
+ case 4:
+ if (i > 0) {
+ (void) fprintf(stderr,
+ gettext("\"all\" conflicts "
+ "with specific fields "
+ "given to -o option\n"));
+ usage(B_FALSE);
+ }
+ cb.cb_columns[0] = GET_COL_NAME;
+ cb.cb_columns[1] = GET_COL_PROPERTY;
+ cb.cb_columns[2] = GET_COL_VALUE;
+ cb.cb_columns[3] = GET_COL_SOURCE;
+ i = ZFS_GET_NCOLS;
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("invalid column name "
+ "'%s'\n"), suboptarg);
+ usage(B_FALSE);
+ }
+ }
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing property "
+ "argument\n"));
+ usage(B_FALSE);
+ }
+
+ if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist,
+ ZFS_TYPE_POOL) != 0)
+ usage(B_FALSE);
+
+ argc--;
+ argv++;
+
+ if (cb.cb_proplist != NULL) {
+ fake_name.pl_prop = ZPOOL_PROP_NAME;
+ fake_name.pl_width = strlen(gettext("NAME"));
+ fake_name.pl_next = cb.cb_proplist;
+ cb.cb_proplist = &fake_name;
+ }
+
+ ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
+ get_callback, &cb);
+
+ if (cb.cb_proplist == &fake_name)
+ zprop_free_list(fake_name.pl_next);
+ else
+ zprop_free_list(cb.cb_proplist);
+
+ return (ret);
+}
+
+typedef struct set_cbdata {
+ char *cb_propname;
+ char *cb_value;
+ boolean_t cb_any_successful;
+} set_cbdata_t;
+
+int
+set_callback(zpool_handle_t *zhp, void *data)
+{
+ int error;
+ set_cbdata_t *cb = (set_cbdata_t *)data;
+
+ error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
+
+ if (!error)
+ cb->cb_any_successful = B_TRUE;
+
+ return (error);
+}
+
+int
+zpool_do_set(int argc, char **argv)
+{
+ set_cbdata_t cb = { 0 };
+ int error;
+
+ if (argc > 1 && argv[1][0] == '-') {
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ argv[1][1]);
+ usage(B_FALSE);
+ }
+
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing property=value "
+ "argument\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc < 3) {
+ (void) fprintf(stderr, gettext("missing pool name\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc > 3) {
+ (void) fprintf(stderr, gettext("too many pool names\n"));
+ usage(B_FALSE);
+ }
+
+ cb.cb_propname = argv[1];
+ cb.cb_value = strchr(cb.cb_propname, '=');
+ if (cb.cb_value == NULL) {
+ (void) fprintf(stderr, gettext("missing value in "
+ "property=value argument\n"));
+ usage(B_FALSE);
+ }
+
+ *(cb.cb_value) = '\0';
+ cb.cb_value++;
+
+ error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
+ set_callback, &cb);
+
+ return (error);
+}
+
+static int
+find_command_idx(char *command, int *idx)
+{
+ int i;
+
+ for (i = 0; i < NCOMMAND; i++) {
+ if (command_table[i].name == NULL)
+ continue;
+
+ if (strcmp(command, command_table[i].name) == 0) {
+ *idx = i;
+ return (0);
+ }
+ }
+ return (1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ret = 0;
+ int i;
+ char *cmdname;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ if ((g_zfs = libzfs_init()) == NULL) {
+ (void) fprintf(stderr, gettext("internal error: failed to "
+ "initialize ZFS library\n"));
+ return (1);
+ }
+
+ libzfs_print_on_error(g_zfs, B_TRUE);
+
+ opterr = 0;
+
+ /*
+ * Make sure the user has specified some command.
+ */
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing command\n"));
+ usage(B_FALSE);
+ }
+
+ cmdname = argv[1];
+
+ /*
+ * Special case '-?'
+ */
+ if (strcmp(cmdname, "-?") == 0)
+ usage(B_TRUE);
+
+ zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
+
+ /*
+ * Run the appropriate command.
+ */
+ if (find_command_idx(cmdname, &i) == 0) {
+ current_command = &command_table[i];
+ ret = command_table[i].func(argc - 1, argv + 1);
+ } else if (strchr(cmdname, '=')) {
+ verify(find_command_idx("set", &i) == 0);
+ current_command = &command_table[i];
+ ret = command_table[i].func(argc, argv);
+ } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
+ /*
+ * 'freeze' is a vile debugging abomination, so we treat
+ * it as such.
+ */
+ zfs_cmd_t zc = { 0 };
+ (void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name));
+ return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc));
+ } else {
+ (void) fprintf(stderr, gettext("unrecognized "
+ "command '%s'\n"), cmdname);
+ usage(B_FALSE);
+ }
+
+ if (ret == 0 && log_history)
+ (void) zpool_log_history(g_zfs, history_str);
+
+ libzfs_fini(g_zfs);
+
+ /*
+ * The 'ZFS_ABORT' environment variable causes us to dump core on exit
+ * for the purposes of running ::findleaks.
+ */
+ if (getenv("ZFS_ABORT") != NULL) {
+ (void) printf("dumping core by request\n");
+ abort();
+ }
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_util.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_util.c
new file mode 100644
index 000000000000..c7a002efb17c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_util.c
@@ -0,0 +1,86 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <errno.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "zpool_util.h"
+
+/*
+ * Utility function to guarantee malloc() success.
+ */
+void *
+safe_malloc(size_t size)
+{
+ void *data;
+
+ if ((data = calloc(1, size)) == NULL) {
+ (void) fprintf(stderr, "internal error: out of memory\n");
+ exit(1);
+ }
+
+ return (data);
+}
+
+/*
+ * Display an out of memory error message and abort the current program.
+ */
+void
+zpool_no_memory(void)
+{
+ assert(errno == ENOMEM);
+ (void) fprintf(stderr,
+ gettext("internal error: out of memory\n"));
+ exit(1);
+}
+
+/*
+ * Return the number of logs in supplied nvlist
+ */
+uint_t
+num_logs(nvlist_t *nv)
+{
+ uint_t nlogs = 0;
+ uint_t c, children;
+ nvlist_t **child;
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0)
+ return (0);
+
+ for (c = 0; c < children; c++) {
+ uint64_t is_log = B_FALSE;
+
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &is_log);
+ if (is_log)
+ nlogs++;
+ }
+ return (nlogs);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_util.h b/cddl/contrib/opensolaris/cmd/zpool/zpool_util.h
new file mode 100644
index 000000000000..8777edc9de17
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_util.h
@@ -0,0 +1,73 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef ZPOOL_UTIL_H
+#define ZPOOL_UTIL_H
+
+#include <libnvpair.h>
+#include <libzfs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Basic utility functions
+ */
+void *safe_malloc(size_t);
+void zpool_no_memory(void);
+uint_t num_logs(nvlist_t *nv);
+
+/*
+ * Virtual device functions
+ */
+
+nvlist_t *make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
+ boolean_t replacing, boolean_t dryrun, zpool_boot_label_t boot_type,
+ uint64_t boot_size, int argc, char **argv);
+nvlist_t *split_mirror_vdev(zpool_handle_t *zhp, char *newname,
+ nvlist_t *props, splitflags_t flags, int argc, char **argv);
+
+/*
+ * Pool list functions
+ */
+int for_each_pool(int, char **, boolean_t unavail, zprop_list_t **,
+ zpool_iter_f, void *);
+
+typedef struct zpool_list zpool_list_t;
+
+zpool_list_t *pool_list_get(int, char **, zprop_list_t **, int *);
+void pool_list_update(zpool_list_t *);
+int pool_list_iter(zpool_list_t *, int unavail, zpool_iter_f, void *);
+void pool_list_free(zpool_list_t *);
+int pool_list_count(zpool_list_t *);
+void pool_list_remove(zpool_list_t *, zpool_handle_t *);
+
+libzfs_handle_t *g_zfs;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZPOOL_UTIL_H */
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_vdev.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_vdev.c
new file mode 100644
index 000000000000..43d66d2263e0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_vdev.c
@@ -0,0 +1,1729 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018 by Delphix. All rights reserved.
+ * Copyright (c) 2016, 2017 Intel Corporation.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
+ */
+
+/*
+ * Functions to convert between a list of vdevs and an nvlist representing the
+ * configuration. Each entry in the list can be one of:
+ *
+ * Device vdevs
+ * disk=(path=..., devid=...)
+ * file=(path=...)
+ *
+ * Group vdevs
+ * raidz[1|2]=(...)
+ * mirror=(...)
+ *
+ * Hot spares
+ *
+ * While the underlying implementation supports it, group vdevs cannot contain
+ * other group vdevs. All userland verification of devices is contained within
+ * this file. If successful, the nvlist returned can be passed directly to the
+ * kernel; we've done as much verification as possible in userland.
+ *
+ * Hot spares are a special case, and passed down as an array of disk vdevs, at
+ * the same level as the root of the vdev tree.
+ *
+ * The only function exported by this file is 'make_root_vdev'. The
+ * function performs several passes:
+ *
+ * 1. Construct the vdev specification. Performs syntax validation and
+ * makes sure each device is valid.
+ * 2. Check for devices in use. Using libdiskmgt, makes sure that no
+ * devices are also in use. Some can be overridden using the 'force'
+ * flag, others cannot.
+ * 3. Check for replication errors if the 'force' flag is not specified.
+ * validates that the replication level is consistent across the
+ * entire pool.
+ * 4. Call libzfs to label any whole disks with an EFI label.
+ */
+
+#include <assert.h>
+#include <devid.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <libnvpair.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <paths.h>
+#include <sys/stat.h>
+#include <sys/disk.h>
+#include <sys/mntent.h>
+#include <libgeom.h>
+
+#include "zpool_util.h"
+
+#define BACKUP_SLICE "s2"
+
+/*
+ * For any given vdev specification, we can have multiple errors. The
+ * vdev_error() function keeps track of whether we have seen an error yet, and
+ * prints out a header if its the first error we've seen.
+ */
+boolean_t error_seen;
+boolean_t is_force;
+
+/*PRINTFLIKE1*/
+static void
+vdev_error(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!error_seen) {
+ (void) fprintf(stderr, gettext("invalid vdev specification\n"));
+ if (!is_force)
+ (void) fprintf(stderr, gettext("use '-f' to override "
+ "the following errors:\n"));
+ else
+ (void) fprintf(stderr, gettext("the following errors "
+ "must be manually repaired:\n"));
+ error_seen = B_TRUE;
+ }
+
+ va_start(ap, fmt);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+#ifdef illumos
+static void
+libdiskmgt_error(int error)
+{
+ /*
+ * ENXIO/ENODEV is a valid error message if the device doesn't live in
+ * /dev/dsk. Don't bother printing an error message in this case.
+ */
+ if (error == ENXIO || error == ENODEV)
+ return;
+
+ (void) fprintf(stderr, gettext("warning: device in use checking "
+ "failed: %s\n"), strerror(error));
+}
+
+/*
+ * Validate a device, passing the bulk of the work off to libdiskmgt.
+ */
+static int
+check_slice(const char *path, int force, boolean_t wholedisk, boolean_t isspare)
+{
+ char *msg;
+ int error = 0;
+ dm_who_type_t who;
+
+ if (force)
+ who = DM_WHO_ZPOOL_FORCE;
+ else if (isspare)
+ who = DM_WHO_ZPOOL_SPARE;
+ else
+ who = DM_WHO_ZPOOL;
+
+ if (dm_inuse((char *)path, &msg, who, &error) || error) {
+ if (error != 0) {
+ libdiskmgt_error(error);
+ return (0);
+ } else {
+ vdev_error("%s", msg);
+ free(msg);
+ return (-1);
+ }
+ }
+
+ /*
+ * If we're given a whole disk, ignore overlapping slices since we're
+ * about to label it anyway.
+ */
+ error = 0;
+ if (!wholedisk && !force &&
+ (dm_isoverlapping((char *)path, &msg, &error) || error)) {
+ if (error == 0) {
+ /* dm_isoverlapping returned -1 */
+ vdev_error(gettext("%s overlaps with %s\n"), path, msg);
+ free(msg);
+ return (-1);
+ } else if (error != ENODEV) {
+ /* libdiskmgt's devcache only handles physical drives */
+ libdiskmgt_error(error);
+ return (0);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Validate a whole disk. Iterate over all slices on the disk and make sure
+ * that none is in use by calling check_slice().
+ */
+static int
+check_disk(const char *name, dm_descriptor_t disk, int force, int isspare)
+{
+ dm_descriptor_t *drive, *media, *slice;
+ int err = 0;
+ int i;
+ int ret;
+
+ /*
+ * Get the drive associated with this disk. This should never fail,
+ * because we already have an alias handle open for the device.
+ */
+ if ((drive = dm_get_associated_descriptors(disk, DM_DRIVE,
+ &err)) == NULL || *drive == NULL) {
+ if (err)
+ libdiskmgt_error(err);
+ return (0);
+ }
+
+ if ((media = dm_get_associated_descriptors(*drive, DM_MEDIA,
+ &err)) == NULL) {
+ dm_free_descriptors(drive);
+ if (err)
+ libdiskmgt_error(err);
+ return (0);
+ }
+
+ dm_free_descriptors(drive);
+
+ /*
+ * It is possible that the user has specified a removable media drive,
+ * and the media is not present.
+ */
+ if (*media == NULL) {
+ dm_free_descriptors(media);
+ vdev_error(gettext("'%s' has no media in drive\n"), name);
+ return (-1);
+ }
+
+ if ((slice = dm_get_associated_descriptors(*media, DM_SLICE,
+ &err)) == NULL) {
+ dm_free_descriptors(media);
+ if (err)
+ libdiskmgt_error(err);
+ return (0);
+ }
+
+ dm_free_descriptors(media);
+
+ ret = 0;
+
+ /*
+ * Iterate over all slices and report any errors. We don't care about
+ * overlapping slices because we are using the whole disk.
+ */
+ for (i = 0; slice[i] != NULL; i++) {
+ char *name = dm_get_name(slice[i], &err);
+
+ if (check_slice(name, force, B_TRUE, isspare) != 0)
+ ret = -1;
+
+ dm_free_name(name);
+ }
+
+ dm_free_descriptors(slice);
+ return (ret);
+}
+
+/*
+ * Validate a device.
+ */
+static int
+check_device(const char *path, boolean_t force, boolean_t isspare)
+{
+ dm_descriptor_t desc;
+ int err;
+ char *dev;
+
+ /*
+ * For whole disks, libdiskmgt does not include the leading dev path.
+ */
+ dev = strrchr(path, '/');
+ assert(dev != NULL);
+ dev++;
+ if ((desc = dm_get_descriptor_by_name(DM_ALIAS, dev, &err)) != NULL) {
+ err = check_disk(path, desc, force, isspare);
+ dm_free_descriptor(desc);
+ return (err);
+ }
+
+ return (check_slice(path, force, B_FALSE, isspare));
+}
+#endif /* illumos */
+
+/*
+ * Check that a file is valid. All we can do in this case is check that it's
+ * not in use by another pool, and not in use by swap.
+ */
+static int
+check_file(const char *file, boolean_t force, boolean_t isspare)
+{
+ char *name;
+ int fd;
+ int ret = 0;
+ int err;
+ pool_state_t state;
+ boolean_t inuse;
+
+#ifdef illumos
+ if (dm_inuse_swap(file, &err)) {
+ if (err)
+ libdiskmgt_error(err);
+ else
+ vdev_error(gettext("%s is currently used by swap. "
+ "Please see swap(1M).\n"), file);
+ return (-1);
+ }
+#endif
+
+ if ((fd = open(file, O_RDONLY)) < 0)
+ return (0);
+
+ if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) == 0 && inuse) {
+ const char *desc;
+
+ switch (state) {
+ case POOL_STATE_ACTIVE:
+ desc = gettext("active");
+ break;
+
+ case POOL_STATE_EXPORTED:
+ desc = gettext("exported");
+ break;
+
+ case POOL_STATE_POTENTIALLY_ACTIVE:
+ desc = gettext("potentially active");
+ break;
+
+ default:
+ desc = gettext("unknown");
+ break;
+ }
+
+ /*
+ * Allow hot spares to be shared between pools.
+ */
+ if (state == POOL_STATE_SPARE && isspare)
+ return (0);
+
+ if (state == POOL_STATE_ACTIVE ||
+ state == POOL_STATE_SPARE || !force) {
+ switch (state) {
+ case POOL_STATE_SPARE:
+ vdev_error(gettext("%s is reserved as a hot "
+ "spare for pool %s\n"), file, name);
+ break;
+ default:
+ vdev_error(gettext("%s is part of %s pool "
+ "'%s'\n"), file, desc, name);
+ break;
+ }
+ ret = -1;
+ }
+
+ free(name);
+ }
+
+ (void) close(fd);
+ return (ret);
+}
+
+static int
+check_device(const char *name, boolean_t force, boolean_t isspare)
+{
+ char path[MAXPATHLEN];
+
+ if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) != 0)
+ snprintf(path, sizeof(path), "%s%s", _PATH_DEV, name);
+ else
+ strlcpy(path, name, sizeof(path));
+
+ return (check_file(path, force, isspare));
+}
+
+/*
+ * By "whole disk" we mean an entire physical disk (something we can
+ * label, toggle the write cache on, etc.) as opposed to the full
+ * capacity of a pseudo-device such as lofi or did. We act as if we
+ * are labeling the disk, which should be a pretty good test of whether
+ * it's a viable device or not. Returns B_TRUE if it is and B_FALSE if
+ * it isn't.
+ */
+static boolean_t
+is_whole_disk(const char *arg)
+{
+#ifdef illumos
+ struct dk_gpt *label;
+ int fd;
+ char path[MAXPATHLEN];
+
+ (void) snprintf(path, sizeof (path), "%s%s%s",
+ ZFS_RDISK_ROOT, strrchr(arg, '/'), BACKUP_SLICE);
+ if ((fd = open(path, O_RDWR | O_NDELAY)) < 0)
+ return (B_FALSE);
+ if (efi_alloc_and_init(fd, EFI_NUMPAR, &label) != 0) {
+ (void) close(fd);
+ return (B_FALSE);
+ }
+ efi_free(label);
+ (void) close(fd);
+ return (B_TRUE);
+#else
+ int fd;
+
+ fd = g_open(arg, 0);
+ if (fd >= 0) {
+ g_close(fd);
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+#endif
+}
+
+/*
+ * Create a leaf vdev. Determine if this is a file or a device. If it's a
+ * device, fill in the device id to make a complete nvlist. Valid forms for a
+ * leaf vdev are:
+ *
+ * /dev/dsk/xxx Complete disk path
+ * /xxx Full path to file
+ * xxx Shorthand for /dev/dsk/xxx
+ */
+static nvlist_t *
+make_leaf_vdev(const char *arg, uint64_t is_log)
+{
+ char path[MAXPATHLEN];
+ struct stat64 statbuf;
+ nvlist_t *vdev = NULL;
+ char *type = NULL;
+ boolean_t wholedisk = B_FALSE;
+
+ /*
+ * Determine what type of vdev this is, and put the full path into
+ * 'path'. We detect whether this is a device of file afterwards by
+ * checking the st_mode of the file.
+ */
+ if (arg[0] == '/') {
+ /*
+ * Complete device or file path. Exact type is determined by
+ * examining the file descriptor afterwards.
+ */
+ wholedisk = is_whole_disk(arg);
+ if (!wholedisk && (stat64(arg, &statbuf) != 0)) {
+ (void) fprintf(stderr,
+ gettext("cannot open '%s': %s\n"),
+ arg, strerror(errno));
+ return (NULL);
+ }
+
+ (void) strlcpy(path, arg, sizeof (path));
+ } else {
+ /*
+ * This may be a short path for a device, or it could be total
+ * gibberish. Check to see if it's a known device in
+ * /dev/dsk/. As part of this check, see if we've been given a
+ * an entire disk (minus the slice number).
+ */
+ if (strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ strlcpy(path, arg, sizeof (path));
+ else
+ snprintf(path, sizeof (path), "%s%s", _PATH_DEV, arg);
+ wholedisk = is_whole_disk(path);
+ if (!wholedisk && (stat64(path, &statbuf) != 0)) {
+ /*
+ * If we got ENOENT, then the user gave us
+ * gibberish, so try to direct them with a
+ * reasonable error message. Otherwise,
+ * regurgitate strerror() since it's the best we
+ * can do.
+ */
+ if (errno == ENOENT) {
+ (void) fprintf(stderr,
+ gettext("cannot open '%s': no such "
+ "GEOM provider\n"), arg);
+ (void) fprintf(stderr,
+ gettext("must be a full path or "
+ "shorthand device name\n"));
+ return (NULL);
+ } else {
+ (void) fprintf(stderr,
+ gettext("cannot open '%s': %s\n"),
+ path, strerror(errno));
+ return (NULL);
+ }
+ }
+ }
+
+#ifdef __FreeBSD__
+ if (S_ISCHR(statbuf.st_mode)) {
+ statbuf.st_mode &= ~S_IFCHR;
+ statbuf.st_mode |= S_IFBLK;
+ wholedisk = B_FALSE;
+ }
+#endif
+
+ /*
+ * Determine whether this is a device or a file.
+ */
+ if (wholedisk || S_ISBLK(statbuf.st_mode)) {
+ type = VDEV_TYPE_DISK;
+ } else if (S_ISREG(statbuf.st_mode)) {
+ type = VDEV_TYPE_FILE;
+ } else {
+ (void) fprintf(stderr, gettext("cannot use '%s': must be a "
+ "GEOM provider or regular file\n"), path);
+ return (NULL);
+ }
+
+ /*
+ * Finally, we have the complete device or file, and we know that it is
+ * acceptable to use. Construct the nvlist to describe this vdev. All
+ * vdevs have a 'path' element, and devices also have a 'devid' element.
+ */
+ verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
+ verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
+ verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
+ verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+ if (is_log)
+ verify(nvlist_add_string(vdev, ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_LOG) == 0);
+ if (strcmp(type, VDEV_TYPE_DISK) == 0)
+ verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
+ (uint64_t)wholedisk) == 0);
+
+#ifdef have_devid
+ /*
+ * For a whole disk, defer getting its devid until after labeling it.
+ */
+ if (S_ISBLK(statbuf.st_mode) && !wholedisk) {
+ /*
+ * Get the devid for the device.
+ */
+ int fd;
+ ddi_devid_t devid;
+ char *minor = NULL, *devid_str = NULL;
+
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ (void) fprintf(stderr, gettext("cannot open '%s': "
+ "%s\n"), path, strerror(errno));
+ nvlist_free(vdev);
+ return (NULL);
+ }
+
+ if (devid_get(fd, &devid) == 0) {
+ if (devid_get_minor_name(fd, &minor) == 0 &&
+ (devid_str = devid_str_encode(devid, minor)) !=
+ NULL) {
+ verify(nvlist_add_string(vdev,
+ ZPOOL_CONFIG_DEVID, devid_str) == 0);
+ }
+ if (devid_str != NULL)
+ devid_str_free(devid_str);
+ if (minor != NULL)
+ devid_str_free(minor);
+ devid_free(devid);
+ }
+
+ (void) close(fd);
+ }
+#endif
+
+ return (vdev);
+}
+
+/*
+ * Go through and verify the replication level of the pool is consistent.
+ * Performs the following checks:
+ *
+ * For the new spec, verifies that devices in mirrors and raidz are the
+ * same size.
+ *
+ * If the current configuration already has inconsistent replication
+ * levels, ignore any other potential problems in the new spec.
+ *
+ * Otherwise, make sure that the current spec (if there is one) and the new
+ * spec have consistent replication levels.
+ *
+ * If there is no current spec (create), make sure new spec has at least
+ * one general purpose vdev.
+ */
+typedef struct replication_level {
+ char *zprl_type;
+ uint64_t zprl_children;
+ uint64_t zprl_parity;
+} replication_level_t;
+
+#define ZPOOL_FUZZ (16 * 1024 * 1024)
+
+static boolean_t
+is_raidz_mirror(replication_level_t *a, replication_level_t *b,
+ replication_level_t **raidz, replication_level_t **mirror)
+{
+ if (strcmp(a->zprl_type, "raidz") == 0 &&
+ strcmp(b->zprl_type, "mirror") == 0) {
+ *raidz = a;
+ *mirror = b;
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Given a list of toplevel vdevs, return the current replication level. If
+ * the config is inconsistent, then NULL is returned. If 'fatal' is set, then
+ * an error message will be displayed for each self-inconsistent vdev.
+ */
+static replication_level_t *
+get_replication(nvlist_t *nvroot, boolean_t fatal)
+{
+ nvlist_t **top;
+ uint_t t, toplevels;
+ nvlist_t **child;
+ uint_t c, children;
+ nvlist_t *nv;
+ char *type;
+ replication_level_t lastrep = {0};
+ replication_level_t rep;
+ replication_level_t *ret;
+ replication_level_t *raidz, *mirror;
+ boolean_t dontreport;
+
+ ret = safe_malloc(sizeof (replication_level_t));
+
+ verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &top, &toplevels) == 0);
+
+ for (t = 0; t < toplevels; t++) {
+ uint64_t is_log = B_FALSE;
+
+ nv = top[t];
+
+ /*
+ * For separate logs we ignore the top level vdev replication
+ * constraints.
+ */
+ (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &is_log);
+ if (is_log)
+ continue;
+
+ verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE,
+ &type) == 0);
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0) {
+ /*
+ * This is a 'file' or 'disk' vdev.
+ */
+ rep.zprl_type = type;
+ rep.zprl_children = 1;
+ rep.zprl_parity = 0;
+ } else {
+ uint64_t vdev_size;
+
+ /*
+ * This is a mirror or RAID-Z vdev. Go through and make
+ * sure the contents are all the same (files vs. disks),
+ * keeping track of the number of elements in the
+ * process.
+ *
+ * We also check that the size of each vdev (if it can
+ * be determined) is the same.
+ */
+ rep.zprl_type = type;
+ rep.zprl_children = 0;
+
+ if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
+ verify(nvlist_lookup_uint64(nv,
+ ZPOOL_CONFIG_NPARITY,
+ &rep.zprl_parity) == 0);
+ assert(rep.zprl_parity != 0);
+ } else {
+ rep.zprl_parity = 0;
+ }
+
+ /*
+ * The 'dontreport' variable indicates that we've
+ * already reported an error for this spec, so don't
+ * bother doing it again.
+ */
+ type = NULL;
+ dontreport = 0;
+ vdev_size = -1ULL;
+ for (c = 0; c < children; c++) {
+ boolean_t is_replacing, is_spare;
+ nvlist_t *cnv = child[c];
+ char *path;
+ struct stat64 statbuf;
+ uint64_t size = -1ULL;
+ char *childtype;
+ int fd, err;
+
+ rep.zprl_children++;
+
+ verify(nvlist_lookup_string(cnv,
+ ZPOOL_CONFIG_TYPE, &childtype) == 0);
+
+ /*
+ * If this is a replacing or spare vdev, then
+ * get the real first child of the vdev.
+ */
+ is_replacing = strcmp(childtype,
+ VDEV_TYPE_REPLACING) == 0;
+ is_spare = strcmp(childtype,
+ VDEV_TYPE_SPARE) == 0;
+ if (is_replacing || is_spare) {
+ nvlist_t **rchild;
+ uint_t rchildren;
+
+ verify(nvlist_lookup_nvlist_array(cnv,
+ ZPOOL_CONFIG_CHILDREN, &rchild,
+ &rchildren) == 0);
+ assert((is_replacing && rchildren == 2)
+ || (is_spare && rchildren >= 2));
+ cnv = rchild[0];
+
+ verify(nvlist_lookup_string(cnv,
+ ZPOOL_CONFIG_TYPE,
+ &childtype) == 0);
+ if (strcmp(childtype,
+ VDEV_TYPE_SPARE) == 0) {
+ /* We have a replacing vdev with
+ * a spare child. Get the first
+ * real child of the spare
+ */
+ verify(
+ nvlist_lookup_nvlist_array(
+ cnv,
+ ZPOOL_CONFIG_CHILDREN,
+ &rchild,
+ &rchildren) == 0);
+ assert(rchildren >= 2);
+ cnv = rchild[0];
+ }
+ }
+
+ verify(nvlist_lookup_string(cnv,
+ ZPOOL_CONFIG_PATH, &path) == 0);
+
+ /*
+ * If we have a raidz/mirror that combines disks
+ * with files, report it as an error.
+ */
+ if (!dontreport && type != NULL &&
+ strcmp(type, childtype) != 0) {
+ if (ret != NULL)
+ free(ret);
+ ret = NULL;
+ if (fatal)
+ vdev_error(gettext(
+ "mismatched replication "
+ "level: %s contains both "
+ "files and devices\n"),
+ rep.zprl_type);
+ else
+ return (NULL);
+ dontreport = B_TRUE;
+ }
+
+ /*
+ * According to stat(2), the value of 'st_size'
+ * is undefined for block devices and character
+ * devices. But there is no effective way to
+ * determine the real size in userland.
+ *
+ * Instead, we'll take advantage of an
+ * implementation detail of spec_size(). If the
+ * device is currently open, then we (should)
+ * return a valid size.
+ *
+ * If we still don't get a valid size (indicated
+ * by a size of 0 or MAXOFFSET_T), then ignore
+ * this device altogether.
+ */
+ if ((fd = open(path, O_RDONLY)) >= 0) {
+ err = fstat64(fd, &statbuf);
+ (void) close(fd);
+ } else {
+ err = stat64(path, &statbuf);
+ }
+
+ if (err != 0 ||
+ statbuf.st_size == 0 ||
+ statbuf.st_size == MAXOFFSET_T)
+ continue;
+
+ size = statbuf.st_size;
+
+ /*
+ * Also make sure that devices and
+ * slices have a consistent size. If
+ * they differ by a significant amount
+ * (~16MB) then report an error.
+ */
+ if (!dontreport &&
+ (vdev_size != -1ULL &&
+ (labs(size - vdev_size) >
+ ZPOOL_FUZZ))) {
+ if (ret != NULL)
+ free(ret);
+ ret = NULL;
+ if (fatal)
+ vdev_error(gettext(
+ "%s contains devices of "
+ "different sizes\n"),
+ rep.zprl_type);
+ else
+ return (NULL);
+ dontreport = B_TRUE;
+ }
+
+ type = childtype;
+ vdev_size = size;
+ }
+ }
+
+ /*
+ * At this point, we have the replication of the last toplevel
+ * vdev in 'rep'. Compare it to 'lastrep' to see if it is
+ * different.
+ */
+ if (lastrep.zprl_type != NULL) {
+ if (is_raidz_mirror(&lastrep, &rep, &raidz, &mirror) ||
+ is_raidz_mirror(&rep, &lastrep, &raidz, &mirror)) {
+ /*
+ * Accepted raidz and mirror when they can
+ * handle the same number of disk failures.
+ */
+ if (raidz->zprl_parity !=
+ mirror->zprl_children - 1) {
+ if (ret != NULL)
+ free(ret);
+ ret = NULL;
+ if (fatal)
+ vdev_error(gettext(
+ "mismatched replication "
+ "level: "
+ "%s and %s vdevs with "
+ "different redundancy, "
+ "%llu vs. %llu (%llu-way) "
+ "are present\n"),
+ raidz->zprl_type,
+ mirror->zprl_type,
+ raidz->zprl_parity,
+ mirror->zprl_children - 1,
+ mirror->zprl_children);
+ else
+ return (NULL);
+ }
+ } else if (strcmp(lastrep.zprl_type, rep.zprl_type) !=
+ 0) {
+ if (ret != NULL)
+ free(ret);
+ ret = NULL;
+ if (fatal)
+ vdev_error(gettext(
+ "mismatched replication level: "
+ "both %s and %s vdevs are "
+ "present\n"),
+ lastrep.zprl_type, rep.zprl_type);
+ else
+ return (NULL);
+ } else if (lastrep.zprl_parity != rep.zprl_parity) {
+ if (ret)
+ free(ret);
+ ret = NULL;
+ if (fatal)
+ vdev_error(gettext(
+ "mismatched replication level: "
+ "both %llu and %llu device parity "
+ "%s vdevs are present\n"),
+ lastrep.zprl_parity,
+ rep.zprl_parity,
+ rep.zprl_type);
+ else
+ return (NULL);
+ } else if (lastrep.zprl_children != rep.zprl_children) {
+ if (ret)
+ free(ret);
+ ret = NULL;
+ if (fatal)
+ vdev_error(gettext(
+ "mismatched replication level: "
+ "both %llu-way and %llu-way %s "
+ "vdevs are present\n"),
+ lastrep.zprl_children,
+ rep.zprl_children,
+ rep.zprl_type);
+ else
+ return (NULL);
+ }
+ }
+ lastrep = rep;
+ }
+
+ if (ret != NULL)
+ *ret = rep;
+
+ return (ret);
+}
+
+/*
+ * Check the replication level of the vdev spec against the current pool. Calls
+ * get_replication() to make sure the new spec is self-consistent. If the pool
+ * has a consistent replication level, then we ignore any errors. Otherwise,
+ * report any difference between the two.
+ */
+static int
+check_replication(nvlist_t *config, nvlist_t *newroot)
+{
+ nvlist_t **child;
+ uint_t children;
+ replication_level_t *current = NULL, *new;
+ replication_level_t *raidz, *mirror;
+ int ret;
+
+ /*
+ * If we have a current pool configuration, check to see if it's
+ * self-consistent. If not, simply return success.
+ */
+ if (config != NULL) {
+ nvlist_t *nvroot;
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ if ((current = get_replication(nvroot, B_FALSE)) == NULL)
+ return (0);
+ }
+ /*
+ * for spares there may be no children, and therefore no
+ * replication level to check
+ */
+ if ((nvlist_lookup_nvlist_array(newroot, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0) || (children == 0)) {
+ free(current);
+ return (0);
+ }
+
+ /*
+ * If all we have is logs then there's no replication level to check.
+ */
+ if (num_logs(newroot) == children) {
+ free(current);
+ return (0);
+ }
+
+ /*
+ * Get the replication level of the new vdev spec, reporting any
+ * inconsistencies found.
+ */
+ if ((new = get_replication(newroot, B_TRUE)) == NULL) {
+ free(current);
+ return (-1);
+ }
+
+ /*
+ * Check to see if the new vdev spec matches the replication level of
+ * the current pool.
+ */
+ ret = 0;
+ if (current != NULL) {
+ if (is_raidz_mirror(current, new, &raidz, &mirror) ||
+ is_raidz_mirror(new, current, &raidz, &mirror)) {
+ if (raidz->zprl_parity != mirror->zprl_children - 1) {
+ vdev_error(gettext(
+ "mismatched replication level: pool and "
+ "new vdev with different redundancy, %s "
+ "and %s vdevs, %llu vs. %llu (%llu-way)\n"),
+ raidz->zprl_type,
+ mirror->zprl_type,
+ raidz->zprl_parity,
+ mirror->zprl_children - 1,
+ mirror->zprl_children);
+ ret = -1;
+ }
+ } else if (strcmp(current->zprl_type, new->zprl_type) != 0) {
+ vdev_error(gettext(
+ "mismatched replication level: pool uses %s "
+ "and new vdev is %s\n"),
+ current->zprl_type, new->zprl_type);
+ ret = -1;
+ } else if (current->zprl_parity != new->zprl_parity) {
+ vdev_error(gettext(
+ "mismatched replication level: pool uses %llu "
+ "device parity and new vdev uses %llu\n"),
+ current->zprl_parity, new->zprl_parity);
+ ret = -1;
+ } else if (current->zprl_children != new->zprl_children) {
+ vdev_error(gettext(
+ "mismatched replication level: pool uses %llu-way "
+ "%s and new vdev uses %llu-way %s\n"),
+ current->zprl_children, current->zprl_type,
+ new->zprl_children, new->zprl_type);
+ ret = -1;
+ }
+ }
+
+ free(new);
+ if (current != NULL)
+ free(current);
+
+ return (ret);
+}
+
+#ifdef illumos
+/*
+ * Go through and find any whole disks in the vdev specification, labelling them
+ * as appropriate. When constructing the vdev spec, we were unable to open this
+ * device in order to provide a devid. Now that we have labelled the disk and
+ * know the pool slice is valid, we can construct the devid now.
+ *
+ * If the disk was already labeled with an EFI label, we will have gotten the
+ * devid already (because we were able to open the whole disk). Otherwise, we
+ * need to get the devid after we label the disk.
+ */
+static int
+make_disks(zpool_handle_t *zhp, nvlist_t *nv, zpool_boot_label_t boot_type,
+ uint64_t boot_size)
+{
+ nvlist_t **child;
+ uint_t c, children;
+ char *type, *path, *diskname;
+ char buf[MAXPATHLEN];
+ uint64_t wholedisk;
+ int fd;
+ int ret;
+ int slice;
+ ddi_devid_t devid;
+ char *minor = NULL, *devid_str = NULL;
+
+ verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0) {
+
+ if (strcmp(type, VDEV_TYPE_DISK) != 0)
+ return (0);
+
+ /*
+ * We have a disk device. Get the path to the device
+ * and see if it's a whole disk by appending the backup
+ * slice and stat()ing the device.
+ */
+ verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
+
+ diskname = strrchr(path, '/');
+ assert(diskname != NULL);
+ diskname++;
+
+ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
+ &wholedisk) != 0 || !wholedisk) {
+ /*
+ * This is not whole disk, return error if
+ * boot partition creation was requested
+ */
+ if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
+ (void) fprintf(stderr,
+ gettext("creating boot partition is only "
+ "supported on whole disk vdevs: %s\n"),
+ diskname);
+ return (-1);
+ }
+ return (0);
+ }
+
+ ret = zpool_label_disk(g_zfs, zhp, diskname, boot_type,
+ boot_size, &slice);
+ if (ret == -1)
+ return (ret);
+
+ /*
+ * Fill in the devid, now that we've labeled the disk.
+ */
+ (void) snprintf(buf, sizeof (buf), "%ss%d", path, slice);
+ if ((fd = open(buf, O_RDONLY)) < 0) {
+ (void) fprintf(stderr,
+ gettext("cannot open '%s': %s\n"),
+ buf, strerror(errno));
+ return (-1);
+ }
+
+ if (devid_get(fd, &devid) == 0) {
+ if (devid_get_minor_name(fd, &minor) == 0 &&
+ (devid_str = devid_str_encode(devid, minor)) !=
+ NULL) {
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_DEVID, devid_str) == 0);
+ }
+ if (devid_str != NULL)
+ devid_str_free(devid_str);
+ if (minor != NULL)
+ devid_str_free(minor);
+ devid_free(devid);
+ }
+
+ /*
+ * Update the path to refer to the pool slice. The presence of
+ * the 'whole_disk' field indicates to the CLI that we should
+ * chop off the slice number when displaying the device in
+ * future output.
+ */
+ verify(nvlist_add_string(nv, ZPOOL_CONFIG_PATH, buf) == 0);
+
+ (void) close(fd);
+
+ return (0);
+ }
+
+ /* illumos kernel does not support booting from multi-vdev pools. */
+ if ((boot_type == ZPOOL_CREATE_BOOT_LABEL)) {
+ if ((strcmp(type, VDEV_TYPE_ROOT) == 0) && children > 1) {
+ (void) fprintf(stderr, gettext("boot pool "
+ "can not have more than one vdev\n"));
+ return (-1);
+ }
+ }
+
+ for (c = 0; c < children; c++) {
+ ret = make_disks(zhp, child[c], boot_type, boot_size);
+ if (ret != 0)
+ return (ret);
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+ &child, &children) == 0)
+ for (c = 0; c < children; c++) {
+ ret = make_disks(zhp, child[c], boot_type, boot_size);
+ if (ret != 0)
+ return (ret);
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+ &child, &children) == 0)
+ for (c = 0; c < children; c++) {
+ ret = make_disks(zhp, child[c], boot_type, boot_size);
+ if (ret != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+#endif /* illumos */
+
+/*
+ * Determine if the given path is a hot spare within the given configuration.
+ */
+static boolean_t
+is_spare(nvlist_t *config, const char *path)
+{
+ int fd;
+ pool_state_t state;
+ char *name = NULL;
+ nvlist_t *label;
+ uint64_t guid, spareguid;
+ nvlist_t *nvroot;
+ nvlist_t **spares;
+ uint_t i, nspares;
+ boolean_t inuse;
+
+ if ((fd = open(path, O_RDONLY)) < 0)
+ return (B_FALSE);
+
+ if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0 ||
+ !inuse ||
+ state != POOL_STATE_SPARE ||
+ zpool_read_label(fd, &label) != 0) {
+ free(name);
+ (void) close(fd);
+ return (B_FALSE);
+ }
+ free(name);
+ (void) close(fd);
+
+ verify(nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &guid) == 0);
+ nvlist_free(label);
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0) {
+ for (i = 0; i < nspares; i++) {
+ verify(nvlist_lookup_uint64(spares[i],
+ ZPOOL_CONFIG_GUID, &spareguid) == 0);
+ if (spareguid == guid)
+ return (B_TRUE);
+ }
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Go through and find any devices that are in use. We rely on libdiskmgt for
+ * the majority of this task.
+ */
+static boolean_t
+is_device_in_use(nvlist_t *config, nvlist_t *nv, boolean_t force,
+ boolean_t replacing, boolean_t isspare)
+{
+ nvlist_t **child;
+ uint_t c, children;
+ char *type, *path;
+ int ret = 0;
+ char buf[MAXPATHLEN];
+ uint64_t wholedisk;
+ boolean_t anyinuse = B_FALSE;
+
+ verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0) {
+
+ verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
+
+ /*
+ * As a generic check, we look to see if this is a replace of a
+ * hot spare within the same pool. If so, we allow it
+ * regardless of what libdiskmgt or zpool_in_use() says.
+ */
+ if (replacing) {
+#ifdef illumos
+ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
+ &wholedisk) == 0 && wholedisk)
+ (void) snprintf(buf, sizeof (buf), "%ss0",
+ path);
+ else
+#endif
+ (void) strlcpy(buf, path, sizeof (buf));
+
+ if (is_spare(config, buf))
+ return (B_FALSE);
+ }
+
+ if (strcmp(type, VDEV_TYPE_DISK) == 0)
+ ret = check_device(path, force, isspare);
+ else if (strcmp(type, VDEV_TYPE_FILE) == 0)
+ ret = check_file(path, force, isspare);
+
+ return (ret != 0);
+ }
+
+ for (c = 0; c < children; c++)
+ if (is_device_in_use(config, child[c], force, replacing,
+ B_FALSE))
+ anyinuse = B_TRUE;
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+ &child, &children) == 0)
+ for (c = 0; c < children; c++)
+ if (is_device_in_use(config, child[c], force, replacing,
+ B_TRUE))
+ anyinuse = B_TRUE;
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+ &child, &children) == 0)
+ for (c = 0; c < children; c++)
+ if (is_device_in_use(config, child[c], force, replacing,
+ B_FALSE))
+ anyinuse = B_TRUE;
+
+ return (anyinuse);
+}
+
+static const char *
+is_grouping(const char *type, int *mindev, int *maxdev)
+{
+ if (strncmp(type, "raidz", 5) == 0) {
+ const char *p = type + 5;
+ char *end;
+ long nparity;
+
+ if (*p == '\0') {
+ nparity = 1;
+ } else if (*p == '0') {
+ return (NULL); /* no zero prefixes allowed */
+ } else {
+ errno = 0;
+ nparity = strtol(p, &end, 10);
+ if (errno != 0 || nparity < 1 || nparity >= 255 ||
+ *end != '\0')
+ return (NULL);
+ }
+
+ if (mindev != NULL)
+ *mindev = nparity + 1;
+ if (maxdev != NULL)
+ *maxdev = 255;
+ return (VDEV_TYPE_RAIDZ);
+ }
+
+ if (maxdev != NULL)
+ *maxdev = INT_MAX;
+
+ if (strcmp(type, "mirror") == 0) {
+ if (mindev != NULL)
+ *mindev = 2;
+ return (VDEV_TYPE_MIRROR);
+ }
+
+ if (strcmp(type, "spare") == 0) {
+ if (mindev != NULL)
+ *mindev = 1;
+ return (VDEV_TYPE_SPARE);
+ }
+
+ if (strcmp(type, "log") == 0) {
+ if (mindev != NULL)
+ *mindev = 1;
+ return (VDEV_TYPE_LOG);
+ }
+
+ if (strcmp(type, VDEV_ALLOC_BIAS_SPECIAL) == 0 ||
+ strcmp(type, VDEV_ALLOC_BIAS_DEDUP) == 0) {
+ if (mindev != NULL)
+ *mindev = 1;
+ return (type);
+ }
+
+ if (strcmp(type, "cache") == 0) {
+ if (mindev != NULL)
+ *mindev = 1;
+ return (VDEV_TYPE_L2CACHE);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Construct a syntactically valid vdev specification,
+ * and ensure that all devices and files exist and can be opened.
+ * Note: we don't bother freeing anything in the error paths
+ * because the program is just going to exit anyway.
+ */
+nvlist_t *
+construct_spec(int argc, char **argv)
+{
+ nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
+ int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
+ const char *type;
+ uint64_t is_log, is_special, is_dedup;
+ boolean_t seen_logs;
+
+ top = NULL;
+ toplevels = 0;
+ spares = NULL;
+ l2cache = NULL;
+ nspares = 0;
+ nlogs = 0;
+ nl2cache = 0;
+ is_log = is_special = is_dedup = B_FALSE;
+ seen_logs = B_FALSE;
+
+ while (argc > 0) {
+ nv = NULL;
+
+ /*
+ * If it's a mirror or raidz, the subsequent arguments are
+ * its leaves -- until we encounter the next mirror or raidz.
+ */
+ if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) {
+ nvlist_t **child = NULL;
+ int c, children = 0;
+
+ if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
+ if (spares != NULL) {
+ (void) fprintf(stderr,
+ gettext("invalid vdev "
+ "specification: 'spare' can be "
+ "specified only once\n"));
+ return (NULL);
+ }
+ is_log = is_special = is_dedup = B_FALSE;
+ }
+
+ if (strcmp(type, VDEV_TYPE_LOG) == 0) {
+ if (seen_logs) {
+ (void) fprintf(stderr,
+ gettext("invalid vdev "
+ "specification: 'log' can be "
+ "specified only once\n"));
+ return (NULL);
+ }
+ seen_logs = B_TRUE;
+ is_log = B_TRUE;
+ is_special = B_FALSE;
+ is_dedup = B_FALSE;
+ argc--;
+ argv++;
+ /*
+ * A log is not a real grouping device.
+ * We just set is_log and continue.
+ */
+ continue;
+ }
+
+ if (strcmp(type, VDEV_ALLOC_BIAS_SPECIAL) == 0) {
+ is_special = B_TRUE;
+ is_log = B_FALSE;
+ is_dedup = B_FALSE;
+ argc--;
+ argv++;
+ continue;
+ }
+
+ if (strcmp(type, VDEV_ALLOC_BIAS_DEDUP) == 0) {
+ is_dedup = B_TRUE;
+ is_log = B_FALSE;
+ is_special = B_FALSE;
+ argc--;
+ argv++;
+ continue;
+ }
+
+ if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) {
+ if (l2cache != NULL) {
+ (void) fprintf(stderr,
+ gettext("invalid vdev "
+ "specification: 'cache' can be "
+ "specified only once\n"));
+ return (NULL);
+ }
+ is_log = is_special = is_dedup = B_FALSE;
+ }
+
+ if (is_log || is_special || is_dedup) {
+ if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
+ (void) fprintf(stderr,
+ gettext("invalid vdev "
+ "specification: unsupported '%s' "
+ "device: %s\n"), is_log ? "log" :
+ "special", type);
+ return (NULL);
+ }
+ nlogs++;
+ }
+
+ for (c = 1; c < argc; c++) {
+ if (is_grouping(argv[c], NULL, NULL) != NULL)
+ break;
+ children++;
+ child = realloc(child,
+ children * sizeof (nvlist_t *));
+ if (child == NULL)
+ zpool_no_memory();
+ if ((nv = make_leaf_vdev(argv[c], B_FALSE))
+ == NULL)
+ return (NULL);
+ child[children - 1] = nv;
+ }
+
+ if (children < mindev) {
+ (void) fprintf(stderr, gettext("invalid vdev "
+ "specification: %s requires at least %d "
+ "devices\n"), argv[0], mindev);
+ return (NULL);
+ }
+
+ if (children > maxdev) {
+ (void) fprintf(stderr, gettext("invalid vdev "
+ "specification: %s supports no more than "
+ "%d devices\n"), argv[0], maxdev);
+ return (NULL);
+ }
+
+ argc -= c;
+ argv += c;
+
+ if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
+ spares = child;
+ nspares = children;
+ continue;
+ } else if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) {
+ l2cache = child;
+ nl2cache = children;
+ continue;
+ } else {
+ /* create a top-level vdev with children */
+ verify(nvlist_alloc(&nv, NV_UNIQUE_NAME,
+ 0) == 0);
+ verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE,
+ type) == 0);
+ verify(nvlist_add_uint64(nv,
+ ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+ if (is_log)
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_LOG) == 0);
+ if (is_special) {
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_SPECIAL) == 0);
+ }
+ if (is_dedup) {
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_DEDUP) == 0);
+ }
+ if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
+ verify(nvlist_add_uint64(nv,
+ ZPOOL_CONFIG_NPARITY,
+ mindev - 1) == 0);
+ }
+ verify(nvlist_add_nvlist_array(nv,
+ ZPOOL_CONFIG_CHILDREN, child,
+ children) == 0);
+
+ for (c = 0; c < children; c++)
+ nvlist_free(child[c]);
+ free(child);
+ }
+ } else {
+ /*
+ * We have a device. Pass off to make_leaf_vdev() to
+ * construct the appropriate nvlist describing the vdev.
+ */
+ if ((nv = make_leaf_vdev(argv[0], is_log)) == NULL)
+ return (NULL);
+ if (is_log)
+ nlogs++;
+ if (is_special) {
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_SPECIAL) == 0);
+ }
+ if (is_dedup) {
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_DEDUP) == 0);
+ }
+ argc--;
+ argv++;
+ }
+
+ toplevels++;
+ top = realloc(top, toplevels * sizeof (nvlist_t *));
+ if (top == NULL)
+ zpool_no_memory();
+ top[toplevels - 1] = nv;
+ }
+
+ if (toplevels == 0 && nspares == 0 && nl2cache == 0) {
+ (void) fprintf(stderr, gettext("invalid vdev "
+ "specification: at least one toplevel vdev must be "
+ "specified\n"));
+ return (NULL);
+ }
+
+ if (seen_logs && nlogs == 0) {
+ (void) fprintf(stderr, gettext("invalid vdev specification: "
+ "log requires at least 1 device\n"));
+ return (NULL);
+ }
+
+ /*
+ * Finally, create nvroot and add all top-level vdevs to it.
+ */
+ verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0);
+ verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_ROOT) == 0);
+ verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ top, toplevels) == 0);
+ if (nspares != 0)
+ verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ spares, nspares) == 0);
+ if (nl2cache != 0)
+ verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+ l2cache, nl2cache) == 0);
+
+ for (t = 0; t < toplevels; t++)
+ nvlist_free(top[t]);
+ for (t = 0; t < nspares; t++)
+ nvlist_free(spares[t]);
+ for (t = 0; t < nl2cache; t++)
+ nvlist_free(l2cache[t]);
+ if (spares)
+ free(spares);
+ if (l2cache)
+ free(l2cache);
+ free(top);
+
+ return (nvroot);
+}
+
+nvlist_t *
+split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
+ splitflags_t flags, int argc, char **argv)
+{
+ nvlist_t *newroot = NULL, **child;
+ uint_t c, children;
+#ifdef illumos
+ zpool_boot_label_t boot_type;
+#endif
+
+ if (argc > 0) {
+ if ((newroot = construct_spec(argc, argv)) == NULL) {
+ (void) fprintf(stderr, gettext("Unable to build a "
+ "pool from the specified devices\n"));
+ return (NULL);
+ }
+
+#ifdef illumos
+ if (zpool_is_bootable(zhp))
+ boot_type = ZPOOL_COPY_BOOT_LABEL;
+ else
+ boot_type = ZPOOL_NO_BOOT_LABEL;
+
+ if (!flags.dryrun &&
+ make_disks(zhp, newroot, boot_type, 0) != 0) {
+ nvlist_free(newroot);
+ return (NULL);
+ }
+#endif
+
+ /* avoid any tricks in the spec */
+ verify(nvlist_lookup_nvlist_array(newroot,
+ ZPOOL_CONFIG_CHILDREN, &child, &children) == 0);
+ for (c = 0; c < children; c++) {
+ char *path;
+ const char *type;
+ int min, max;
+
+ verify(nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_PATH, &path) == 0);
+ if ((type = is_grouping(path, &min, &max)) != NULL) {
+ (void) fprintf(stderr, gettext("Cannot use "
+ "'%s' as a device for splitting\n"), type);
+ nvlist_free(newroot);
+ return (NULL);
+ }
+ }
+ }
+
+ if (zpool_vdev_split(zhp, newname, &newroot, props, flags) != 0) {
+ nvlist_free(newroot);
+ return (NULL);
+ }
+
+ return (newroot);
+}
+
+static int
+num_normal_vdevs(nvlist_t *nvroot)
+{
+ nvlist_t **top;
+ uint_t t, toplevels, normal = 0;
+
+ verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &top, &toplevels) == 0);
+
+ for (t = 0; t < toplevels; t++) {
+ uint64_t log = B_FALSE;
+
+ (void) nvlist_lookup_uint64(top[t], ZPOOL_CONFIG_IS_LOG, &log);
+ if (log)
+ continue;
+ if (nvlist_exists(top[t], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
+
+ normal++;
+ }
+
+ return (normal);
+}
+
+/*
+ * Get and validate the contents of the given vdev specification. This ensures
+ * that the nvlist returned is well-formed, that all the devices exist, and that
+ * they are not currently in use by any other known consumer. The 'poolconfig'
+ * parameter is the current configuration of the pool when adding devices
+ * existing pool, and is used to perform additional checks, such as changing the
+ * replication level of the pool. It can be 'NULL' to indicate that this is a
+ * new pool. The 'force' flag controls whether devices should be forcefully
+ * added, even if they appear in use.
+ */
+nvlist_t *
+make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
+ boolean_t replacing, boolean_t dryrun, zpool_boot_label_t boot_type,
+ uint64_t boot_size, int argc, char **argv)
+{
+ nvlist_t *newroot;
+ nvlist_t *poolconfig = NULL;
+ is_force = force;
+
+ /*
+ * Construct the vdev specification. If this is successful, we know
+ * that we have a valid specification, and that all devices can be
+ * opened.
+ */
+ if ((newroot = construct_spec(argc, argv)) == NULL)
+ return (NULL);
+
+ if (zhp && ((poolconfig = zpool_get_config(zhp, NULL)) == NULL))
+ return (NULL);
+
+ /*
+ * Validate each device to make sure that its not shared with another
+ * subsystem. We do this even if 'force' is set, because there are some
+ * uses (such as a dedicated dump device) that even '-f' cannot
+ * override.
+ */
+ if (is_device_in_use(poolconfig, newroot, force, replacing, B_FALSE)) {
+ nvlist_free(newroot);
+ return (NULL);
+ }
+
+ /*
+ * Check the replication level of the given vdevs and report any errors
+ * found. We include the existing pool spec, if any, as we need to
+ * catch changes against the existing replication level.
+ */
+ if (check_rep && check_replication(poolconfig, newroot) != 0) {
+ nvlist_free(newroot);
+ return (NULL);
+ }
+
+#ifdef illumos
+ /*
+ * On pool create the new vdev spec must have one normal vdev.
+ */
+ if (poolconfig == NULL && num_normal_vdevs(newroot) == 0) {
+ vdev_error(gettext("at least one general top-level vdev must "
+ "be specified\n"));
+ nvlist_free(newroot);
+ return (NULL);
+ }
+
+ /*
+ * Run through the vdev specification and label any whole disks found.
+ */
+ if (!dryrun && make_disks(zhp, newroot, boot_type, boot_size) != 0) {
+ nvlist_free(newroot);
+ return (NULL);
+ }
+#endif
+
+ return (newroot);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.1 b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.1
new file mode 100644
index 000000000000..7158075d8b40
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.1
@@ -0,0 +1,71 @@
+'\" te
+.\" Copyright (c) 2011, Martin Matuska <mm@FreeBSD.org>.
+.\" All Rights Reserved.
+.\"
+.\" 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]
+.\"
+.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright (c) 2013, Delphix. All Rights Reserved.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 31, 2013
+.Dt ZSTREAMDUMP 8
+.Os
+.Sh NAME
+.Nm zstreamdump
+.Nd filter data in zfs send stream
+.Sh SYNOPSIS
+.Nm
+.Op Fl C
+.Op Fl d
+.Op Fl v
+.Sh DESCRIPTION
+The
+.Nm
+utility reads from the output of the
+.Qq Nm zfs Cm send
+command, then displays headers and some statistics from that output. See
+.Xr zfs 8 .
+.Pp
+The following options are supported:
+.Bl -tag -width indent
+.It Fl C
+Suppress the validation of checksums.
+.It Fl d
+Dump contents of blocks modified, implies verbose.
+.It Fl v
+Verbose. Dump all headers, not only begin and end headers.
+.El
+.Sh SEE ALSO
+.Xr zfs 8
+.Sh AUTHORS
+This manual page is a
+.Xr mdoc 7
+reimplementation of the
+.Tn OpenSolaris
+manual page
+.Em zstreamdump(1M) ,
+modified and customized for
+.Fx
+and licensed under the
+.Tn Common Development and Distribution License
+.Pq Tn CDDL .
+.Pp
+The
+.Xr mdoc 7
+implementation of this manual page was initially written by
+.An Martin Matuska Aq mm@FreeBSD.org .
diff --git a/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c
new file mode 100644
index 000000000000..51c4c8e0e649
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c
@@ -0,0 +1,644 @@
+/*
+ * 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 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
+ */
+
+#include <ctype.h>
+#include <libnvpair.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+
+#include <sys/dmu.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zio.h>
+#include <zfs_fletcher.h>
+
+/*
+ * If dump mode is enabled, the number of bytes to print per line
+ */
+#define BYTES_PER_LINE 16
+/*
+ * If dump mode is enabled, the number of bytes to group together, separated
+ * by newlines or spaces
+ */
+#define DUMP_GROUPING 4
+
+uint64_t total_write_size = 0;
+uint64_t total_stream_len = 0;
+FILE *send_stream = 0;
+boolean_t do_byteswap = B_FALSE;
+boolean_t do_cksum = B_TRUE;
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] [-d] < file\n");
+ (void) fprintf(stderr, "\t -v -- verbose\n");
+ (void) fprintf(stderr, "\t -C -- suppress checksum verification\n");
+ (void) fprintf(stderr, "\t -d -- dump contents of blocks modified, "
+ "implies verbose\n");
+ exit(1);
+}
+
+static void *
+safe_malloc(size_t size)
+{
+ void *rv = malloc(size);
+ if (rv == NULL) {
+ (void) fprintf(stderr, "ERROR; failed to allocate %zu bytes\n",
+ size);
+ abort();
+ }
+ return (rv);
+}
+
+/*
+ * ssread - send stream read.
+ *
+ * Read while computing incremental checksum
+ */
+static size_t
+ssread(void *buf, size_t len, zio_cksum_t *cksum)
+{
+ size_t outlen;
+
+ if ((outlen = fread(buf, len, 1, send_stream)) == 0)
+ return (0);
+
+ if (do_cksum) {
+ if (do_byteswap)
+ fletcher_4_incremental_byteswap(buf, len, cksum);
+ else
+ fletcher_4_incremental_native(buf, len, cksum);
+ }
+ total_stream_len += len;
+ return (outlen);
+}
+
+static size_t
+read_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum)
+{
+ ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+ ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
+ size_t r = ssread(drr, sizeof (*drr) - sizeof (zio_cksum_t), cksum);
+ if (r == 0)
+ return (0);
+ zio_cksum_t saved_cksum = *cksum;
+ r = ssread(&drr->drr_u.drr_checksum.drr_checksum,
+ sizeof (zio_cksum_t), cksum);
+ if (r == 0)
+ return (0);
+ if (!ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.drr_checksum.drr_checksum) &&
+ !ZIO_CHECKSUM_EQUAL(saved_cksum,
+ drr->drr_u.drr_checksum.drr_checksum)) {
+ fprintf(stderr, "invalid checksum\n");
+ (void) printf("Incorrect checksum in record header.\n");
+ (void) printf("Expected checksum = %llx/%llx/%llx/%llx\n",
+ saved_cksum.zc_word[0],
+ saved_cksum.zc_word[1],
+ saved_cksum.zc_word[2],
+ saved_cksum.zc_word[3]);
+ return (0);
+ }
+ return (sizeof (*drr));
+}
+
+/*
+ * Print part of a block in ASCII characters
+ */
+static void
+print_ascii_block(char *subbuf, int length)
+{
+ int i;
+
+ for (i = 0; i < length; i++) {
+ char char_print = isprint(subbuf[i]) ? subbuf[i] : '.';
+ if (i != 0 && i % DUMP_GROUPING == 0) {
+ (void) printf(" ");
+ }
+ (void) printf("%c", char_print);
+ }
+ (void) printf("\n");
+}
+
+/*
+ * print_block - Dump the contents of a modified block to STDOUT
+ *
+ * Assume that buf has capacity evenly divisible by BYTES_PER_LINE
+ */
+static void
+print_block(char *buf, int length)
+{
+ int i;
+ /*
+ * Start printing ASCII characters at a constant offset, after
+ * the hex prints. Leave 3 characters per byte on a line (2 digit
+ * hex number plus 1 space) plus spaces between characters and
+ * groupings.
+ */
+ int ascii_start = BYTES_PER_LINE * 3 +
+ BYTES_PER_LINE / DUMP_GROUPING + 2;
+
+ for (i = 0; i < length; i += BYTES_PER_LINE) {
+ int j;
+ int this_line_length = MIN(BYTES_PER_LINE, length - i);
+ int print_offset = 0;
+
+ for (j = 0; j < this_line_length; j++) {
+ int buf_offset = i + j;
+
+ /*
+ * Separate every DUMP_GROUPING bytes by a space.
+ */
+ if (buf_offset % DUMP_GROUPING == 0) {
+ print_offset += printf(" ");
+ }
+
+ /*
+ * Print the two-digit hex value for this byte.
+ */
+ unsigned char hex_print = buf[buf_offset];
+ print_offset += printf("%02x ", hex_print);
+ }
+
+ (void) printf("%*s", ascii_start - print_offset, " ");
+
+ print_ascii_block(buf + i, this_line_length);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *buf = safe_malloc(SPA_MAXBLOCKSIZE);
+ uint64_t drr_record_count[DRR_NUMTYPES] = { 0 };
+ uint64_t total_records = 0;
+ dmu_replay_record_t thedrr;
+ dmu_replay_record_t *drr = &thedrr;
+ struct drr_begin *drrb = &thedrr.drr_u.drr_begin;
+ struct drr_end *drre = &thedrr.drr_u.drr_end;
+ struct drr_object *drro = &thedrr.drr_u.drr_object;
+ struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects;
+ struct drr_write *drrw = &thedrr.drr_u.drr_write;
+ struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref;
+ struct drr_free *drrf = &thedrr.drr_u.drr_free;
+ struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
+ struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded;
+ struct drr_checksum *drrc = &thedrr.drr_u.drr_checksum;
+ char c;
+ boolean_t verbose = B_FALSE;
+ boolean_t very_verbose = B_FALSE;
+ boolean_t first = B_TRUE;
+ /*
+ * dump flag controls whether the contents of any modified data blocks
+ * are printed to the console during processing of the stream. Warning:
+ * for large streams, this can obviously lead to massive prints.
+ */
+ boolean_t dump = B_FALSE;
+ int err;
+ zio_cksum_t zc = { 0 };
+ zio_cksum_t pcksum = { 0 };
+
+ while ((c = getopt(argc, argv, ":vCd")) != -1) {
+ switch (c) {
+ case 'C':
+ do_cksum = B_FALSE;
+ break;
+ case 'v':
+ if (verbose)
+ very_verbose = B_TRUE;
+ verbose = B_TRUE;
+ break;
+ case 'd':
+ dump = B_TRUE;
+ verbose = B_TRUE;
+ very_verbose = B_TRUE;
+ break;
+ case ':':
+ (void) fprintf(stderr,
+ "missing argument for '%c' option\n", optopt);
+ usage();
+ break;
+ case '?':
+ (void) fprintf(stderr, "invalid option '%c'\n",
+ optopt);
+ usage();
+ break;
+ }
+ }
+
+ if (isatty(STDIN_FILENO)) {
+ (void) fprintf(stderr,
+ "Error: Backup stream can not be read "
+ "from a terminal.\n"
+ "You must redirect standard input.\n");
+ exit(1);
+ }
+
+ send_stream = stdin;
+ pcksum = zc;
+ while (read_hdr(drr, &zc)) {
+
+ /*
+ * If this is the first DMU record being processed, check for
+ * the magic bytes and figure out the endian-ness based on them.
+ */
+ if (first) {
+ if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
+ do_byteswap = B_TRUE;
+ if (do_cksum) {
+ ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
+ /*
+ * recalculate header checksum now
+ * that we know it needs to be
+ * byteswapped.
+ */
+ fletcher_4_incremental_byteswap(drr,
+ sizeof (dmu_replay_record_t), &zc);
+ }
+ } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) {
+ (void) fprintf(stderr, "Invalid stream "
+ "(bad magic number)\n");
+ exit(1);
+ }
+ first = B_FALSE;
+ }
+ if (do_byteswap) {
+ drr->drr_type = BSWAP_32(drr->drr_type);
+ drr->drr_payloadlen =
+ BSWAP_32(drr->drr_payloadlen);
+ }
+
+ /*
+ * At this point, the leading fields of the replay record
+ * (drr_type and drr_payloadlen) have been byte-swapped if
+ * necessary, but the rest of the data structure (the
+ * union of type-specific structures) is still in its
+ * original state.
+ */
+ if (drr->drr_type >= DRR_NUMTYPES) {
+ (void) printf("INVALID record found: type 0x%x\n",
+ drr->drr_type);
+ (void) printf("Aborting.\n");
+ exit(1);
+ }
+
+ drr_record_count[drr->drr_type]++;
+ total_records++;
+
+ switch (drr->drr_type) {
+ case DRR_BEGIN:
+ if (do_byteswap) {
+ drrb->drr_magic = BSWAP_64(drrb->drr_magic);
+ drrb->drr_versioninfo =
+ BSWAP_64(drrb->drr_versioninfo);
+ drrb->drr_creation_time =
+ BSWAP_64(drrb->drr_creation_time);
+ drrb->drr_type = BSWAP_32(drrb->drr_type);
+ drrb->drr_flags = BSWAP_32(drrb->drr_flags);
+ drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
+ drrb->drr_fromguid =
+ BSWAP_64(drrb->drr_fromguid);
+ }
+
+ (void) printf("BEGIN record\n");
+ (void) printf("\thdrtype = %lld\n",
+ DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo));
+ (void) printf("\tfeatures = %llx\n",
+ DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo));
+ (void) printf("\tmagic = %llx\n",
+ (u_longlong_t)drrb->drr_magic);
+ (void) printf("\tcreation_time = %llx\n",
+ (u_longlong_t)drrb->drr_creation_time);
+ (void) printf("\ttype = %u\n", drrb->drr_type);
+ (void) printf("\tflags = 0x%x\n", drrb->drr_flags);
+ (void) printf("\ttoguid = %llx\n",
+ (u_longlong_t)drrb->drr_toguid);
+ (void) printf("\tfromguid = %llx\n",
+ (u_longlong_t)drrb->drr_fromguid);
+ (void) printf("\ttoname = %s\n", drrb->drr_toname);
+ if (verbose)
+ (void) printf("\n");
+
+ if (drr->drr_payloadlen != 0) {
+ nvlist_t *nv;
+ int sz = drr->drr_payloadlen;
+
+ if (sz > SPA_MAXBLOCKSIZE) {
+ free(buf);
+ buf = safe_malloc(sz);
+ }
+ (void) ssread(buf, sz, &zc);
+ if (ferror(send_stream))
+ perror("fread");
+ err = nvlist_unpack(buf, sz, &nv, 0);
+ if (err)
+ perror(strerror(err));
+ nvlist_print(stdout, nv);
+ nvlist_free(nv);
+ }
+ break;
+
+ case DRR_END:
+ if (do_byteswap) {
+ drre->drr_checksum.zc_word[0] =
+ BSWAP_64(drre->drr_checksum.zc_word[0]);
+ drre->drr_checksum.zc_word[1] =
+ BSWAP_64(drre->drr_checksum.zc_word[1]);
+ drre->drr_checksum.zc_word[2] =
+ BSWAP_64(drre->drr_checksum.zc_word[2]);
+ drre->drr_checksum.zc_word[3] =
+ BSWAP_64(drre->drr_checksum.zc_word[3]);
+ }
+ /*
+ * We compare against the *previous* checksum
+ * value, because the stored checksum is of
+ * everything before the DRR_END record.
+ */
+ if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum,
+ pcksum)) {
+ (void) printf("Expected checksum differs from "
+ "checksum in stream.\n");
+ (void) printf("Expected checksum = "
+ "%llx/%llx/%llx/%llx\n",
+ pcksum.zc_word[0],
+ pcksum.zc_word[1],
+ pcksum.zc_word[2],
+ pcksum.zc_word[3]);
+ }
+ (void) printf("END checksum = %llx/%llx/%llx/%llx\n",
+ drre->drr_checksum.zc_word[0],
+ drre->drr_checksum.zc_word[1],
+ drre->drr_checksum.zc_word[2],
+ drre->drr_checksum.zc_word[3]);
+
+ ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
+ break;
+
+ case DRR_OBJECT:
+ if (do_byteswap) {
+ drro->drr_object = BSWAP_64(drro->drr_object);
+ drro->drr_type = BSWAP_32(drro->drr_type);
+ drro->drr_bonustype =
+ BSWAP_32(drro->drr_bonustype);
+ drro->drr_blksz = BSWAP_32(drro->drr_blksz);
+ drro->drr_bonuslen =
+ BSWAP_32(drro->drr_bonuslen);
+ drro->drr_toguid = BSWAP_64(drro->drr_toguid);
+ }
+ if (verbose) {
+ (void) printf("OBJECT object = %" PRIu64
+ " type = %u bonustype = %u blksz = %u"
+ " bonuslen = %u dn_slots = %u\n",
+ drro->drr_object,
+ drro->drr_type,
+ drro->drr_bonustype,
+ drro->drr_blksz,
+ drro->drr_bonuslen,
+ drro->drr_dn_slots);
+ }
+ if (drro->drr_bonuslen > 0) {
+ (void) ssread(buf,
+ P2ROUNDUP(drro->drr_bonuslen, 8), &zc);
+ if (dump) {
+ print_block(buf,
+ P2ROUNDUP(drro->drr_bonuslen, 8));
+ }
+ }
+ break;
+
+ case DRR_FREEOBJECTS:
+ if (do_byteswap) {
+ drrfo->drr_firstobj =
+ BSWAP_64(drrfo->drr_firstobj);
+ drrfo->drr_numobjs =
+ BSWAP_64(drrfo->drr_numobjs);
+ drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid);
+ }
+ if (verbose) {
+ (void) printf("FREEOBJECTS firstobj = %llu "
+ "numobjs = %llu\n",
+ (u_longlong_t)drrfo->drr_firstobj,
+ (u_longlong_t)drrfo->drr_numobjs);
+ }
+ break;
+
+ case DRR_WRITE:
+ if (do_byteswap) {
+ drrw->drr_object = BSWAP_64(drrw->drr_object);
+ drrw->drr_type = BSWAP_32(drrw->drr_type);
+ drrw->drr_offset = BSWAP_64(drrw->drr_offset);
+ drrw->drr_logical_size =
+ BSWAP_64(drrw->drr_logical_size);
+ drrw->drr_toguid = BSWAP_64(drrw->drr_toguid);
+ drrw->drr_key.ddk_prop =
+ BSWAP_64(drrw->drr_key.ddk_prop);
+ drrw->drr_compressed_size =
+ BSWAP_64(drrw->drr_compressed_size);
+ }
+
+ uint64_t payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw);
+
+ /*
+ * If this is verbose and/or dump output,
+ * print info on the modified block
+ */
+ if (verbose) {
+ (void) printf("WRITE object = %llu type = %u "
+ "checksum type = %u compression type = %u\n"
+ " offset = %llu logical_size = %llu "
+ "compressed_size = %llu "
+ "payload_size = %llu "
+ "props = %llx\n",
+ (u_longlong_t)drrw->drr_object,
+ drrw->drr_type,
+ drrw->drr_checksumtype,
+ drrw->drr_compressiontype,
+ (u_longlong_t)drrw->drr_offset,
+ (u_longlong_t)drrw->drr_logical_size,
+ (u_longlong_t)drrw->drr_compressed_size,
+ (u_longlong_t)payload_size,
+ (u_longlong_t)drrw->drr_key.ddk_prop);
+ }
+
+ /*
+ * Read the contents of the block in from STDIN to buf
+ */
+ (void) ssread(buf, payload_size, &zc);
+ /*
+ * If in dump mode
+ */
+ if (dump) {
+ print_block(buf, payload_size);
+ }
+ total_write_size += payload_size;
+ break;
+
+ case DRR_WRITE_BYREF:
+ if (do_byteswap) {
+ drrwbr->drr_object =
+ BSWAP_64(drrwbr->drr_object);
+ drrwbr->drr_offset =
+ BSWAP_64(drrwbr->drr_offset);
+ drrwbr->drr_length =
+ BSWAP_64(drrwbr->drr_length);
+ drrwbr->drr_toguid =
+ BSWAP_64(drrwbr->drr_toguid);
+ drrwbr->drr_refguid =
+ BSWAP_64(drrwbr->drr_refguid);
+ drrwbr->drr_refobject =
+ BSWAP_64(drrwbr->drr_refobject);
+ drrwbr->drr_refoffset =
+ BSWAP_64(drrwbr->drr_refoffset);
+ drrwbr->drr_key.ddk_prop =
+ BSWAP_64(drrwbr->drr_key.ddk_prop);
+ }
+ if (verbose) {
+ (void) printf("WRITE_BYREF object = %llu "
+ "checksum type = %u props = %llx\n"
+ " offset = %llu length = %llu\n"
+ "toguid = %llx refguid = %llx\n"
+ " refobject = %llu refoffset = %llu\n",
+ (u_longlong_t)drrwbr->drr_object,
+ drrwbr->drr_checksumtype,
+ (u_longlong_t)drrwbr->drr_key.ddk_prop,
+ (u_longlong_t)drrwbr->drr_offset,
+ (u_longlong_t)drrwbr->drr_length,
+ (u_longlong_t)drrwbr->drr_toguid,
+ (u_longlong_t)drrwbr->drr_refguid,
+ (u_longlong_t)drrwbr->drr_refobject,
+ (u_longlong_t)drrwbr->drr_refoffset);
+ }
+ break;
+
+ case DRR_FREE:
+ if (do_byteswap) {
+ drrf->drr_object = BSWAP_64(drrf->drr_object);
+ drrf->drr_offset = BSWAP_64(drrf->drr_offset);
+ drrf->drr_length = BSWAP_64(drrf->drr_length);
+ }
+ if (verbose) {
+ (void) printf("FREE object = %llu "
+ "offset = %llu length = %lld\n",
+ (u_longlong_t)drrf->drr_object,
+ (u_longlong_t)drrf->drr_offset,
+ (longlong_t)drrf->drr_length);
+ }
+ break;
+ case DRR_SPILL:
+ if (do_byteswap) {
+ drrs->drr_object = BSWAP_64(drrs->drr_object);
+ drrs->drr_length = BSWAP_64(drrs->drr_length);
+ }
+ if (verbose) {
+ (void) printf("SPILL block for object = %llu "
+ "length = %llu\n", drrs->drr_object,
+ drrs->drr_length);
+ }
+ (void) ssread(buf, drrs->drr_length, &zc);
+ if (dump) {
+ print_block(buf, drrs->drr_length);
+ }
+ break;
+ case DRR_WRITE_EMBEDDED:
+ if (do_byteswap) {
+ drrwe->drr_object =
+ BSWAP_64(drrwe->drr_object);
+ drrwe->drr_offset =
+ BSWAP_64(drrwe->drr_offset);
+ drrwe->drr_length =
+ BSWAP_64(drrwe->drr_length);
+ drrwe->drr_toguid =
+ BSWAP_64(drrwe->drr_toguid);
+ drrwe->drr_lsize =
+ BSWAP_32(drrwe->drr_lsize);
+ drrwe->drr_psize =
+ BSWAP_32(drrwe->drr_psize);
+ }
+ if (verbose) {
+ (void) printf("WRITE_EMBEDDED object = %llu "
+ "offset = %llu length = %llu\n"
+ " toguid = %llx comp = %u etype = %u "
+ "lsize = %u psize = %u\n",
+ (u_longlong_t)drrwe->drr_object,
+ (u_longlong_t)drrwe->drr_offset,
+ (u_longlong_t)drrwe->drr_length,
+ (u_longlong_t)drrwe->drr_toguid,
+ drrwe->drr_compression,
+ drrwe->drr_etype,
+ drrwe->drr_lsize,
+ drrwe->drr_psize);
+ }
+ (void) ssread(buf,
+ P2ROUNDUP(drrwe->drr_psize, 8), &zc);
+ break;
+ }
+ if (drr->drr_type != DRR_BEGIN && very_verbose) {
+ (void) printf(" checksum = %llx/%llx/%llx/%llx\n",
+ (longlong_t)drrc->drr_checksum.zc_word[0],
+ (longlong_t)drrc->drr_checksum.zc_word[1],
+ (longlong_t)drrc->drr_checksum.zc_word[2],
+ (longlong_t)drrc->drr_checksum.zc_word[3]);
+ }
+ pcksum = zc;
+ }
+ free(buf);
+
+ /* Print final summary */
+
+ (void) printf("SUMMARY:\n");
+ (void) printf("\tTotal DRR_BEGIN records = %lld\n",
+ (u_longlong_t)drr_record_count[DRR_BEGIN]);
+ (void) printf("\tTotal DRR_END records = %lld\n",
+ (u_longlong_t)drr_record_count[DRR_END]);
+ (void) printf("\tTotal DRR_OBJECT records = %lld\n",
+ (u_longlong_t)drr_record_count[DRR_OBJECT]);
+ (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n",
+ (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]);
+ (void) printf("\tTotal DRR_WRITE records = %lld\n",
+ (u_longlong_t)drr_record_count[DRR_WRITE]);
+ (void) printf("\tTotal DRR_WRITE_BYREF records = %lld\n",
+ (u_longlong_t)drr_record_count[DRR_WRITE_BYREF]);
+ (void) printf("\tTotal DRR_WRITE_EMBEDDED records = %lld\n",
+ (u_longlong_t)drr_record_count[DRR_WRITE_EMBEDDED]);
+ (void) printf("\tTotal DRR_FREE records = %lld\n",
+ (u_longlong_t)drr_record_count[DRR_FREE]);
+ (void) printf("\tTotal DRR_SPILL records = %lld\n",
+ (u_longlong_t)drr_record_count[DRR_SPILL]);
+ (void) printf("\tTotal records = %lld\n",
+ (u_longlong_t)total_records);
+ (void) printf("\tTotal write size = %lld (0x%llx)\n",
+ (u_longlong_t)total_write_size, (u_longlong_t)total_write_size);
+ (void) printf("\tTotal stream length = %lld (0x%llx)\n",
+ (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len);
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/ztest/ztest.c b/cddl/contrib/opensolaris/cmd/ztest/ztest.c
new file mode 100644
index 000000000000..be2f2cdd029f
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/ztest/ztest.c
@@ -0,0 +1,7135 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2017 Joyent, Inc.
+ * Copyright (c) 2017, Intel Corporation.
+ * Copyright 2017 RackTop Systems.
+ */
+
+/*
+ * The objective of this program is to provide a DMU/ZAP/SPA stress test
+ * that runs entirely in userland, is easy to use, and easy to extend.
+ *
+ * The overall design of the ztest program is as follows:
+ *
+ * (1) For each major functional area (e.g. adding vdevs to a pool,
+ * creating and destroying datasets, reading and writing objects, etc)
+ * we have a simple routine to test that functionality. These
+ * individual routines do not have to do anything "stressful".
+ *
+ * (2) We turn these simple functionality tests into a stress test by
+ * running them all in parallel, with as many threads as desired,
+ * and spread across as many datasets, objects, and vdevs as desired.
+ *
+ * (3) While all this is happening, we inject faults into the pool to
+ * verify that self-healing data really works.
+ *
+ * (4) Every time we open a dataset, we change its checksum and compression
+ * functions. Thus even individual objects vary from block to block
+ * in which checksum they use and whether they're compressed.
+ *
+ * (5) To verify that we never lose on-disk consistency after a crash,
+ * we run the entire test in a child of the main process.
+ * At random times, the child self-immolates with a SIGKILL.
+ * This is the software equivalent of pulling the power cord.
+ * The parent then runs the test again, using the existing
+ * storage pool, as many times as desired. If backwards compatibility
+ * testing is enabled ztest will sometimes run the "older" version
+ * of ztest after a SIGKILL.
+ *
+ * (6) To verify that we don't have future leaks or temporal incursions,
+ * many of the functional tests record the transaction group number
+ * as part of their data. When reading old data, they verify that
+ * the transaction group number is less than the current, open txg.
+ * If you add a new test, please do this if applicable.
+ *
+ * When run with no arguments, ztest runs for about five minutes and
+ * produces no output if successful. To get a little bit of information,
+ * specify -V. To get more information, specify -VV, and so on.
+ *
+ * To turn this into an overnight stress test, use -T to specify run time.
+ *
+ * You can ask more more vdevs [-v], datasets [-d], or threads [-t]
+ * to increase the pool capacity, fanout, and overall stress level.
+ *
+ * Use the -k option to set the desired frequency of kills.
+ *
+ * When ztest invokes itself it passes all relevant information through a
+ * temporary file which is mmap-ed in the child process. This allows shared
+ * memory to survive the exec syscall. The ztest_shared_hdr_t struct is always
+ * stored at offset 0 of this file and contains information on the size and
+ * number of shared structures in the file. The information stored in this file
+ * must remain backwards compatible with older versions of ztest so that
+ * ztest can invoke them during backwards compatibility testing (-B).
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/txg.h>
+#include <sys/dbuf.h>
+#include <sys/zap.h>
+#include <sys/dmu_objset.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/zio.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+#include <sys/vdev_impl.h>
+#include <sys/vdev_file.h>
+#include <sys/vdev_initialize.h>
+#include <sys/spa_impl.h>
+#include <sys/metaslab_impl.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_destroy.h>
+#include <sys/dsl_scan.h>
+#include <sys/zio_checksum.h>
+#include <sys/refcount.h>
+#include <sys/zfeature.h>
+#include <sys/dsl_userhold.h>
+#include <sys/abd.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <umem.h>
+#include <dlfcn.h>
+#include <ctype.h>
+#include <math.h>
+#include <errno.h>
+#include <sys/fs/zfs.h>
+#include <libnvpair.h>
+#include <libzfs.h>
+#include <libcmdutils.h>
+
+static int ztest_fd_data = -1;
+static int ztest_fd_rand = -1;
+
+typedef struct ztest_shared_hdr {
+ uint64_t zh_hdr_size;
+ uint64_t zh_opts_size;
+ uint64_t zh_size;
+ uint64_t zh_stats_size;
+ uint64_t zh_stats_count;
+ uint64_t zh_ds_size;
+ uint64_t zh_ds_count;
+} ztest_shared_hdr_t;
+
+static ztest_shared_hdr_t *ztest_shared_hdr;
+
+enum ztest_class_state {
+ ZTEST_VDEV_CLASS_OFF,
+ ZTEST_VDEV_CLASS_ON,
+ ZTEST_VDEV_CLASS_RND
+};
+
+typedef struct ztest_shared_opts {
+ char zo_pool[ZFS_MAX_DATASET_NAME_LEN];
+ char zo_dir[ZFS_MAX_DATASET_NAME_LEN];
+ char zo_alt_ztest[MAXNAMELEN];
+ char zo_alt_libpath[MAXNAMELEN];
+ uint64_t zo_vdevs;
+ uint64_t zo_vdevtime;
+ size_t zo_vdev_size;
+ int zo_ashift;
+ int zo_mirrors;
+ int zo_raidz;
+ int zo_raidz_parity;
+ int zo_datasets;
+ int zo_threads;
+ uint64_t zo_passtime;
+ uint64_t zo_killrate;
+ int zo_verbose;
+ int zo_init;
+ uint64_t zo_time;
+ uint64_t zo_maxloops;
+ uint64_t zo_metaslab_force_ganging;
+ int zo_mmp_test;
+ int zo_special_vdevs;
+} ztest_shared_opts_t;
+
+static const ztest_shared_opts_t ztest_opts_defaults = {
+ .zo_pool = { 'z', 't', 'e', 's', 't', '\0' },
+ .zo_dir = { '/', 't', 'm', 'p', '\0' },
+ .zo_alt_ztest = { '\0' },
+ .zo_alt_libpath = { '\0' },
+ .zo_vdevs = 5,
+ .zo_ashift = SPA_MINBLOCKSHIFT,
+ .zo_mirrors = 2,
+ .zo_raidz = 4,
+ .zo_raidz_parity = 1,
+ .zo_vdev_size = SPA_MINDEVSIZE * 4, /* 256m default size */
+ .zo_datasets = 7,
+ .zo_threads = 23,
+ .zo_passtime = 60, /* 60 seconds */
+ .zo_killrate = 70, /* 70% kill rate */
+ .zo_verbose = 0,
+ .zo_mmp_test = 0,
+ .zo_init = 1,
+ .zo_time = 300, /* 5 minutes */
+ .zo_maxloops = 50, /* max loops during spa_freeze() */
+ .zo_metaslab_force_ganging = 32 << 10,
+ .zo_special_vdevs = ZTEST_VDEV_CLASS_RND,
+};
+
+extern uint64_t metaslab_force_ganging;
+extern uint64_t metaslab_df_alloc_threshold;
+extern uint64_t zfs_deadman_synctime_ms;
+extern int metaslab_preload_limit;
+extern boolean_t zfs_compressed_arc_enabled;
+extern boolean_t zfs_abd_scatter_enabled;
+extern int dmu_object_alloc_chunk_shift;
+extern boolean_t zfs_force_some_double_word_sm_entries;
+extern unsigned long zfs_reconstruct_indirect_damage_fraction;
+
+static ztest_shared_opts_t *ztest_shared_opts;
+static ztest_shared_opts_t ztest_opts;
+
+typedef struct ztest_shared_ds {
+ uint64_t zd_seq;
+} ztest_shared_ds_t;
+
+static ztest_shared_ds_t *ztest_shared_ds;
+#define ZTEST_GET_SHARED_DS(d) (&ztest_shared_ds[d])
+
+#define BT_MAGIC 0x123456789abcdefULL
+#define MAXFAULTS() \
+ (MAX(zs->zs_mirrors, 1) * (ztest_opts.zo_raidz_parity + 1) - 1)
+
+enum ztest_io_type {
+ ZTEST_IO_WRITE_TAG,
+ ZTEST_IO_WRITE_PATTERN,
+ ZTEST_IO_WRITE_ZEROES,
+ ZTEST_IO_TRUNCATE,
+ ZTEST_IO_SETATTR,
+ ZTEST_IO_REWRITE,
+ ZTEST_IO_TYPES
+};
+
+typedef struct ztest_block_tag {
+ uint64_t bt_magic;
+ uint64_t bt_objset;
+ uint64_t bt_object;
+ uint64_t bt_dnodesize;
+ uint64_t bt_offset;
+ uint64_t bt_gen;
+ uint64_t bt_txg;
+ uint64_t bt_crtxg;
+} ztest_block_tag_t;
+
+typedef struct bufwad {
+ uint64_t bw_index;
+ uint64_t bw_txg;
+ uint64_t bw_data;
+} bufwad_t;
+
+/*
+ * It would be better to use a rangelock_t per object. Unfortunately
+ * the rangelock_t is not a drop-in replacement for rl_t, because we
+ * still need to map from object ID to rangelock_t.
+ */
+typedef enum {
+ RL_READER,
+ RL_WRITER,
+ RL_APPEND
+} rl_type_t;
+
+typedef struct rll {
+ void *rll_writer;
+ int rll_readers;
+ kmutex_t rll_lock;
+ kcondvar_t rll_cv;
+} rll_t;
+
+typedef struct rl {
+ uint64_t rl_object;
+ uint64_t rl_offset;
+ uint64_t rl_size;
+ rll_t *rl_lock;
+} rl_t;
+
+#define ZTEST_RANGE_LOCKS 64
+#define ZTEST_OBJECT_LOCKS 64
+
+/*
+ * Object descriptor. Used as a template for object lookup/create/remove.
+ */
+typedef struct ztest_od {
+ uint64_t od_dir;
+ uint64_t od_object;
+ dmu_object_type_t od_type;
+ dmu_object_type_t od_crtype;
+ uint64_t od_blocksize;
+ uint64_t od_crblocksize;
+ uint64_t od_crdnodesize;
+ uint64_t od_gen;
+ uint64_t od_crgen;
+ char od_name[ZFS_MAX_DATASET_NAME_LEN];
+} ztest_od_t;
+
+/*
+ * Per-dataset state.
+ */
+typedef struct ztest_ds {
+ ztest_shared_ds_t *zd_shared;
+ objset_t *zd_os;
+ krwlock_t zd_zilog_lock;
+ zilog_t *zd_zilog;
+ ztest_od_t *zd_od; /* debugging aid */
+ char zd_name[ZFS_MAX_DATASET_NAME_LEN];
+ kmutex_t zd_dirobj_lock;
+ rll_t zd_object_lock[ZTEST_OBJECT_LOCKS];
+ rll_t zd_range_lock[ZTEST_RANGE_LOCKS];
+} ztest_ds_t;
+
+/*
+ * Per-iteration state.
+ */
+typedef void ztest_func_t(ztest_ds_t *zd, uint64_t id);
+
+typedef struct ztest_info {
+ ztest_func_t *zi_func; /* test function */
+ uint64_t zi_iters; /* iterations per execution */
+ uint64_t *zi_interval; /* execute every <interval> seconds */
+} ztest_info_t;
+
+typedef struct ztest_shared_callstate {
+ uint64_t zc_count; /* per-pass count */
+ uint64_t zc_time; /* per-pass time */
+ uint64_t zc_next; /* next time to call this function */
+} ztest_shared_callstate_t;
+
+static ztest_shared_callstate_t *ztest_shared_callstate;
+#define ZTEST_GET_SHARED_CALLSTATE(c) (&ztest_shared_callstate[c])
+
+/*
+ * Note: these aren't static because we want dladdr() to work.
+ */
+ztest_func_t ztest_dmu_read_write;
+ztest_func_t ztest_dmu_write_parallel;
+ztest_func_t ztest_dmu_object_alloc_free;
+ztest_func_t ztest_dmu_object_next_chunk;
+ztest_func_t ztest_dmu_commit_callbacks;
+ztest_func_t ztest_zap;
+ztest_func_t ztest_zap_parallel;
+ztest_func_t ztest_zil_commit;
+ztest_func_t ztest_zil_remount;
+ztest_func_t ztest_dmu_read_write_zcopy;
+ztest_func_t ztest_dmu_objset_create_destroy;
+ztest_func_t ztest_dmu_prealloc;
+ztest_func_t ztest_fzap;
+ztest_func_t ztest_dmu_snapshot_create_destroy;
+ztest_func_t ztest_dsl_prop_get_set;
+ztest_func_t ztest_spa_prop_get_set;
+ztest_func_t ztest_spa_create_destroy;
+ztest_func_t ztest_fault_inject;
+ztest_func_t ztest_ddt_repair;
+ztest_func_t ztest_dmu_snapshot_hold;
+ztest_func_t ztest_mmp_enable_disable;
+ztest_func_t ztest_scrub;
+ztest_func_t ztest_dsl_dataset_promote_busy;
+ztest_func_t ztest_vdev_attach_detach;
+ztest_func_t ztest_vdev_LUN_growth;
+ztest_func_t ztest_vdev_add_remove;
+ztest_func_t ztest_vdev_class_add;
+ztest_func_t ztest_vdev_aux_add_remove;
+ztest_func_t ztest_split_pool;
+ztest_func_t ztest_reguid;
+ztest_func_t ztest_spa_upgrade;
+ztest_func_t ztest_device_removal;
+ztest_func_t ztest_remap_blocks;
+ztest_func_t ztest_spa_checkpoint_create_discard;
+ztest_func_t ztest_initialize;
+ztest_func_t ztest_verify_dnode_bt;
+
+uint64_t zopt_always = 0ULL * NANOSEC; /* all the time */
+uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */
+uint64_t zopt_often = 1ULL * NANOSEC; /* every second */
+uint64_t zopt_sometimes = 10ULL * NANOSEC; /* every 10 seconds */
+uint64_t zopt_rarely = 60ULL * NANOSEC; /* every 60 seconds */
+
+ztest_info_t ztest_info[] = {
+ { ztest_dmu_read_write, 1, &zopt_always },
+ { ztest_dmu_write_parallel, 10, &zopt_always },
+ { ztest_dmu_object_alloc_free, 1, &zopt_always },
+ { ztest_dmu_object_next_chunk, 1, &zopt_sometimes },
+ { ztest_dmu_commit_callbacks, 1, &zopt_always },
+ { ztest_zap, 30, &zopt_always },
+ { ztest_zap_parallel, 100, &zopt_always },
+ { ztest_split_pool, 1, &zopt_always },
+ { ztest_zil_commit, 1, &zopt_incessant },
+ { ztest_zil_remount, 1, &zopt_sometimes },
+ { ztest_dmu_read_write_zcopy, 1, &zopt_often },
+ { ztest_dmu_objset_create_destroy, 1, &zopt_often },
+ { ztest_dsl_prop_get_set, 1, &zopt_often },
+ { ztest_spa_prop_get_set, 1, &zopt_sometimes },
+#if 0
+ { ztest_dmu_prealloc, 1, &zopt_sometimes },
+#endif
+ { ztest_fzap, 1, &zopt_sometimes },
+ { ztest_dmu_snapshot_create_destroy, 1, &zopt_sometimes },
+ { ztest_spa_create_destroy, 1, &zopt_sometimes },
+ { ztest_fault_inject, 1, &zopt_incessant },
+ { ztest_ddt_repair, 1, &zopt_sometimes },
+ { ztest_dmu_snapshot_hold, 1, &zopt_sometimes },
+ { ztest_mmp_enable_disable, 1, &zopt_sometimes },
+ { ztest_reguid, 1, &zopt_rarely },
+ { ztest_scrub, 1, &zopt_often },
+ { ztest_spa_upgrade, 1, &zopt_rarely },
+ { ztest_dsl_dataset_promote_busy, 1, &zopt_rarely },
+ { ztest_vdev_attach_detach, 1, &zopt_incessant },
+ { ztest_vdev_LUN_growth, 1, &zopt_rarely },
+ { ztest_vdev_add_remove, 1,
+ &ztest_opts.zo_vdevtime },
+ { ztest_vdev_class_add, 1,
+ &ztest_opts.zo_vdevtime },
+ { ztest_vdev_aux_add_remove, 1,
+ &ztest_opts.zo_vdevtime },
+ { ztest_device_removal, 1, &zopt_sometimes },
+ { ztest_remap_blocks, 1, &zopt_sometimes },
+ { ztest_spa_checkpoint_create_discard, 1, &zopt_rarely },
+ { ztest_initialize, 1, &zopt_sometimes },
+ { ztest_verify_dnode_bt, 1, &zopt_sometimes }
+};
+
+#define ZTEST_FUNCS (sizeof (ztest_info) / sizeof (ztest_info_t))
+
+/*
+ * The following struct is used to hold a list of uncalled commit callbacks.
+ * The callbacks are ordered by txg number.
+ */
+typedef struct ztest_cb_list {
+ kmutex_t zcl_callbacks_lock;
+ list_t zcl_callbacks;
+} ztest_cb_list_t;
+
+/*
+ * Stuff we need to share writably between parent and child.
+ */
+typedef struct ztest_shared {
+ boolean_t zs_do_init;
+ hrtime_t zs_proc_start;
+ hrtime_t zs_proc_stop;
+ hrtime_t zs_thread_start;
+ hrtime_t zs_thread_stop;
+ hrtime_t zs_thread_kill;
+ uint64_t zs_enospc_count;
+ uint64_t zs_vdev_next_leaf;
+ uint64_t zs_vdev_aux;
+ uint64_t zs_alloc;
+ uint64_t zs_space;
+ uint64_t zs_splits;
+ uint64_t zs_mirrors;
+ uint64_t zs_metaslab_sz;
+ uint64_t zs_metaslab_df_alloc_threshold;
+ uint64_t zs_guid;
+} ztest_shared_t;
+
+#define ID_PARALLEL -1ULL
+
+static char ztest_dev_template[] = "%s/%s.%llua";
+static char ztest_aux_template[] = "%s/%s.%s.%llu";
+ztest_shared_t *ztest_shared;
+
+static spa_t *ztest_spa = NULL;
+static ztest_ds_t *ztest_ds;
+
+static kmutex_t ztest_vdev_lock;
+static boolean_t ztest_device_removal_active = B_FALSE;
+static kmutex_t ztest_checkpoint_lock;
+
+/*
+ * The ztest_name_lock protects the pool and dataset namespace used by
+ * the individual tests. To modify the namespace, consumers must grab
+ * this lock as writer. Grabbing the lock as reader will ensure that the
+ * namespace does not change while the lock is held.
+ */
+static krwlock_t ztest_name_lock;
+
+static boolean_t ztest_dump_core = B_TRUE;
+static boolean_t ztest_exiting;
+
+/* Global commit callback list */
+static ztest_cb_list_t zcl;
+
+enum ztest_object {
+ ZTEST_META_DNODE = 0,
+ ZTEST_DIROBJ,
+ ZTEST_OBJECTS
+};
+
+static void usage(boolean_t) __NORETURN;
+
+/*
+ * These libumem hooks provide a reasonable set of defaults for the allocator's
+ * debugging facilities.
+ */
+const char *
+_umem_debug_init()
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+
+#define FATAL_MSG_SZ 1024
+
+char *fatal_msg;
+
+static void
+fatal(int do_perror, char *message, ...)
+{
+ va_list args;
+ int save_errno = errno;
+ char buf[FATAL_MSG_SZ];
+
+ (void) fflush(stdout);
+
+ va_start(args, message);
+ (void) sprintf(buf, "ztest: ");
+ /* LINTED */
+ (void) vsprintf(buf + strlen(buf), message, args);
+ va_end(args);
+ if (do_perror) {
+ (void) snprintf(buf + strlen(buf), FATAL_MSG_SZ - strlen(buf),
+ ": %s", strerror(save_errno));
+ }
+ (void) fprintf(stderr, "%s\n", buf);
+ fatal_msg = buf; /* to ease debugging */
+ if (ztest_dump_core)
+ abort();
+ exit(3);
+}
+
+static int
+str2shift(const char *buf)
+{
+ const char *ends = "BKMGTPEZ";
+ int i;
+
+ if (buf[0] == '\0')
+ return (0);
+ for (i = 0; i < strlen(ends); i++) {
+ if (toupper(buf[0]) == ends[i])
+ break;
+ }
+ if (i == strlen(ends)) {
+ (void) fprintf(stderr, "ztest: invalid bytes suffix: %s\n",
+ buf);
+ usage(B_FALSE);
+ }
+ if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0')) {
+ return (10*i);
+ }
+ (void) fprintf(stderr, "ztest: invalid bytes suffix: %s\n", buf);
+ usage(B_FALSE);
+ /* NOTREACHED */
+}
+
+static uint64_t
+nicenumtoull(const char *buf)
+{
+ char *end;
+ uint64_t val;
+
+ val = strtoull(buf, &end, 0);
+ if (end == buf) {
+ (void) fprintf(stderr, "ztest: bad numeric value: %s\n", buf);
+ usage(B_FALSE);
+ } else if (end[0] == '.') {
+ double fval = strtod(buf, &end);
+ fval *= pow(2, str2shift(end));
+ if (fval > UINT64_MAX) {
+ (void) fprintf(stderr, "ztest: value too large: %s\n",
+ buf);
+ usage(B_FALSE);
+ }
+ val = (uint64_t)fval;
+ } else {
+ int shift = str2shift(end);
+ if (shift >= 64 || (val << shift) >> shift != val) {
+ (void) fprintf(stderr, "ztest: value too large: %s\n",
+ buf);
+ usage(B_FALSE);
+ }
+ val <<= shift;
+ }
+ return (val);
+}
+
+static void
+usage(boolean_t requested)
+{
+ const ztest_shared_opts_t *zo = &ztest_opts_defaults;
+
+ char nice_vdev_size[NN_NUMBUF_SZ];
+ char nice_force_ganging[NN_NUMBUF_SZ];
+ FILE *fp = requested ? stdout : stderr;
+
+ nicenum(zo->zo_vdev_size, nice_vdev_size, sizeof (nice_vdev_size));
+ nicenum(zo->zo_metaslab_force_ganging, nice_force_ganging,
+ sizeof (nice_force_ganging));
+
+ (void) fprintf(fp, "Usage: %s\n"
+ "\t[-v vdevs (default: %llu)]\n"
+ "\t[-s size_of_each_vdev (default: %s)]\n"
+ "\t[-a alignment_shift (default: %d)] use 0 for random\n"
+ "\t[-m mirror_copies (default: %d)]\n"
+ "\t[-r raidz_disks (default: %d)]\n"
+ "\t[-R raidz_parity (default: %d)]\n"
+ "\t[-d datasets (default: %d)]\n"
+ "\t[-t threads (default: %d)]\n"
+ "\t[-g gang_block_threshold (default: %s)]\n"
+ "\t[-i init_count (default: %d)] initialize pool i times\n"
+ "\t[-k kill_percentage (default: %llu%%)]\n"
+ "\t[-p pool_name (default: %s)]\n"
+ "\t[-f dir (default: %s)] file directory for vdev files\n"
+ "\t[-M] Multi-host simulate pool imported on remote host\n"
+ "\t[-V] verbose (use multiple times for ever more blather)\n"
+ "\t[-E] use existing pool instead of creating new one\n"
+ "\t[-T time (default: %llu sec)] total run time\n"
+ "\t[-F freezeloops (default: %llu)] max loops in spa_freeze()\n"
+ "\t[-P passtime (default: %llu sec)] time per pass\n"
+ "\t[-B alt_ztest (default: <none>)] alternate ztest path\n"
+ "\t[-C vdev class state (default: random)] special=on|off|random\n"
+ "\t[-o variable=value] ... set global variable to an unsigned\n"
+ "\t 32-bit integer value\n"
+ "\t[-h] (print help)\n"
+ "",
+ zo->zo_pool,
+ (u_longlong_t)zo->zo_vdevs, /* -v */
+ nice_vdev_size, /* -s */
+ zo->zo_ashift, /* -a */
+ zo->zo_mirrors, /* -m */
+ zo->zo_raidz, /* -r */
+ zo->zo_raidz_parity, /* -R */
+ zo->zo_datasets, /* -d */
+ zo->zo_threads, /* -t */
+ nice_force_ganging, /* -g */
+ zo->zo_init, /* -i */
+ (u_longlong_t)zo->zo_killrate, /* -k */
+ zo->zo_pool, /* -p */
+ zo->zo_dir, /* -f */
+ (u_longlong_t)zo->zo_time, /* -T */
+ (u_longlong_t)zo->zo_maxloops, /* -F */
+ (u_longlong_t)zo->zo_passtime);
+ exit(requested ? 0 : 1);
+}
+
+
+static void
+ztest_parse_name_value(const char *input, ztest_shared_opts_t *zo)
+{
+ char name[32];
+ char *value;
+ int state = ZTEST_VDEV_CLASS_RND;
+
+ (void) strlcpy(name, input, sizeof (name));
+
+ value = strchr(name, '=');
+ if (value == NULL) {
+ (void) fprintf(stderr, "missing value in property=value "
+ "'-C' argument (%s)\n", input);
+ usage(B_FALSE);
+ }
+ *(value) = '\0';
+ value++;
+
+ if (strcmp(value, "on") == 0) {
+ state = ZTEST_VDEV_CLASS_ON;
+ } else if (strcmp(value, "off") == 0) {
+ state = ZTEST_VDEV_CLASS_OFF;
+ } else if (strcmp(value, "random") == 0) {
+ state = ZTEST_VDEV_CLASS_RND;
+ } else {
+ (void) fprintf(stderr, "invalid property value '%s'\n", value);
+ usage(B_FALSE);
+ }
+
+ if (strcmp(name, "special") == 0) {
+ zo->zo_special_vdevs = state;
+ } else {
+ (void) fprintf(stderr, "invalid property name '%s'\n", name);
+ usage(B_FALSE);
+ }
+ if (zo->zo_verbose >= 3)
+ (void) printf("%s vdev state is '%s'\n", name, value);
+}
+
+static void
+process_options(int argc, char **argv)
+{
+ char *path;
+ ztest_shared_opts_t *zo = &ztest_opts;
+
+ int opt;
+ uint64_t value;
+ char altdir[MAXNAMELEN] = { 0 };
+
+ bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
+
+ while ((opt = getopt(argc, argv,
+ "v:s:a:m:r:R:d:t:g:i:k:p:f:MVET:P:hF:B:C:o:")) != EOF) {
+ value = 0;
+ switch (opt) {
+ case 'v':
+ case 's':
+ case 'a':
+ case 'm':
+ case 'r':
+ case 'R':
+ case 'd':
+ case 't':
+ case 'g':
+ case 'i':
+ case 'k':
+ case 'T':
+ case 'P':
+ case 'F':
+ value = nicenumtoull(optarg);
+ }
+ switch (opt) {
+ case 'v':
+ zo->zo_vdevs = value;
+ break;
+ case 's':
+ zo->zo_vdev_size = MAX(SPA_MINDEVSIZE, value);
+ break;
+ case 'a':
+ zo->zo_ashift = value;
+ break;
+ case 'm':
+ zo->zo_mirrors = value;
+ break;
+ case 'r':
+ zo->zo_raidz = MAX(1, value);
+ break;
+ case 'R':
+ zo->zo_raidz_parity = MIN(MAX(value, 1), 3);
+ break;
+ case 'd':
+ zo->zo_datasets = MAX(1, value);
+ break;
+ case 't':
+ zo->zo_threads = MAX(1, value);
+ break;
+ case 'g':
+ zo->zo_metaslab_force_ganging =
+ MAX(SPA_MINBLOCKSIZE << 1, value);
+ break;
+ case 'i':
+ zo->zo_init = value;
+ break;
+ case 'k':
+ zo->zo_killrate = value;
+ break;
+ case 'p':
+ (void) strlcpy(zo->zo_pool, optarg,
+ sizeof (zo->zo_pool));
+ break;
+ case 'f':
+ path = realpath(optarg, NULL);
+ if (path == NULL) {
+ (void) fprintf(stderr, "error: %s: %s\n",
+ optarg, strerror(errno));
+ usage(B_FALSE);
+ } else {
+ (void) strlcpy(zo->zo_dir, path,
+ sizeof (zo->zo_dir));
+ }
+ break;
+ case 'M':
+ zo->zo_mmp_test = 1;
+ break;
+ case 'V':
+ zo->zo_verbose++;
+ break;
+ case 'E':
+ zo->zo_init = 0;
+ break;
+ case 'T':
+ zo->zo_time = value;
+ break;
+ case 'P':
+ zo->zo_passtime = MAX(1, value);
+ break;
+ case 'F':
+ zo->zo_maxloops = MAX(1, value);
+ break;
+ case 'B':
+ (void) strlcpy(altdir, optarg, sizeof (altdir));
+ break;
+ case 'C':
+ ztest_parse_name_value(optarg, zo);
+ break;
+ case 'o':
+ if (set_global_var(optarg) != 0)
+ usage(B_FALSE);
+ break;
+ case 'h':
+ usage(B_TRUE);
+ break;
+ case '?':
+ default:
+ usage(B_FALSE);
+ break;
+ }
+ }
+
+ zo->zo_raidz_parity = MIN(zo->zo_raidz_parity, zo->zo_raidz - 1);
+
+ zo->zo_vdevtime =
+ (zo->zo_vdevs > 0 ? zo->zo_time * NANOSEC / zo->zo_vdevs :
+ UINT64_MAX >> 2);
+
+ if (strlen(altdir) > 0) {
+ char *cmd;
+ char *realaltdir;
+ char *bin;
+ char *ztest;
+ char *isa;
+ int isalen;
+
+ cmd = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+ realaltdir = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+
+ VERIFY(NULL != realpath(getexecname(), cmd));
+ if (0 != access(altdir, F_OK)) {
+ ztest_dump_core = B_FALSE;
+ fatal(B_TRUE, "invalid alternate ztest path: %s",
+ altdir);
+ }
+ VERIFY(NULL != realpath(altdir, realaltdir));
+
+ /*
+ * 'cmd' should be of the form "<anything>/usr/bin/<isa>/ztest".
+ * We want to extract <isa> to determine if we should use
+ * 32 or 64 bit binaries.
+ */
+ bin = strstr(cmd, "/usr/bin/");
+ ztest = strstr(bin, "/ztest");
+ isa = bin + 9;
+ isalen = ztest - isa;
+ (void) snprintf(zo->zo_alt_ztest, sizeof (zo->zo_alt_ztest),
+ "%s/usr/bin/%.*s/ztest", realaltdir, isalen, isa);
+ (void) snprintf(zo->zo_alt_libpath, sizeof (zo->zo_alt_libpath),
+ "%s/usr/lib/%.*s", realaltdir, isalen, isa);
+
+ if (0 != access(zo->zo_alt_ztest, X_OK)) {
+ ztest_dump_core = B_FALSE;
+ fatal(B_TRUE, "invalid alternate ztest: %s",
+ zo->zo_alt_ztest);
+ } else if (0 != access(zo->zo_alt_libpath, X_OK)) {
+ ztest_dump_core = B_FALSE;
+ fatal(B_TRUE, "invalid alternate lib directory %s",
+ zo->zo_alt_libpath);
+ }
+
+ umem_free(cmd, MAXPATHLEN);
+ umem_free(realaltdir, MAXPATHLEN);
+ }
+}
+
+static void
+ztest_kill(ztest_shared_t *zs)
+{
+ zs->zs_alloc = metaslab_class_get_alloc(spa_normal_class(ztest_spa));
+ zs->zs_space = metaslab_class_get_space(spa_normal_class(ztest_spa));
+
+ /*
+ * Before we kill off ztest, make sure that the config is updated.
+ * See comment above spa_write_cachefile().
+ */
+ mutex_enter(&spa_namespace_lock);
+ spa_write_cachefile(ztest_spa, B_FALSE, B_FALSE);
+ mutex_exit(&spa_namespace_lock);
+
+ zfs_dbgmsg_print(FTAG);
+ (void) kill(getpid(), SIGKILL);
+}
+
+static uint64_t
+ztest_random(uint64_t range)
+{
+ uint64_t r;
+
+ ASSERT3S(ztest_fd_rand, >=, 0);
+
+ if (range == 0)
+ return (0);
+
+ if (read(ztest_fd_rand, &r, sizeof (r)) != sizeof (r))
+ fatal(1, "short read from /dev/urandom");
+
+ return (r % range);
+}
+
+/* ARGSUSED */
+static void
+ztest_record_enospc(const char *s)
+{
+ ztest_shared->zs_enospc_count++;
+}
+
+static uint64_t
+ztest_get_ashift(void)
+{
+ if (ztest_opts.zo_ashift == 0)
+ return (SPA_MINBLOCKSHIFT + ztest_random(5));
+ return (ztest_opts.zo_ashift);
+}
+
+static nvlist_t *
+make_vdev_file(char *path, char *aux, char *pool, size_t size, uint64_t ashift)
+{
+ char pathbuf[MAXPATHLEN];
+ uint64_t vdev;
+ nvlist_t *file;
+
+ if (ashift == 0)
+ ashift = ztest_get_ashift();
+
+ if (path == NULL) {
+ path = pathbuf;
+
+ if (aux != NULL) {
+ vdev = ztest_shared->zs_vdev_aux;
+ (void) snprintf(path, sizeof (pathbuf),
+ ztest_aux_template, ztest_opts.zo_dir,
+ pool == NULL ? ztest_opts.zo_pool : pool,
+ aux, vdev);
+ } else {
+ vdev = ztest_shared->zs_vdev_next_leaf++;
+ (void) snprintf(path, sizeof (pathbuf),
+ ztest_dev_template, ztest_opts.zo_dir,
+ pool == NULL ? ztest_opts.zo_pool : pool, vdev);
+ }
+ }
+
+ if (size != 0) {
+ int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
+ if (fd == -1)
+ fatal(1, "can't open %s", path);
+ if (ftruncate(fd, size) != 0)
+ fatal(1, "can't ftruncate %s", path);
+ (void) close(fd);
+ }
+
+ VERIFY(nvlist_alloc(&file, NV_UNIQUE_NAME, 0) == 0);
+ VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_TYPE, VDEV_TYPE_FILE) == 0);
+ VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_PATH, path) == 0);
+ VERIFY(nvlist_add_uint64(file, ZPOOL_CONFIG_ASHIFT, ashift) == 0);
+
+ return (file);
+}
+
+static nvlist_t *
+make_vdev_raidz(char *path, char *aux, char *pool, size_t size,
+ uint64_t ashift, int r)
+{
+ nvlist_t *raidz, **child;
+ int c;
+
+ if (r < 2)
+ return (make_vdev_file(path, aux, pool, size, ashift));
+ child = umem_alloc(r * sizeof (nvlist_t *), UMEM_NOFAIL);
+
+ for (c = 0; c < r; c++)
+ child[c] = make_vdev_file(path, aux, pool, size, ashift);
+
+ VERIFY(nvlist_alloc(&raidz, NV_UNIQUE_NAME, 0) == 0);
+ VERIFY(nvlist_add_string(raidz, ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_RAIDZ) == 0);
+ VERIFY(nvlist_add_uint64(raidz, ZPOOL_CONFIG_NPARITY,
+ ztest_opts.zo_raidz_parity) == 0);
+ VERIFY(nvlist_add_nvlist_array(raidz, ZPOOL_CONFIG_CHILDREN,
+ child, r) == 0);
+
+ for (c = 0; c < r; c++)
+ nvlist_free(child[c]);
+
+ umem_free(child, r * sizeof (nvlist_t *));
+
+ return (raidz);
+}
+
+static nvlist_t *
+make_vdev_mirror(char *path, char *aux, char *pool, size_t size,
+ uint64_t ashift, int r, int m)
+{
+ nvlist_t *mirror, **child;
+ int c;
+
+ if (m < 1)
+ return (make_vdev_raidz(path, aux, pool, size, ashift, r));
+
+ child = umem_alloc(m * sizeof (nvlist_t *), UMEM_NOFAIL);
+
+ for (c = 0; c < m; c++)
+ child[c] = make_vdev_raidz(path, aux, pool, size, ashift, r);
+
+ VERIFY(nvlist_alloc(&mirror, NV_UNIQUE_NAME, 0) == 0);
+ VERIFY(nvlist_add_string(mirror, ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_MIRROR) == 0);
+ VERIFY(nvlist_add_nvlist_array(mirror, ZPOOL_CONFIG_CHILDREN,
+ child, m) == 0);
+
+ for (c = 0; c < m; c++)
+ nvlist_free(child[c]);
+
+ umem_free(child, m * sizeof (nvlist_t *));
+
+ return (mirror);
+}
+
+static nvlist_t *
+make_vdev_root(char *path, char *aux, char *pool, size_t size, uint64_t ashift,
+ const char *class, int r, int m, int t)
+{
+ nvlist_t *root, **child;
+ int c;
+ boolean_t log;
+
+ ASSERT(t > 0);
+
+ log = (class != NULL && strcmp(class, "log") == 0);
+
+ child = umem_alloc(t * sizeof (nvlist_t *), UMEM_NOFAIL);
+
+ for (c = 0; c < t; c++) {
+ child[c] = make_vdev_mirror(path, aux, pool, size, ashift,
+ r, m);
+ VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ log) == 0);
+
+ if (class != NULL && class[0] != '\0') {
+ ASSERT(m > 1 || log); /* expecting a mirror */
+ VERIFY(nvlist_add_string(child[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, class) == 0);
+ }
+ }
+
+ VERIFY(nvlist_alloc(&root, NV_UNIQUE_NAME, 0) == 0);
+ VERIFY(nvlist_add_string(root, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) == 0);
+ VERIFY(nvlist_add_nvlist_array(root, aux ? aux : ZPOOL_CONFIG_CHILDREN,
+ child, t) == 0);
+
+ for (c = 0; c < t; c++)
+ nvlist_free(child[c]);
+
+ umem_free(child, t * sizeof (nvlist_t *));
+
+ return (root);
+}
+
+/*
+ * Find a random spa version. Returns back a random spa version in the
+ * range [initial_version, SPA_VERSION_FEATURES].
+ */
+static uint64_t
+ztest_random_spa_version(uint64_t initial_version)
+{
+ uint64_t version = initial_version;
+
+ if (version <= SPA_VERSION_BEFORE_FEATURES) {
+ version = version +
+ ztest_random(SPA_VERSION_BEFORE_FEATURES - version + 1);
+ }
+
+ if (version > SPA_VERSION_BEFORE_FEATURES)
+ version = SPA_VERSION_FEATURES;
+
+ ASSERT(SPA_VERSION_IS_SUPPORTED(version));
+ return (version);
+}
+
+static int
+ztest_random_blocksize(void)
+{
+ uint64_t block_shift;
+
+ ASSERT(ztest_spa->spa_max_ashift != 0);
+
+ /*
+ * Choose a block size >= the ashift.
+ * If the SPA supports new MAXBLOCKSIZE, test up to 1MB blocks.
+ */
+ int maxbs = SPA_OLD_MAXBLOCKSHIFT;
+ if (spa_maxblocksize(ztest_spa) == SPA_MAXBLOCKSIZE)
+ maxbs = 20;
+ block_shift = ztest_random(maxbs - ztest_spa->spa_max_ashift + 1);
+ return (1 << (SPA_MINBLOCKSHIFT + block_shift));
+}
+
+static int
+ztest_random_dnodesize(void)
+{
+ int slots;
+ int max_slots = spa_maxdnodesize(ztest_spa) >> DNODE_SHIFT;
+
+ if (max_slots == DNODE_MIN_SLOTS)
+ return (DNODE_MIN_SIZE);
+
+ /*
+ * Weight the random distribution more heavily toward smaller
+ * dnode sizes since that is more likely to reflect real-world
+ * usage.
+ */
+ ASSERT3U(max_slots, >, 4);
+ switch (ztest_random(10)) {
+ case 0:
+ slots = 5 + ztest_random(max_slots - 4);
+ break;
+ case 1 ... 4:
+ slots = 2 + ztest_random(3);
+ break;
+ default:
+ slots = 1;
+ break;
+ }
+
+ return (slots << DNODE_SHIFT);
+}
+
+static int
+ztest_random_ibshift(void)
+{
+ return (DN_MIN_INDBLKSHIFT +
+ ztest_random(DN_MAX_INDBLKSHIFT - DN_MIN_INDBLKSHIFT + 1));
+}
+
+static uint64_t
+ztest_random_vdev_top(spa_t *spa, boolean_t log_ok)
+{
+ uint64_t top;
+ vdev_t *rvd = spa->spa_root_vdev;
+ vdev_t *tvd;
+
+ ASSERT(spa_config_held(spa, SCL_ALL, RW_READER) != 0);
+
+ do {
+ top = ztest_random(rvd->vdev_children);
+ tvd = rvd->vdev_child[top];
+ } while (!vdev_is_concrete(tvd) || (tvd->vdev_islog && !log_ok) ||
+ tvd->vdev_mg == NULL || tvd->vdev_mg->mg_class == NULL);
+
+ return (top);
+}
+
+static uint64_t
+ztest_random_dsl_prop(zfs_prop_t prop)
+{
+ uint64_t value;
+
+ do {
+ value = zfs_prop_random_value(prop, ztest_random(-1ULL));
+ } while (prop == ZFS_PROP_CHECKSUM && value == ZIO_CHECKSUM_OFF);
+
+ return (value);
+}
+
+static int
+ztest_dsl_prop_set_uint64(char *osname, zfs_prop_t prop, uint64_t value,
+ boolean_t inherit)
+{
+ const char *propname = zfs_prop_to_name(prop);
+ const char *valname;
+ char setpoint[MAXPATHLEN];
+ uint64_t curval;
+ int error;
+
+ error = dsl_prop_set_int(osname, propname,
+ (inherit ? ZPROP_SRC_NONE : ZPROP_SRC_LOCAL), value);
+
+ if (error == ENOSPC) {
+ ztest_record_enospc(FTAG);
+ return (error);
+ }
+ ASSERT0(error);
+
+ VERIFY0(dsl_prop_get_integer(osname, propname, &curval, setpoint));
+
+ if (ztest_opts.zo_verbose >= 6) {
+ VERIFY(zfs_prop_index_to_string(prop, curval, &valname) == 0);
+ (void) printf("%s %s = %s at '%s'\n",
+ osname, propname, valname, setpoint);
+ }
+
+ return (error);
+}
+
+static int
+ztest_spa_prop_set_uint64(zpool_prop_t prop, uint64_t value)
+{
+ spa_t *spa = ztest_spa;
+ nvlist_t *props = NULL;
+ int error;
+
+ VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
+ VERIFY(nvlist_add_uint64(props, zpool_prop_to_name(prop), value) == 0);
+
+ error = spa_prop_set(spa, props);
+
+ nvlist_free(props);
+
+ if (error == ENOSPC) {
+ ztest_record_enospc(FTAG);
+ return (error);
+ }
+ ASSERT0(error);
+
+ return (error);
+}
+
+static void
+ztest_rll_init(rll_t *rll)
+{
+ rll->rll_writer = NULL;
+ rll->rll_readers = 0;
+ mutex_init(&rll->rll_lock, NULL, USYNC_THREAD, NULL);
+ cv_init(&rll->rll_cv, NULL, USYNC_THREAD, NULL);
+}
+
+static void
+ztest_rll_destroy(rll_t *rll)
+{
+ ASSERT(rll->rll_writer == NULL);
+ ASSERT(rll->rll_readers == 0);
+ mutex_destroy(&rll->rll_lock);
+ cv_destroy(&rll->rll_cv);
+}
+
+static void
+ztest_rll_lock(rll_t *rll, rl_type_t type)
+{
+ mutex_enter(&rll->rll_lock);
+
+ if (type == RL_READER) {
+ while (rll->rll_writer != NULL)
+ cv_wait(&rll->rll_cv, &rll->rll_lock);
+ rll->rll_readers++;
+ } else {
+ while (rll->rll_writer != NULL || rll->rll_readers)
+ cv_wait(&rll->rll_cv, &rll->rll_lock);
+ rll->rll_writer = curthread;
+ }
+
+ mutex_exit(&rll->rll_lock);
+}
+
+static void
+ztest_rll_unlock(rll_t *rll)
+{
+ mutex_enter(&rll->rll_lock);
+
+ if (rll->rll_writer) {
+ ASSERT(rll->rll_readers == 0);
+ rll->rll_writer = NULL;
+ } else {
+ ASSERT(rll->rll_readers != 0);
+ ASSERT(rll->rll_writer == NULL);
+ rll->rll_readers--;
+ }
+
+ if (rll->rll_writer == NULL && rll->rll_readers == 0)
+ cv_broadcast(&rll->rll_cv);
+
+ mutex_exit(&rll->rll_lock);
+}
+
+static void
+ztest_object_lock(ztest_ds_t *zd, uint64_t object, rl_type_t type)
+{
+ rll_t *rll = &zd->zd_object_lock[object & (ZTEST_OBJECT_LOCKS - 1)];
+
+ ztest_rll_lock(rll, type);
+}
+
+static void
+ztest_object_unlock(ztest_ds_t *zd, uint64_t object)
+{
+ rll_t *rll = &zd->zd_object_lock[object & (ZTEST_OBJECT_LOCKS - 1)];
+
+ ztest_rll_unlock(rll);
+}
+
+static rl_t *
+ztest_range_lock(ztest_ds_t *zd, uint64_t object, uint64_t offset,
+ uint64_t size, rl_type_t type)
+{
+ uint64_t hash = object ^ (offset % (ZTEST_RANGE_LOCKS + 1));
+ rll_t *rll = &zd->zd_range_lock[hash & (ZTEST_RANGE_LOCKS - 1)];
+ rl_t *rl;
+
+ rl = umem_alloc(sizeof (*rl), UMEM_NOFAIL);
+ rl->rl_object = object;
+ rl->rl_offset = offset;
+ rl->rl_size = size;
+ rl->rl_lock = rll;
+
+ ztest_rll_lock(rll, type);
+
+ return (rl);
+}
+
+static void
+ztest_range_unlock(rl_t *rl)
+{
+ rll_t *rll = rl->rl_lock;
+
+ ztest_rll_unlock(rll);
+
+ umem_free(rl, sizeof (*rl));
+}
+
+static void
+ztest_zd_init(ztest_ds_t *zd, ztest_shared_ds_t *szd, objset_t *os)
+{
+ zd->zd_os = os;
+ zd->zd_zilog = dmu_objset_zil(os);
+ zd->zd_shared = szd;
+ dmu_objset_name(os, zd->zd_name);
+
+ if (zd->zd_shared != NULL)
+ zd->zd_shared->zd_seq = 0;
+
+ rw_init(&zd->zd_zilog_lock, NULL, USYNC_THREAD, NULL);
+ mutex_init(&zd->zd_dirobj_lock, NULL, USYNC_THREAD, NULL);
+
+ for (int l = 0; l < ZTEST_OBJECT_LOCKS; l++)
+ ztest_rll_init(&zd->zd_object_lock[l]);
+
+ for (int l = 0; l < ZTEST_RANGE_LOCKS; l++)
+ ztest_rll_init(&zd->zd_range_lock[l]);
+}
+
+static void
+ztest_zd_fini(ztest_ds_t *zd)
+{
+ mutex_destroy(&zd->zd_dirobj_lock);
+
+ for (int l = 0; l < ZTEST_OBJECT_LOCKS; l++)
+ ztest_rll_destroy(&zd->zd_object_lock[l]);
+
+ for (int l = 0; l < ZTEST_RANGE_LOCKS; l++)
+ ztest_rll_destroy(&zd->zd_range_lock[l]);
+}
+
+#define TXG_MIGHTWAIT (ztest_random(10) == 0 ? TXG_NOWAIT : TXG_WAIT)
+
+static uint64_t
+ztest_tx_assign(dmu_tx_t *tx, uint64_t txg_how, const char *tag)
+{
+ uint64_t txg;
+ int error;
+
+ /*
+ * Attempt to assign tx to some transaction group.
+ */
+ error = dmu_tx_assign(tx, txg_how);
+ if (error) {
+ if (error == ERESTART) {
+ ASSERT(txg_how == TXG_NOWAIT);
+ dmu_tx_wait(tx);
+ } else {
+ ASSERT3U(error, ==, ENOSPC);
+ ztest_record_enospc(tag);
+ }
+ dmu_tx_abort(tx);
+ return (0);
+ }
+ txg = dmu_tx_get_txg(tx);
+ ASSERT(txg != 0);
+ return (txg);
+}
+
+static void
+ztest_pattern_set(void *buf, uint64_t size, uint64_t value)
+{
+ uint64_t *ip = buf;
+ uint64_t *ip_end = (uint64_t *)((uintptr_t)buf + (uintptr_t)size);
+
+ while (ip < ip_end)
+ *ip++ = value;
+}
+
+static boolean_t
+ztest_pattern_match(void *buf, uint64_t size, uint64_t value)
+{
+ uint64_t *ip = buf;
+ uint64_t *ip_end = (uint64_t *)((uintptr_t)buf + (uintptr_t)size);
+ uint64_t diff = 0;
+
+ while (ip < ip_end)
+ diff |= (value - *ip++);
+
+ return (diff == 0);
+}
+
+static void
+ztest_bt_generate(ztest_block_tag_t *bt, objset_t *os, uint64_t object,
+ uint64_t dnodesize, uint64_t offset, uint64_t gen, uint64_t txg,
+ uint64_t crtxg)
+{
+ bt->bt_magic = BT_MAGIC;
+ bt->bt_objset = dmu_objset_id(os);
+ bt->bt_object = object;
+ bt->bt_dnodesize = dnodesize;
+ bt->bt_offset = offset;
+ bt->bt_gen = gen;
+ bt->bt_txg = txg;
+ bt->bt_crtxg = crtxg;
+}
+
+static void
+ztest_bt_verify(ztest_block_tag_t *bt, objset_t *os, uint64_t object,
+ uint64_t dnodesize, uint64_t offset, uint64_t gen, uint64_t txg,
+ uint64_t crtxg)
+{
+ ASSERT3U(bt->bt_magic, ==, BT_MAGIC);
+ ASSERT3U(bt->bt_objset, ==, dmu_objset_id(os));
+ ASSERT3U(bt->bt_object, ==, object);
+ ASSERT3U(bt->bt_dnodesize, ==, dnodesize);
+ ASSERT3U(bt->bt_offset, ==, offset);
+ ASSERT3U(bt->bt_gen, <=, gen);
+ ASSERT3U(bt->bt_txg, <=, txg);
+ ASSERT3U(bt->bt_crtxg, ==, crtxg);
+}
+
+static ztest_block_tag_t *
+ztest_bt_bonus(dmu_buf_t *db)
+{
+ dmu_object_info_t doi;
+ ztest_block_tag_t *bt;
+
+ dmu_object_info_from_db(db, &doi);
+ ASSERT3U(doi.doi_bonus_size, <=, db->db_size);
+ ASSERT3U(doi.doi_bonus_size, >=, sizeof (*bt));
+ bt = (void *)((char *)db->db_data + doi.doi_bonus_size - sizeof (*bt));
+
+ return (bt);
+}
+
+/*
+ * Generate a token to fill up unused bonus buffer space. Try to make
+ * it unique to the object, generation, and offset to verify that data
+ * is not getting overwritten by data from other dnodes.
+ */
+#define ZTEST_BONUS_FILL_TOKEN(obj, ds, gen, offset) \
+ (((ds) << 48) | ((gen) << 32) | ((obj) << 8) | (offset))
+
+/*
+ * Fill up the unused bonus buffer region before the block tag with a
+ * verifiable pattern. Filling the whole bonus area with non-zero data
+ * helps ensure that all dnode traversal code properly skips the
+ * interior regions of large dnodes.
+ */
+void
+ztest_fill_unused_bonus(dmu_buf_t *db, void *end, uint64_t obj,
+ objset_t *os, uint64_t gen)
+{
+ uint64_t *bonusp;
+
+ ASSERT(IS_P2ALIGNED((char *)end - (char *)db->db_data, 8));
+
+ for (bonusp = db->db_data; bonusp < (uint64_t *)end; bonusp++) {
+ uint64_t token = ZTEST_BONUS_FILL_TOKEN(obj, dmu_objset_id(os),
+ gen, bonusp - (uint64_t *)db->db_data);
+ *bonusp = token;
+ }
+}
+
+/*
+ * Verify that the unused area of a bonus buffer is filled with the
+ * expected tokens.
+ */
+void
+ztest_verify_unused_bonus(dmu_buf_t *db, void *end, uint64_t obj,
+ objset_t *os, uint64_t gen)
+{
+ uint64_t *bonusp;
+
+ for (bonusp = db->db_data; bonusp < (uint64_t *)end; bonusp++) {
+ uint64_t token = ZTEST_BONUS_FILL_TOKEN(obj, dmu_objset_id(os),
+ gen, bonusp - (uint64_t *)db->db_data);
+ VERIFY3U(*bonusp, ==, token);
+ }
+}
+
+/*
+ * ZIL logging ops
+ */
+
+#define lrz_type lr_mode
+#define lrz_blocksize lr_uid
+#define lrz_ibshift lr_gid
+#define lrz_bonustype lr_rdev
+#define lrz_dnodesize lr_crtime[1]
+
+static void
+ztest_log_create(ztest_ds_t *zd, dmu_tx_t *tx, lr_create_t *lr)
+{
+ char *name = (void *)(lr + 1); /* name follows lr */
+ size_t namesize = strlen(name) + 1;
+ itx_t *itx;
+
+ if (zil_replaying(zd->zd_zilog, tx))
+ return;
+
+ itx = zil_itx_create(TX_CREATE, sizeof (*lr) + namesize);
+ bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+ sizeof (*lr) + namesize - sizeof (lr_t));
+
+ zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+static void
+ztest_log_remove(ztest_ds_t *zd, dmu_tx_t *tx, lr_remove_t *lr, uint64_t object)
+{
+ char *name = (void *)(lr + 1); /* name follows lr */
+ size_t namesize = strlen(name) + 1;
+ itx_t *itx;
+
+ if (zil_replaying(zd->zd_zilog, tx))
+ return;
+
+ itx = zil_itx_create(TX_REMOVE, sizeof (*lr) + namesize);
+ bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+ sizeof (*lr) + namesize - sizeof (lr_t));
+
+ itx->itx_oid = object;
+ zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+static void
+ztest_log_write(ztest_ds_t *zd, dmu_tx_t *tx, lr_write_t *lr)
+{
+ itx_t *itx;
+ itx_wr_state_t write_state = ztest_random(WR_NUM_STATES);
+
+ if (zil_replaying(zd->zd_zilog, tx))
+ return;
+
+ if (lr->lr_length > ZIL_MAX_LOG_DATA)
+ write_state = WR_INDIRECT;
+
+ itx = zil_itx_create(TX_WRITE,
+ sizeof (*lr) + (write_state == WR_COPIED ? lr->lr_length : 0));
+
+ if (write_state == WR_COPIED &&
+ dmu_read(zd->zd_os, lr->lr_foid, lr->lr_offset, lr->lr_length,
+ ((lr_write_t *)&itx->itx_lr) + 1, DMU_READ_NO_PREFETCH) != 0) {
+ zil_itx_destroy(itx);
+ itx = zil_itx_create(TX_WRITE, sizeof (*lr));
+ write_state = WR_NEED_COPY;
+ }
+ itx->itx_private = zd;
+ itx->itx_wr_state = write_state;
+ itx->itx_sync = (ztest_random(8) == 0);
+
+ bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+ sizeof (*lr) - sizeof (lr_t));
+
+ zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+static void
+ztest_log_truncate(ztest_ds_t *zd, dmu_tx_t *tx, lr_truncate_t *lr)
+{
+ itx_t *itx;
+
+ if (zil_replaying(zd->zd_zilog, tx))
+ return;
+
+ itx = zil_itx_create(TX_TRUNCATE, sizeof (*lr));
+ bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+ sizeof (*lr) - sizeof (lr_t));
+
+ itx->itx_sync = B_FALSE;
+ zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+static void
+ztest_log_setattr(ztest_ds_t *zd, dmu_tx_t *tx, lr_setattr_t *lr)
+{
+ itx_t *itx;
+
+ if (zil_replaying(zd->zd_zilog, tx))
+ return;
+
+ itx = zil_itx_create(TX_SETATTR, sizeof (*lr));
+ bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+ sizeof (*lr) - sizeof (lr_t));
+
+ itx->itx_sync = B_FALSE;
+ zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+/*
+ * ZIL replay ops
+ */
+static int
+ztest_replay_create(void *arg1, void *arg2, boolean_t byteswap)
+{
+ ztest_ds_t *zd = arg1;
+ lr_create_t *lr = arg2;
+ char *name = (void *)(lr + 1); /* name follows lr */
+ objset_t *os = zd->zd_os;
+ ztest_block_tag_t *bbt;
+ dmu_buf_t *db;
+ dmu_tx_t *tx;
+ uint64_t txg;
+ int error = 0;
+ int bonuslen;
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ ASSERT(lr->lr_doid == ZTEST_DIROBJ);
+ ASSERT(name[0] != '\0');
+
+ tx = dmu_tx_create(os);
+
+ dmu_tx_hold_zap(tx, lr->lr_doid, B_TRUE, name);
+
+ if (lr->lrz_type == DMU_OT_ZAP_OTHER) {
+ dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, B_TRUE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ }
+
+ txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+ if (txg == 0)
+ return (ENOSPC);
+
+ ASSERT(dmu_objset_zil(os)->zl_replay == !!lr->lr_foid);
+ bonuslen = DN_BONUS_SIZE(lr->lrz_dnodesize);
+
+ if (lr->lrz_type == DMU_OT_ZAP_OTHER) {
+ if (lr->lr_foid == 0) {
+ lr->lr_foid = zap_create_dnsize(os,
+ lr->lrz_type, lr->lrz_bonustype,
+ bonuslen, lr->lrz_dnodesize, tx);
+ } else {
+ error = zap_create_claim_dnsize(os, lr->lr_foid,
+ lr->lrz_type, lr->lrz_bonustype,
+ bonuslen, lr->lrz_dnodesize, tx);
+ }
+ } else {
+ if (lr->lr_foid == 0) {
+ lr->lr_foid = dmu_object_alloc_dnsize(os,
+ lr->lrz_type, 0, lr->lrz_bonustype,
+ bonuslen, lr->lrz_dnodesize, tx);
+ } else {
+ error = dmu_object_claim_dnsize(os, lr->lr_foid,
+ lr->lrz_type, 0, lr->lrz_bonustype,
+ bonuslen, lr->lrz_dnodesize, tx);
+ }
+ }
+
+ if (error) {
+ ASSERT3U(error, ==, EEXIST);
+ ASSERT(zd->zd_zilog->zl_replay);
+ dmu_tx_commit(tx);
+ return (error);
+ }
+
+ ASSERT(lr->lr_foid != 0);
+
+ if (lr->lrz_type != DMU_OT_ZAP_OTHER)
+ VERIFY3U(0, ==, dmu_object_set_blocksize(os, lr->lr_foid,
+ lr->lrz_blocksize, lr->lrz_ibshift, tx));
+
+ VERIFY3U(0, ==, dmu_bonus_hold(os, lr->lr_foid, FTAG, &db));
+ bbt = ztest_bt_bonus(db);
+ dmu_buf_will_dirty(db, tx);
+ ztest_bt_generate(bbt, os, lr->lr_foid, lr->lrz_dnodesize, -1ULL,
+ lr->lr_gen, txg, txg);
+ ztest_fill_unused_bonus(db, bbt, lr->lr_foid, os, lr->lr_gen);
+ dmu_buf_rele(db, FTAG);
+
+ VERIFY3U(0, ==, zap_add(os, lr->lr_doid, name, sizeof (uint64_t), 1,
+ &lr->lr_foid, tx));
+
+ (void) ztest_log_create(zd, tx, lr);
+
+ dmu_tx_commit(tx);
+
+ return (0);
+}
+
+static int
+ztest_replay_remove(void *arg1, void *arg2, boolean_t byteswap)
+{
+ ztest_ds_t *zd = arg1;
+ lr_remove_t *lr = arg2;
+ char *name = (void *)(lr + 1); /* name follows lr */
+ objset_t *os = zd->zd_os;
+ dmu_object_info_t doi;
+ dmu_tx_t *tx;
+ uint64_t object, txg;
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ ASSERT(lr->lr_doid == ZTEST_DIROBJ);
+ ASSERT(name[0] != '\0');
+
+ VERIFY3U(0, ==,
+ zap_lookup(os, lr->lr_doid, name, sizeof (object), 1, &object));
+ ASSERT(object != 0);
+
+ ztest_object_lock(zd, object, RL_WRITER);
+
+ VERIFY3U(0, ==, dmu_object_info(os, object, &doi));
+
+ tx = dmu_tx_create(os);
+
+ dmu_tx_hold_zap(tx, lr->lr_doid, B_FALSE, name);
+ dmu_tx_hold_free(tx, object, 0, DMU_OBJECT_END);
+
+ txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+ if (txg == 0) {
+ ztest_object_unlock(zd, object);
+ return (ENOSPC);
+ }
+
+ if (doi.doi_type == DMU_OT_ZAP_OTHER) {
+ VERIFY3U(0, ==, zap_destroy(os, object, tx));
+ } else {
+ VERIFY3U(0, ==, dmu_object_free(os, object, tx));
+ }
+
+ VERIFY3U(0, ==, zap_remove(os, lr->lr_doid, name, tx));
+
+ (void) ztest_log_remove(zd, tx, lr, object);
+
+ dmu_tx_commit(tx);
+
+ ztest_object_unlock(zd, object);
+
+ return (0);
+}
+
+static int
+ztest_replay_write(void *arg1, void *arg2, boolean_t byteswap)
+{
+ ztest_ds_t *zd = arg1;
+ lr_write_t *lr = arg2;
+ objset_t *os = zd->zd_os;
+ void *data = lr + 1; /* data follows lr */
+ uint64_t offset, length;
+ ztest_block_tag_t *bt = data;
+ ztest_block_tag_t *bbt;
+ uint64_t gen, txg, lrtxg, crtxg;
+ dmu_object_info_t doi;
+ dmu_tx_t *tx;
+ dmu_buf_t *db;
+ arc_buf_t *abuf = NULL;
+ rl_t *rl;
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ offset = lr->lr_offset;
+ length = lr->lr_length;
+
+ /* If it's a dmu_sync() block, write the whole block */
+ if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
+ uint64_t blocksize = BP_GET_LSIZE(&lr->lr_blkptr);
+ if (length < blocksize) {
+ offset -= offset % blocksize;
+ length = blocksize;
+ }
+ }
+
+ if (bt->bt_magic == BSWAP_64(BT_MAGIC))
+ byteswap_uint64_array(bt, sizeof (*bt));
+
+ if (bt->bt_magic != BT_MAGIC)
+ bt = NULL;
+
+ ztest_object_lock(zd, lr->lr_foid, RL_READER);
+ rl = ztest_range_lock(zd, lr->lr_foid, offset, length, RL_WRITER);
+
+ VERIFY3U(0, ==, dmu_bonus_hold(os, lr->lr_foid, FTAG, &db));
+
+ dmu_object_info_from_db(db, &doi);
+
+ bbt = ztest_bt_bonus(db);
+ ASSERT3U(bbt->bt_magic, ==, BT_MAGIC);
+ gen = bbt->bt_gen;
+ crtxg = bbt->bt_crtxg;
+ lrtxg = lr->lr_common.lrc_txg;
+
+ tx = dmu_tx_create(os);
+
+ dmu_tx_hold_write(tx, lr->lr_foid, offset, length);
+
+ if (ztest_random(8) == 0 && length == doi.doi_data_block_size &&
+ P2PHASE(offset, length) == 0)
+ abuf = dmu_request_arcbuf(db, length);
+
+ txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+ if (txg == 0) {
+ if (abuf != NULL)
+ dmu_return_arcbuf(abuf);
+ dmu_buf_rele(db, FTAG);
+ ztest_range_unlock(rl);
+ ztest_object_unlock(zd, lr->lr_foid);
+ return (ENOSPC);
+ }
+
+ if (bt != NULL) {
+ /*
+ * Usually, verify the old data before writing new data --
+ * but not always, because we also want to verify correct
+ * behavior when the data was not recently read into cache.
+ */
+ ASSERT(offset % doi.doi_data_block_size == 0);
+ if (ztest_random(4) != 0) {
+ int prefetch = ztest_random(2) ?
+ DMU_READ_PREFETCH : DMU_READ_NO_PREFETCH;
+ ztest_block_tag_t rbt;
+
+ VERIFY(dmu_read(os, lr->lr_foid, offset,
+ sizeof (rbt), &rbt, prefetch) == 0);
+ if (rbt.bt_magic == BT_MAGIC) {
+ ztest_bt_verify(&rbt, os, lr->lr_foid, 0,
+ offset, gen, txg, crtxg);
+ }
+ }
+
+ /*
+ * Writes can appear to be newer than the bonus buffer because
+ * the ztest_get_data() callback does a dmu_read() of the
+ * open-context data, which may be different than the data
+ * as it was when the write was generated.
+ */
+ if (zd->zd_zilog->zl_replay) {
+ ztest_bt_verify(bt, os, lr->lr_foid, 0, offset,
+ MAX(gen, bt->bt_gen), MAX(txg, lrtxg),
+ bt->bt_crtxg);
+ }
+
+ /*
+ * Set the bt's gen/txg to the bonus buffer's gen/txg
+ * so that all of the usual ASSERTs will work.
+ */
+ ztest_bt_generate(bt, os, lr->lr_foid, 0, offset, gen, txg,
+ crtxg);
+ }
+
+ if (abuf == NULL) {
+ dmu_write(os, lr->lr_foid, offset, length, data, tx);
+ } else {
+ bcopy(data, abuf->b_data, length);
+ dmu_assign_arcbuf(db, offset, abuf, tx);
+ }
+
+ (void) ztest_log_write(zd, tx, lr);
+
+ dmu_buf_rele(db, FTAG);
+
+ dmu_tx_commit(tx);
+
+ ztest_range_unlock(rl);
+ ztest_object_unlock(zd, lr->lr_foid);
+
+ return (0);
+}
+
+static int
+ztest_replay_truncate(void *arg1, void *arg2, boolean_t byteswap)
+{
+ ztest_ds_t *zd = arg1;
+ lr_truncate_t *lr = arg2;
+ objset_t *os = zd->zd_os;
+ dmu_tx_t *tx;
+ uint64_t txg;
+ rl_t *rl;
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ ztest_object_lock(zd, lr->lr_foid, RL_READER);
+ rl = ztest_range_lock(zd, lr->lr_foid, lr->lr_offset, lr->lr_length,
+ RL_WRITER);
+
+ tx = dmu_tx_create(os);
+
+ dmu_tx_hold_free(tx, lr->lr_foid, lr->lr_offset, lr->lr_length);
+
+ txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+ if (txg == 0) {
+ ztest_range_unlock(rl);
+ ztest_object_unlock(zd, lr->lr_foid);
+ return (ENOSPC);
+ }
+
+ VERIFY(dmu_free_range(os, lr->lr_foid, lr->lr_offset,
+ lr->lr_length, tx) == 0);
+
+ (void) ztest_log_truncate(zd, tx, lr);
+
+ dmu_tx_commit(tx);
+
+ ztest_range_unlock(rl);
+ ztest_object_unlock(zd, lr->lr_foid);
+
+ return (0);
+}
+
+static int
+ztest_replay_setattr(void *arg1, void *arg2, boolean_t byteswap)
+{
+ ztest_ds_t *zd = arg1;
+ lr_setattr_t *lr = arg2;
+ objset_t *os = zd->zd_os;
+ dmu_tx_t *tx;
+ dmu_buf_t *db;
+ ztest_block_tag_t *bbt;
+ uint64_t txg, lrtxg, crtxg, dnodesize;
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ ztest_object_lock(zd, lr->lr_foid, RL_WRITER);
+
+ VERIFY3U(0, ==, dmu_bonus_hold(os, lr->lr_foid, FTAG, &db));
+
+ tx = dmu_tx_create(os);
+ dmu_tx_hold_bonus(tx, lr->lr_foid);
+
+ txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+ if (txg == 0) {
+ dmu_buf_rele(db, FTAG);
+ ztest_object_unlock(zd, lr->lr_foid);
+ return (ENOSPC);
+ }
+
+ bbt = ztest_bt_bonus(db);
+ ASSERT3U(bbt->bt_magic, ==, BT_MAGIC);
+ crtxg = bbt->bt_crtxg;
+ lrtxg = lr->lr_common.lrc_txg;
+ dnodesize = bbt->bt_dnodesize;
+
+ if (zd->zd_zilog->zl_replay) {
+ ASSERT(lr->lr_size != 0);
+ ASSERT(lr->lr_mode != 0);
+ ASSERT(lrtxg != 0);
+ } else {
+ /*
+ * Randomly change the size and increment the generation.
+ */
+ lr->lr_size = (ztest_random(db->db_size / sizeof (*bbt)) + 1) *
+ sizeof (*bbt);
+ lr->lr_mode = bbt->bt_gen + 1;
+ ASSERT(lrtxg == 0);
+ }
+
+ /*
+ * Verify that the current bonus buffer is not newer than our txg.
+ */
+ ztest_bt_verify(bbt, os, lr->lr_foid, dnodesize, -1ULL, lr->lr_mode,
+ MAX(txg, lrtxg), crtxg);
+
+ dmu_buf_will_dirty(db, tx);
+
+ ASSERT3U(lr->lr_size, >=, sizeof (*bbt));
+ ASSERT3U(lr->lr_size, <=, db->db_size);
+ VERIFY0(dmu_set_bonus(db, lr->lr_size, tx));
+ bbt = ztest_bt_bonus(db);
+
+ ztest_bt_generate(bbt, os, lr->lr_foid, dnodesize, -1ULL, lr->lr_mode,
+ txg, crtxg);
+ ztest_fill_unused_bonus(db, bbt, lr->lr_foid, os, bbt->bt_gen);
+
+ dmu_buf_rele(db, FTAG);
+
+ (void) ztest_log_setattr(zd, tx, lr);
+
+ dmu_tx_commit(tx);
+
+ ztest_object_unlock(zd, lr->lr_foid);
+
+ return (0);
+}
+
+zil_replay_func_t *ztest_replay_vector[TX_MAX_TYPE] = {
+ NULL, /* 0 no such transaction type */
+ ztest_replay_create, /* TX_CREATE */
+ NULL, /* TX_MKDIR */
+ NULL, /* TX_MKXATTR */
+ NULL, /* TX_SYMLINK */
+ ztest_replay_remove, /* TX_REMOVE */
+ NULL, /* TX_RMDIR */
+ NULL, /* TX_LINK */
+ NULL, /* TX_RENAME */
+ ztest_replay_write, /* TX_WRITE */
+ ztest_replay_truncate, /* TX_TRUNCATE */
+ ztest_replay_setattr, /* TX_SETATTR */
+ NULL, /* TX_ACL */
+ NULL, /* TX_CREATE_ACL */
+ NULL, /* TX_CREATE_ATTR */
+ NULL, /* TX_CREATE_ACL_ATTR */
+ NULL, /* TX_MKDIR_ACL */
+ NULL, /* TX_MKDIR_ATTR */
+ NULL, /* TX_MKDIR_ACL_ATTR */
+ NULL, /* TX_WRITE2 */
+};
+
+/*
+ * ZIL get_data callbacks
+ */
+
+/* ARGSUSED */
+static void
+ztest_get_done(zgd_t *zgd, int error)
+{
+ ztest_ds_t *zd = zgd->zgd_private;
+ uint64_t object = ((rl_t *)zgd->zgd_lr)->rl_object;
+
+ if (zgd->zgd_db)
+ dmu_buf_rele(zgd->zgd_db, zgd);
+
+ ztest_range_unlock((rl_t *)zgd->zgd_lr);
+ ztest_object_unlock(zd, object);
+
+ umem_free(zgd, sizeof (*zgd));
+}
+
+static int
+ztest_get_data(void *arg, lr_write_t *lr, char *buf, struct lwb *lwb,
+ zio_t *zio)
+{
+ ztest_ds_t *zd = arg;
+ objset_t *os = zd->zd_os;
+ uint64_t object = lr->lr_foid;
+ uint64_t offset = lr->lr_offset;
+ uint64_t size = lr->lr_length;
+ uint64_t txg = lr->lr_common.lrc_txg;
+ uint64_t crtxg;
+ dmu_object_info_t doi;
+ dmu_buf_t *db;
+ zgd_t *zgd;
+ int error;
+
+ ASSERT3P(lwb, !=, NULL);
+ ASSERT3P(zio, !=, NULL);
+ ASSERT3U(size, !=, 0);
+
+ ztest_object_lock(zd, object, RL_READER);
+ error = dmu_bonus_hold(os, object, FTAG, &db);
+ if (error) {
+ ztest_object_unlock(zd, object);
+ return (error);
+ }
+
+ crtxg = ztest_bt_bonus(db)->bt_crtxg;
+
+ if (crtxg == 0 || crtxg > txg) {
+ dmu_buf_rele(db, FTAG);
+ ztest_object_unlock(zd, object);
+ return (ENOENT);
+ }
+
+ dmu_object_info_from_db(db, &doi);
+ dmu_buf_rele(db, FTAG);
+ db = NULL;
+
+ zgd = umem_zalloc(sizeof (*zgd), UMEM_NOFAIL);
+ zgd->zgd_lwb = lwb;
+ zgd->zgd_private = zd;
+
+ if (buf != NULL) { /* immediate write */
+ zgd->zgd_lr = (struct locked_range *)ztest_range_lock(zd,
+ object, offset, size, RL_READER);
+
+ error = dmu_read(os, object, offset, size, buf,
+ DMU_READ_NO_PREFETCH);
+ ASSERT(error == 0);
+ } else {
+ size = doi.doi_data_block_size;
+ if (ISP2(size)) {
+ offset = P2ALIGN(offset, size);
+ } else {
+ ASSERT(offset < size);
+ offset = 0;
+ }
+
+ zgd->zgd_lr = (struct locked_range *)ztest_range_lock(zd,
+ object, offset, size, RL_READER);
+
+ error = dmu_buf_hold(os, object, offset, zgd, &db,
+ DMU_READ_NO_PREFETCH);
+
+ if (error == 0) {
+ blkptr_t *bp = &lr->lr_blkptr;
+
+ zgd->zgd_db = db;
+ zgd->zgd_bp = bp;
+
+ ASSERT(db->db_offset == offset);
+ ASSERT(db->db_size == size);
+
+ error = dmu_sync(zio, lr->lr_common.lrc_txg,
+ ztest_get_done, zgd);
+
+ if (error == 0)
+ return (0);
+ }
+ }
+
+ ztest_get_done(zgd, error);
+
+ return (error);
+}
+
+static void *
+ztest_lr_alloc(size_t lrsize, char *name)
+{
+ char *lr;
+ size_t namesize = name ? strlen(name) + 1 : 0;
+
+ lr = umem_zalloc(lrsize + namesize, UMEM_NOFAIL);
+
+ if (name)
+ bcopy(name, lr + lrsize, namesize);
+
+ return (lr);
+}
+
+void
+ztest_lr_free(void *lr, size_t lrsize, char *name)
+{
+ size_t namesize = name ? strlen(name) + 1 : 0;
+
+ umem_free(lr, lrsize + namesize);
+}
+
+/*
+ * Lookup a bunch of objects. Returns the number of objects not found.
+ */
+static int
+ztest_lookup(ztest_ds_t *zd, ztest_od_t *od, int count)
+{
+ int missing = 0;
+ int error;
+
+ ASSERT(MUTEX_HELD(&zd->zd_dirobj_lock));
+
+ for (int i = 0; i < count; i++, od++) {
+ od->od_object = 0;
+ error = zap_lookup(zd->zd_os, od->od_dir, od->od_name,
+ sizeof (uint64_t), 1, &od->od_object);
+ if (error) {
+ ASSERT(error == ENOENT);
+ ASSERT(od->od_object == 0);
+ missing++;
+ } else {
+ dmu_buf_t *db;
+ ztest_block_tag_t *bbt;
+ dmu_object_info_t doi;
+
+ ASSERT(od->od_object != 0);
+ ASSERT(missing == 0); /* there should be no gaps */
+
+ ztest_object_lock(zd, od->od_object, RL_READER);
+ VERIFY3U(0, ==, dmu_bonus_hold(zd->zd_os,
+ od->od_object, FTAG, &db));
+ dmu_object_info_from_db(db, &doi);
+ bbt = ztest_bt_bonus(db);
+ ASSERT3U(bbt->bt_magic, ==, BT_MAGIC);
+ od->od_type = doi.doi_type;
+ od->od_blocksize = doi.doi_data_block_size;
+ od->od_gen = bbt->bt_gen;
+ dmu_buf_rele(db, FTAG);
+ ztest_object_unlock(zd, od->od_object);
+ }
+ }
+
+ return (missing);
+}
+
+static int
+ztest_create(ztest_ds_t *zd, ztest_od_t *od, int count)
+{
+ int missing = 0;
+
+ ASSERT(MUTEX_HELD(&zd->zd_dirobj_lock));
+
+ for (int i = 0; i < count; i++, od++) {
+ if (missing) {
+ od->od_object = 0;
+ missing++;
+ continue;
+ }
+
+ lr_create_t *lr = ztest_lr_alloc(sizeof (*lr), od->od_name);
+
+ lr->lr_doid = od->od_dir;
+ lr->lr_foid = 0; /* 0 to allocate, > 0 to claim */
+ lr->lrz_type = od->od_crtype;
+ lr->lrz_blocksize = od->od_crblocksize;
+ lr->lrz_ibshift = ztest_random_ibshift();
+ lr->lrz_bonustype = DMU_OT_UINT64_OTHER;
+ lr->lrz_dnodesize = od->od_crdnodesize;
+ lr->lr_gen = od->od_crgen;
+ lr->lr_crtime[0] = time(NULL);
+
+ if (ztest_replay_create(zd, lr, B_FALSE) != 0) {
+ ASSERT(missing == 0);
+ od->od_object = 0;
+ missing++;
+ } else {
+ od->od_object = lr->lr_foid;
+ od->od_type = od->od_crtype;
+ od->od_blocksize = od->od_crblocksize;
+ od->od_gen = od->od_crgen;
+ ASSERT(od->od_object != 0);
+ }
+
+ ztest_lr_free(lr, sizeof (*lr), od->od_name);
+ }
+
+ return (missing);
+}
+
+static int
+ztest_remove(ztest_ds_t *zd, ztest_od_t *od, int count)
+{
+ int missing = 0;
+ int error;
+
+ ASSERT(MUTEX_HELD(&zd->zd_dirobj_lock));
+
+ od += count - 1;
+
+ for (int i = count - 1; i >= 0; i--, od--) {
+ if (missing) {
+ missing++;
+ continue;
+ }
+
+ /*
+ * No object was found.
+ */
+ if (od->od_object == 0)
+ continue;
+
+ lr_remove_t *lr = ztest_lr_alloc(sizeof (*lr), od->od_name);
+
+ lr->lr_doid = od->od_dir;
+
+ if ((error = ztest_replay_remove(zd, lr, B_FALSE)) != 0) {
+ ASSERT3U(error, ==, ENOSPC);
+ missing++;
+ } else {
+ od->od_object = 0;
+ }
+ ztest_lr_free(lr, sizeof (*lr), od->od_name);
+ }
+
+ return (missing);
+}
+
+static int
+ztest_write(ztest_ds_t *zd, uint64_t object, uint64_t offset, uint64_t size,
+ void *data)
+{
+ lr_write_t *lr;
+ int error;
+
+ lr = ztest_lr_alloc(sizeof (*lr) + size, NULL);
+
+ lr->lr_foid = object;
+ lr->lr_offset = offset;
+ lr->lr_length = size;
+ lr->lr_blkoff = 0;
+ BP_ZERO(&lr->lr_blkptr);
+
+ bcopy(data, lr + 1, size);
+
+ error = ztest_replay_write(zd, lr, B_FALSE);
+
+ ztest_lr_free(lr, sizeof (*lr) + size, NULL);
+
+ return (error);
+}
+
+static int
+ztest_truncate(ztest_ds_t *zd, uint64_t object, uint64_t offset, uint64_t size)
+{
+ lr_truncate_t *lr;
+ int error;
+
+ lr = ztest_lr_alloc(sizeof (*lr), NULL);
+
+ lr->lr_foid = object;
+ lr->lr_offset = offset;
+ lr->lr_length = size;
+
+ error = ztest_replay_truncate(zd, lr, B_FALSE);
+
+ ztest_lr_free(lr, sizeof (*lr), NULL);
+
+ return (error);
+}
+
+static int
+ztest_setattr(ztest_ds_t *zd, uint64_t object)
+{
+ lr_setattr_t *lr;
+ int error;
+
+ lr = ztest_lr_alloc(sizeof (*lr), NULL);
+
+ lr->lr_foid = object;
+ lr->lr_size = 0;
+ lr->lr_mode = 0;
+
+ error = ztest_replay_setattr(zd, lr, B_FALSE);
+
+ ztest_lr_free(lr, sizeof (*lr), NULL);
+
+ return (error);
+}
+
+static void
+ztest_prealloc(ztest_ds_t *zd, uint64_t object, uint64_t offset, uint64_t size)
+{
+ objset_t *os = zd->zd_os;
+ dmu_tx_t *tx;
+ uint64_t txg;
+ rl_t *rl;
+
+ txg_wait_synced(dmu_objset_pool(os), 0);
+
+ ztest_object_lock(zd, object, RL_READER);
+ rl = ztest_range_lock(zd, object, offset, size, RL_WRITER);
+
+ tx = dmu_tx_create(os);
+
+ dmu_tx_hold_write(tx, object, offset, size);
+
+ txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+
+ if (txg != 0) {
+ dmu_prealloc(os, object, offset, size, tx);
+ dmu_tx_commit(tx);
+ txg_wait_synced(dmu_objset_pool(os), txg);
+ } else {
+ (void) dmu_free_long_range(os, object, offset, size);
+ }
+
+ ztest_range_unlock(rl);
+ ztest_object_unlock(zd, object);
+}
+
+static void
+ztest_io(ztest_ds_t *zd, uint64_t object, uint64_t offset)
+{
+ int err;
+ ztest_block_tag_t wbt;
+ dmu_object_info_t doi;
+ enum ztest_io_type io_type;
+ uint64_t blocksize;
+ void *data;
+
+ VERIFY(dmu_object_info(zd->zd_os, object, &doi) == 0);
+ blocksize = doi.doi_data_block_size;
+ data = umem_alloc(blocksize, UMEM_NOFAIL);
+
+ /*
+ * Pick an i/o type at random, biased toward writing block tags.
+ */
+ io_type = ztest_random(ZTEST_IO_TYPES);
+ if (ztest_random(2) == 0)
+ io_type = ZTEST_IO_WRITE_TAG;
+
+ rw_enter(&zd->zd_zilog_lock, RW_READER);
+
+ switch (io_type) {
+
+ case ZTEST_IO_WRITE_TAG:
+ ztest_bt_generate(&wbt, zd->zd_os, object, doi.doi_dnodesize,
+ offset, 0, 0, 0);
+ (void) ztest_write(zd, object, offset, sizeof (wbt), &wbt);
+ break;
+
+ case ZTEST_IO_WRITE_PATTERN:
+ (void) memset(data, 'a' + (object + offset) % 5, blocksize);
+ if (ztest_random(2) == 0) {
+ /*
+ * Induce fletcher2 collisions to ensure that
+ * zio_ddt_collision() detects and resolves them
+ * when using fletcher2-verify for deduplication.
+ */
+ ((uint64_t *)data)[0] ^= 1ULL << 63;
+ ((uint64_t *)data)[4] ^= 1ULL << 63;
+ }
+ (void) ztest_write(zd, object, offset, blocksize, data);
+ break;
+
+ case ZTEST_IO_WRITE_ZEROES:
+ bzero(data, blocksize);
+ (void) ztest_write(zd, object, offset, blocksize, data);
+ break;
+
+ case ZTEST_IO_TRUNCATE:
+ (void) ztest_truncate(zd, object, offset, blocksize);
+ break;
+
+ case ZTEST_IO_SETATTR:
+ (void) ztest_setattr(zd, object);
+ break;
+
+ case ZTEST_IO_REWRITE:
+ rw_enter(&ztest_name_lock, RW_READER);
+ err = ztest_dsl_prop_set_uint64(zd->zd_name,
+ ZFS_PROP_CHECKSUM, spa_dedup_checksum(ztest_spa),
+ B_FALSE);
+ VERIFY(err == 0 || err == ENOSPC);
+ err = ztest_dsl_prop_set_uint64(zd->zd_name,
+ ZFS_PROP_COMPRESSION,
+ ztest_random_dsl_prop(ZFS_PROP_COMPRESSION),
+ B_FALSE);
+ VERIFY(err == 0 || err == ENOSPC);
+ rw_exit(&ztest_name_lock);
+
+ VERIFY0(dmu_read(zd->zd_os, object, offset, blocksize, data,
+ DMU_READ_NO_PREFETCH));
+
+ (void) ztest_write(zd, object, offset, blocksize, data);
+ break;
+ }
+
+ rw_exit(&zd->zd_zilog_lock);
+
+ umem_free(data, blocksize);
+}
+
+/*
+ * Initialize an object description template.
+ */
+static void
+ztest_od_init(ztest_od_t *od, uint64_t id, char *tag, uint64_t index,
+ dmu_object_type_t type, uint64_t blocksize, uint64_t dnodesize,
+ uint64_t gen)
+{
+ od->od_dir = ZTEST_DIROBJ;
+ od->od_object = 0;
+
+ od->od_crtype = type;
+ od->od_crblocksize = blocksize ? blocksize : ztest_random_blocksize();
+ od->od_crdnodesize = dnodesize ? dnodesize : ztest_random_dnodesize();
+ od->od_crgen = gen;
+
+ od->od_type = DMU_OT_NONE;
+ od->od_blocksize = 0;
+ od->od_gen = 0;
+
+ (void) snprintf(od->od_name, sizeof (od->od_name), "%s(%lld)[%llu]",
+ tag, (int64_t)id, index);
+}
+
+/*
+ * Lookup or create the objects for a test using the od template.
+ * If the objects do not all exist, or if 'remove' is specified,
+ * remove any existing objects and create new ones. Otherwise,
+ * use the existing objects.
+ */
+static int
+ztest_object_init(ztest_ds_t *zd, ztest_od_t *od, size_t size, boolean_t remove)
+{
+ int count = size / sizeof (*od);
+ int rv = 0;
+
+ mutex_enter(&zd->zd_dirobj_lock);
+ if ((ztest_lookup(zd, od, count) != 0 || remove) &&
+ (ztest_remove(zd, od, count) != 0 ||
+ ztest_create(zd, od, count) != 0))
+ rv = -1;
+ zd->zd_od = od;
+ mutex_exit(&zd->zd_dirobj_lock);
+
+ return (rv);
+}
+
+/* ARGSUSED */
+void
+ztest_zil_commit(ztest_ds_t *zd, uint64_t id)
+{
+ zilog_t *zilog = zd->zd_zilog;
+
+ rw_enter(&zd->zd_zilog_lock, RW_READER);
+
+ zil_commit(zilog, ztest_random(ZTEST_OBJECTS));
+
+ /*
+ * Remember the committed values in zd, which is in parent/child
+ * shared memory. If we die, the next iteration of ztest_run()
+ * will verify that the log really does contain this record.
+ */
+ mutex_enter(&zilog->zl_lock);
+ ASSERT(zd->zd_shared != NULL);
+ ASSERT3U(zd->zd_shared->zd_seq, <=, zilog->zl_commit_lr_seq);
+ zd->zd_shared->zd_seq = zilog->zl_commit_lr_seq;
+ mutex_exit(&zilog->zl_lock);
+
+ rw_exit(&zd->zd_zilog_lock);
+}
+
+/*
+ * This function is designed to simulate the operations that occur during a
+ * mount/unmount operation. We hold the dataset across these operations in an
+ * attempt to expose any implicit assumptions about ZIL management.
+ */
+/* ARGSUSED */
+void
+ztest_zil_remount(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+
+ /*
+ * We grab the zd_dirobj_lock to ensure that no other thread is
+ * updating the zil (i.e. adding in-memory log records) and the
+ * zd_zilog_lock to block any I/O.
+ */
+ mutex_enter(&zd->zd_dirobj_lock);
+ rw_enter(&zd->zd_zilog_lock, RW_WRITER);
+
+ /* zfsvfs_teardown() */
+ zil_close(zd->zd_zilog);
+
+ /* zfsvfs_setup() */
+ VERIFY(zil_open(os, ztest_get_data) == zd->zd_zilog);
+ zil_replay(os, zd, ztest_replay_vector);
+
+ rw_exit(&zd->zd_zilog_lock);
+ mutex_exit(&zd->zd_dirobj_lock);
+}
+
+/*
+ * Verify that we can't destroy an active pool, create an existing pool,
+ * or create a pool with a bad vdev spec.
+ */
+/* ARGSUSED */
+void
+ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_opts_t *zo = &ztest_opts;
+ spa_t *spa;
+ nvlist_t *nvroot;
+
+ if (zo->zo_mmp_test)
+ return;
+
+ /*
+ * Attempt to create using a bad file.
+ */
+ nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 0, 1);
+ VERIFY3U(ENOENT, ==,
+ spa_create("ztest_bad_file", nvroot, NULL, NULL));
+ nvlist_free(nvroot);
+
+ /*
+ * Attempt to create using a bad mirror.
+ */
+ nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 2, 1);
+ VERIFY3U(ENOENT, ==,
+ spa_create("ztest_bad_mirror", nvroot, NULL, NULL));
+ nvlist_free(nvroot);
+
+ /*
+ * Attempt to create an existing pool. It shouldn't matter
+ * what's in the nvroot; we should fail with EEXIST.
+ */
+ rw_enter(&ztest_name_lock, RW_READER);
+ nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 0, 1);
+ VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL));
+ nvlist_free(nvroot);
+ VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
+ VERIFY3U(EBUSY, ==, spa_destroy(zo->zo_pool));
+ spa_close(spa, FTAG);
+
+ rw_exit(&ztest_name_lock);
+}
+
+/*
+ * Start and then stop the MMP threads to ensure the startup and shutdown code
+ * works properly. Actual protection and property-related code tested via ZTS.
+ */
+/* ARGSUSED */
+void
+ztest_mmp_enable_disable(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_opts_t *zo = &ztest_opts;
+ spa_t *spa = ztest_spa;
+
+ if (zo->zo_mmp_test)
+ return;
+
+ /*
+ * Since enabling MMP involves setting a property, it could not be done
+ * while the pool is suspended.
+ */
+ if (spa_suspended(spa))
+ return;
+
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+ mutex_enter(&spa->spa_props_lock);
+
+ zfs_multihost_fail_intervals = 0;
+
+ if (!spa_multihost(spa)) {
+ spa->spa_multihost = B_TRUE;
+ mmp_thread_start(spa);
+ }
+
+ mutex_exit(&spa->spa_props_lock);
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
+
+ txg_wait_synced(spa_get_dsl(spa), 0);
+ mmp_signal_all_threads();
+ txg_wait_synced(spa_get_dsl(spa), 0);
+
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+ mutex_enter(&spa->spa_props_lock);
+
+ if (spa_multihost(spa)) {
+ mmp_thread_stop(spa);
+ spa->spa_multihost = B_FALSE;
+ }
+
+ mutex_exit(&spa->spa_props_lock);
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
+}
+
+/* ARGSUSED */
+void
+ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
+{
+ spa_t *spa;
+ uint64_t initial_version = SPA_VERSION_INITIAL;
+ uint64_t version, newversion;
+ nvlist_t *nvroot, *props;
+ char *name;
+
+ if (ztest_opts.zo_mmp_test)
+ return;
+
+ mutex_enter(&ztest_vdev_lock);
+ name = kmem_asprintf("%s_upgrade", ztest_opts.zo_pool);
+
+ /*
+ * Clean up from previous runs.
+ */
+ (void) spa_destroy(name);
+
+ nvroot = make_vdev_root(NULL, NULL, name, ztest_opts.zo_vdev_size, 0,
+ NULL, ztest_opts.zo_raidz, ztest_opts.zo_mirrors, 1);
+
+ /*
+ * If we're configuring a RAIDZ device then make sure that the
+ * the initial version is capable of supporting that feature.
+ */
+ switch (ztest_opts.zo_raidz_parity) {
+ case 0:
+ case 1:
+ initial_version = SPA_VERSION_INITIAL;
+ break;
+ case 2:
+ initial_version = SPA_VERSION_RAIDZ2;
+ break;
+ case 3:
+ initial_version = SPA_VERSION_RAIDZ3;
+ break;
+ }
+
+ /*
+ * Create a pool with a spa version that can be upgraded. Pick
+ * a value between initial_version and SPA_VERSION_BEFORE_FEATURES.
+ */
+ do {
+ version = ztest_random_spa_version(initial_version);
+ } while (version > SPA_VERSION_BEFORE_FEATURES);
+
+ props = fnvlist_alloc();
+ fnvlist_add_uint64(props,
+ zpool_prop_to_name(ZPOOL_PROP_VERSION), version);
+ VERIFY0(spa_create(name, nvroot, props, NULL));
+ fnvlist_free(nvroot);
+ fnvlist_free(props);
+
+ VERIFY0(spa_open(name, &spa, FTAG));
+ VERIFY3U(spa_version(spa), ==, version);
+ newversion = ztest_random_spa_version(version + 1);
+
+ if (ztest_opts.zo_verbose >= 4) {
+ (void) printf("upgrading spa version from %llu to %llu\n",
+ (u_longlong_t)version, (u_longlong_t)newversion);
+ }
+
+ spa_upgrade(spa, newversion);
+ VERIFY3U(spa_version(spa), >, version);
+ VERIFY3U(spa_version(spa), ==, fnvlist_lookup_uint64(spa->spa_config,
+ zpool_prop_to_name(ZPOOL_PROP_VERSION)));
+ spa_close(spa, FTAG);
+
+ strfree(name);
+ mutex_exit(&ztest_vdev_lock);
+}
+
+static void
+ztest_spa_checkpoint(spa_t *spa)
+{
+ ASSERT(MUTEX_HELD(&ztest_checkpoint_lock));
+
+ int error = spa_checkpoint(spa->spa_name);
+
+ switch (error) {
+ case 0:
+ case ZFS_ERR_DEVRM_IN_PROGRESS:
+ case ZFS_ERR_DISCARDING_CHECKPOINT:
+ case ZFS_ERR_CHECKPOINT_EXISTS:
+ break;
+ case ENOSPC:
+ ztest_record_enospc(FTAG);
+ break;
+ default:
+ fatal(0, "spa_checkpoint(%s) = %d", spa->spa_name, error);
+ }
+}
+
+static void
+ztest_spa_discard_checkpoint(spa_t *spa)
+{
+ ASSERT(MUTEX_HELD(&ztest_checkpoint_lock));
+
+ int error = spa_checkpoint_discard(spa->spa_name);
+
+ switch (error) {
+ case 0:
+ case ZFS_ERR_DISCARDING_CHECKPOINT:
+ case ZFS_ERR_NO_CHECKPOINT:
+ break;
+ default:
+ fatal(0, "spa_discard_checkpoint(%s) = %d",
+ spa->spa_name, error);
+ }
+
+}
+
+/* ARGSUSED */
+void
+ztest_spa_checkpoint_create_discard(ztest_ds_t *zd, uint64_t id)
+{
+ spa_t *spa = ztest_spa;
+
+ mutex_enter(&ztest_checkpoint_lock);
+ if (ztest_random(2) == 0) {
+ ztest_spa_checkpoint(spa);
+ } else {
+ ztest_spa_discard_checkpoint(spa);
+ }
+ mutex_exit(&ztest_checkpoint_lock);
+}
+
+
+static vdev_t *
+vdev_lookup_by_path(vdev_t *vd, const char *path)
+{
+ vdev_t *mvd;
+
+ if (vd->vdev_path != NULL && strcmp(path, vd->vdev_path) == 0)
+ return (vd);
+
+ for (int c = 0; c < vd->vdev_children; c++)
+ if ((mvd = vdev_lookup_by_path(vd->vdev_child[c], path)) !=
+ NULL)
+ return (mvd);
+
+ return (NULL);
+}
+
+/*
+ * Find the first available hole which can be used as a top-level.
+ */
+int
+find_vdev_hole(spa_t *spa)
+{
+ vdev_t *rvd = spa->spa_root_vdev;
+ int c;
+
+ ASSERT(spa_config_held(spa, SCL_VDEV, RW_READER) == SCL_VDEV);
+
+ for (c = 0; c < rvd->vdev_children; c++) {
+ vdev_t *cvd = rvd->vdev_child[c];
+
+ if (cvd->vdev_ishole)
+ break;
+ }
+ return (c);
+}
+
+/*
+ * Verify that vdev_add() works as expected.
+ */
+/* ARGSUSED */
+void
+ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_t *zs = ztest_shared;
+ spa_t *spa = ztest_spa;
+ uint64_t leaves;
+ uint64_t guid;
+ nvlist_t *nvroot;
+ int error;
+
+ if (ztest_opts.zo_mmp_test)
+ return;
+
+ mutex_enter(&ztest_vdev_lock);
+ leaves = MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
+
+ spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+ ztest_shared->zs_vdev_next_leaf = find_vdev_hole(spa) * leaves;
+
+ /*
+ * If we have slogs then remove them 1/4 of the time.
+ */
+ if (spa_has_slogs(spa) && ztest_random(4) == 0) {
+ metaslab_group_t *mg;
+
+ /*
+ * find the first real slog in log allocation class
+ */
+ mg = spa_log_class(spa)->mc_rotor;
+ while (!mg->mg_vd->vdev_islog)
+ mg = mg->mg_next;
+
+ guid = mg->mg_vd->vdev_guid;
+
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+
+ /*
+ * We have to grab the zs_name_lock as writer to
+ * prevent a race between removing a slog (dmu_objset_find)
+ * and destroying a dataset. Removing the slog will
+ * grab a reference on the dataset which may cause
+ * dmu_objset_destroy() to fail with EBUSY thus
+ * leaving the dataset in an inconsistent state.
+ */
+ rw_enter(&ztest_name_lock, RW_WRITER);
+ error = spa_vdev_remove(spa, guid, B_FALSE);
+ rw_exit(&ztest_name_lock);
+
+ switch (error) {
+ case 0:
+ case EEXIST:
+ case ZFS_ERR_CHECKPOINT_EXISTS:
+ case ZFS_ERR_DISCARDING_CHECKPOINT:
+ break;
+ default:
+ fatal(0, "spa_vdev_remove() = %d", error);
+ }
+ } else {
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+
+ /*
+ * Make 1/4 of the devices be log devices
+ */
+ nvroot = make_vdev_root(NULL, NULL, NULL,
+ ztest_opts.zo_vdev_size, 0, (ztest_random(4) == 0) ?
+ "log" : NULL, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
+
+ error = spa_vdev_add(spa, nvroot);
+ nvlist_free(nvroot);
+
+ switch (error) {
+ case 0:
+ break;
+ case ENOSPC:
+ ztest_record_enospc("spa_vdev_add");
+ break;
+ default:
+ fatal(0, "spa_vdev_add() = %d", error);
+ }
+ }
+
+ mutex_exit(&ztest_vdev_lock);
+}
+
+/* ARGSUSED */
+void
+ztest_vdev_class_add(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_t *zs = ztest_shared;
+ spa_t *spa = ztest_spa;
+ uint64_t leaves;
+ nvlist_t *nvroot;
+ const char *class = (ztest_random(2) == 0) ?
+ VDEV_ALLOC_BIAS_SPECIAL : VDEV_ALLOC_BIAS_DEDUP;
+ int error;
+
+ /*
+ * By default add a special vdev 50% of the time
+ */
+ if ((ztest_opts.zo_special_vdevs == ZTEST_VDEV_CLASS_OFF) ||
+ (ztest_opts.zo_special_vdevs == ZTEST_VDEV_CLASS_RND &&
+ ztest_random(2) == 0)) {
+ return;
+ }
+
+ mutex_enter(&ztest_vdev_lock);
+
+ /* Only test with mirrors */
+ if (zs->zs_mirrors < 2) {
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ /* requires feature@allocation_classes */
+ if (!spa_feature_is_enabled(spa, SPA_FEATURE_ALLOCATION_CLASSES)) {
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ leaves = MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
+
+ spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+ ztest_shared->zs_vdev_next_leaf = find_vdev_hole(spa) * leaves;
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+
+ nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0,
+ class, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
+
+ error = spa_vdev_add(spa, nvroot);
+ nvlist_free(nvroot);
+
+ if (error == ENOSPC)
+ ztest_record_enospc("spa_vdev_add");
+ else if (error != 0)
+ fatal(0, "spa_vdev_add() = %d", error);
+
+ /*
+ * 50% of the time allow small blocks in the special class
+ */
+ if (error == 0 &&
+ spa_special_class(spa)->mc_groups == 1 && ztest_random(2) == 0) {
+ if (ztest_opts.zo_verbose >= 3)
+ (void) printf("Enabling special VDEV small blocks\n");
+ (void) ztest_dsl_prop_set_uint64(zd->zd_name,
+ ZFS_PROP_SPECIAL_SMALL_BLOCKS, 32768, B_FALSE);
+ }
+
+ mutex_exit(&ztest_vdev_lock);
+
+ if (ztest_opts.zo_verbose >= 3) {
+ metaslab_class_t *mc;
+
+ if (strcmp(class, VDEV_ALLOC_BIAS_SPECIAL) == 0)
+ mc = spa_special_class(spa);
+ else
+ mc = spa_dedup_class(spa);
+ (void) printf("Added a %s mirrored vdev (of %d)\n",
+ class, (int)mc->mc_groups);
+ }
+}
+
+/*
+ * Verify that adding/removing aux devices (l2arc, hot spare) works as expected.
+ */
+/* ARGSUSED */
+void
+ztest_vdev_aux_add_remove(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_t *zs = ztest_shared;
+ spa_t *spa = ztest_spa;
+ vdev_t *rvd = spa->spa_root_vdev;
+ spa_aux_vdev_t *sav;
+ char *aux;
+ uint64_t guid = 0;
+ int error;
+
+ if (ztest_opts.zo_mmp_test)
+ return;
+
+ if (ztest_random(2) == 0) {
+ sav = &spa->spa_spares;
+ aux = ZPOOL_CONFIG_SPARES;
+ } else {
+ sav = &spa->spa_l2cache;
+ aux = ZPOOL_CONFIG_L2CACHE;
+ }
+
+ mutex_enter(&ztest_vdev_lock);
+
+ spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+ if (sav->sav_count != 0 && ztest_random(4) == 0) {
+ /*
+ * Pick a random device to remove.
+ */
+ guid = sav->sav_vdevs[ztest_random(sav->sav_count)]->vdev_guid;
+ } else {
+ /*
+ * Find an unused device we can add.
+ */
+ zs->zs_vdev_aux = 0;
+ for (;;) {
+ char path[MAXPATHLEN];
+ int c;
+ (void) snprintf(path, sizeof (path), ztest_aux_template,
+ ztest_opts.zo_dir, ztest_opts.zo_pool, aux,
+ zs->zs_vdev_aux);
+ for (c = 0; c < sav->sav_count; c++)
+ if (strcmp(sav->sav_vdevs[c]->vdev_path,
+ path) == 0)
+ break;
+ if (c == sav->sav_count &&
+ vdev_lookup_by_path(rvd, path) == NULL)
+ break;
+ zs->zs_vdev_aux++;
+ }
+ }
+
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+
+ if (guid == 0) {
+ /*
+ * Add a new device.
+ */
+ nvlist_t *nvroot = make_vdev_root(NULL, aux, NULL,
+ (ztest_opts.zo_vdev_size * 5) / 4, 0, NULL, 0, 0, 1);
+ error = spa_vdev_add(spa, nvroot);
+
+ switch (error) {
+ case 0:
+ break;
+ default:
+ fatal(0, "spa_vdev_add(%p) = %d", nvroot, error);
+ }
+ nvlist_free(nvroot);
+ } else {
+ /*
+ * Remove an existing device. Sometimes, dirty its
+ * vdev state first to make sure we handle removal
+ * of devices that have pending state changes.
+ */
+ if (ztest_random(2) == 0)
+ (void) vdev_online(spa, guid, 0, NULL);
+
+ error = spa_vdev_remove(spa, guid, B_FALSE);
+
+ switch (error) {
+ case 0:
+ case EBUSY:
+ case ZFS_ERR_CHECKPOINT_EXISTS:
+ case ZFS_ERR_DISCARDING_CHECKPOINT:
+ break;
+ default:
+ fatal(0, "spa_vdev_remove(%llu) = %d", guid, error);
+ }
+ }
+
+ mutex_exit(&ztest_vdev_lock);
+}
+
+/*
+ * split a pool if it has mirror tlvdevs
+ */
+/* ARGSUSED */
+void
+ztest_split_pool(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_t *zs = ztest_shared;
+ spa_t *spa = ztest_spa;
+ vdev_t *rvd = spa->spa_root_vdev;
+ nvlist_t *tree, **child, *config, *split, **schild;
+ uint_t c, children, schildren = 0, lastlogid = 0;
+ int error = 0;
+
+ if (ztest_opts.zo_mmp_test)
+ return;
+
+ mutex_enter(&ztest_vdev_lock);
+
+ /* ensure we have a useable config; mirrors of raidz aren't supported */
+ if (zs->zs_mirrors < 3 || ztest_opts.zo_raidz > 1) {
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ /* clean up the old pool, if any */
+ (void) spa_destroy("splitp");
+
+ spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+ /* generate a config from the existing config */
+ mutex_enter(&spa->spa_props_lock);
+ VERIFY(nvlist_lookup_nvlist(spa->spa_config, ZPOOL_CONFIG_VDEV_TREE,
+ &tree) == 0);
+ mutex_exit(&spa->spa_props_lock);
+
+ VERIFY(nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child,
+ &children) == 0);
+
+ schild = malloc(rvd->vdev_children * sizeof (nvlist_t *));
+ for (c = 0; c < children; c++) {
+ vdev_t *tvd = rvd->vdev_child[c];
+ nvlist_t **mchild;
+ uint_t mchildren;
+
+ if (tvd->vdev_islog || tvd->vdev_ops == &vdev_hole_ops) {
+ VERIFY(nvlist_alloc(&schild[schildren], NV_UNIQUE_NAME,
+ 0) == 0);
+ VERIFY(nvlist_add_string(schild[schildren],
+ ZPOOL_CONFIG_TYPE, VDEV_TYPE_HOLE) == 0);
+ VERIFY(nvlist_add_uint64(schild[schildren],
+ ZPOOL_CONFIG_IS_HOLE, 1) == 0);
+ if (lastlogid == 0)
+ lastlogid = schildren;
+ ++schildren;
+ continue;
+ }
+ lastlogid = 0;
+ VERIFY(nvlist_lookup_nvlist_array(child[c],
+ ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0);
+ VERIFY(nvlist_dup(mchild[0], &schild[schildren++], 0) == 0);
+ }
+
+ /* OK, create a config that can be used to split */
+ VERIFY(nvlist_alloc(&split, NV_UNIQUE_NAME, 0) == 0);
+ VERIFY(nvlist_add_string(split, ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_ROOT) == 0);
+ VERIFY(nvlist_add_nvlist_array(split, ZPOOL_CONFIG_CHILDREN, schild,
+ lastlogid != 0 ? lastlogid : schildren) == 0);
+
+ VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, 0) == 0);
+ VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, split) == 0);
+
+ for (c = 0; c < schildren; c++)
+ nvlist_free(schild[c]);
+ free(schild);
+ nvlist_free(split);
+
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+
+ rw_enter(&ztest_name_lock, RW_WRITER);
+ error = spa_vdev_split_mirror(spa, "splitp", config, NULL, B_FALSE);
+ rw_exit(&ztest_name_lock);
+
+ nvlist_free(config);
+
+ if (error == 0) {
+ (void) printf("successful split - results:\n");
+ mutex_enter(&spa_namespace_lock);
+ show_pool_stats(spa);
+ show_pool_stats(spa_lookup("splitp"));
+ mutex_exit(&spa_namespace_lock);
+ ++zs->zs_splits;
+ --zs->zs_mirrors;
+ }
+ mutex_exit(&ztest_vdev_lock);
+}
+
+/*
+ * Verify that we can attach and detach devices.
+ */
+/* ARGSUSED */
+void
+ztest_vdev_attach_detach(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_t *zs = ztest_shared;
+ spa_t *spa = ztest_spa;
+ spa_aux_vdev_t *sav = &spa->spa_spares;
+ vdev_t *rvd = spa->spa_root_vdev;
+ vdev_t *oldvd, *newvd, *pvd;
+ nvlist_t *root;
+ uint64_t leaves;
+ uint64_t leaf, top;
+ uint64_t ashift = ztest_get_ashift();
+ uint64_t oldguid, pguid;
+ uint64_t oldsize, newsize;
+ char oldpath[MAXPATHLEN], newpath[MAXPATHLEN];
+ int replacing;
+ int oldvd_has_siblings = B_FALSE;
+ int newvd_is_spare = B_FALSE;
+ int oldvd_is_log;
+ int error, expected_error;
+
+ if (ztest_opts.zo_mmp_test)
+ return;
+
+ mutex_enter(&ztest_vdev_lock);
+ leaves = MAX(zs->zs_mirrors, 1) * ztest_opts.zo_raidz;
+
+ spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+
+ /*
+ * If a vdev is in the process of being removed, its removal may
+ * finish while we are in progress, leading to an unexpected error
+ * value. Don't bother trying to attach while we are in the middle
+ * of removal.
+ */
+ if (ztest_device_removal_active) {
+ spa_config_exit(spa, SCL_ALL, FTAG);
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ /*
+ * Decide whether to do an attach or a replace.
+ */
+ replacing = ztest_random(2);
+
+ /*
+ * Pick a random top-level vdev.
+ */
+ top = ztest_random_vdev_top(spa, B_TRUE);
+
+ /*
+ * Pick a random leaf within it.
+ */
+ leaf = ztest_random(leaves);
+
+ /*
+ * Locate this vdev.
+ */
+ oldvd = rvd->vdev_child[top];
+
+ /* pick a child from the mirror */
+ if (zs->zs_mirrors >= 1) {
+ ASSERT(oldvd->vdev_ops == &vdev_mirror_ops);
+ ASSERT(oldvd->vdev_children >= zs->zs_mirrors);
+ oldvd = oldvd->vdev_child[leaf / ztest_opts.zo_raidz];
+ }
+
+ /* pick a child out of the raidz group */
+ if (ztest_opts.zo_raidz > 1) {
+ ASSERT(oldvd->vdev_ops == &vdev_raidz_ops);
+ ASSERT(oldvd->vdev_children == ztest_opts.zo_raidz);
+ oldvd = oldvd->vdev_child[leaf % ztest_opts.zo_raidz];
+ }
+
+ /*
+ * If we're already doing an attach or replace, oldvd may be a
+ * mirror vdev -- in which case, pick a random child.
+ */
+ while (oldvd->vdev_children != 0) {
+ oldvd_has_siblings = B_TRUE;
+ ASSERT(oldvd->vdev_children >= 2);
+ oldvd = oldvd->vdev_child[ztest_random(oldvd->vdev_children)];
+ }
+
+ oldguid = oldvd->vdev_guid;
+ oldsize = vdev_get_min_asize(oldvd);
+ oldvd_is_log = oldvd->vdev_top->vdev_islog;
+ (void) strcpy(oldpath, oldvd->vdev_path);
+ pvd = oldvd->vdev_parent;
+ pguid = pvd->vdev_guid;
+
+ /*
+ * If oldvd has siblings, then half of the time, detach it.
+ */
+ if (oldvd_has_siblings && ztest_random(2) == 0) {
+ spa_config_exit(spa, SCL_ALL, FTAG);
+ error = spa_vdev_detach(spa, oldguid, pguid, B_FALSE);
+ if (error != 0 && error != ENODEV && error != EBUSY &&
+ error != ENOTSUP && error != ZFS_ERR_CHECKPOINT_EXISTS &&
+ error != ZFS_ERR_DISCARDING_CHECKPOINT)
+ fatal(0, "detach (%s) returned %d", oldpath, error);
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ /*
+ * For the new vdev, choose with equal probability between the two
+ * standard paths (ending in either 'a' or 'b') or a random hot spare.
+ */
+ if (sav->sav_count != 0 && ztest_random(3) == 0) {
+ newvd = sav->sav_vdevs[ztest_random(sav->sav_count)];
+ newvd_is_spare = B_TRUE;
+ (void) strcpy(newpath, newvd->vdev_path);
+ } else {
+ (void) snprintf(newpath, sizeof (newpath), ztest_dev_template,
+ ztest_opts.zo_dir, ztest_opts.zo_pool,
+ top * leaves + leaf);
+ if (ztest_random(2) == 0)
+ newpath[strlen(newpath) - 1] = 'b';
+ newvd = vdev_lookup_by_path(rvd, newpath);
+ }
+
+ if (newvd) {
+ /*
+ * Reopen to ensure the vdev's asize field isn't stale.
+ */
+ vdev_reopen(newvd);
+ newsize = vdev_get_min_asize(newvd);
+ } else {
+ /*
+ * Make newsize a little bigger or smaller than oldsize.
+ * If it's smaller, the attach should fail.
+ * If it's larger, and we're doing a replace,
+ * we should get dynamic LUN growth when we're done.
+ */
+ newsize = 10 * oldsize / (9 + ztest_random(3));
+ }
+
+ /*
+ * If pvd is not a mirror or root, the attach should fail with ENOTSUP,
+ * unless it's a replace; in that case any non-replacing parent is OK.
+ *
+ * If newvd is already part of the pool, it should fail with EBUSY.
+ *
+ * If newvd is too small, it should fail with EOVERFLOW.
+ */
+ if (pvd->vdev_ops != &vdev_mirror_ops &&
+ pvd->vdev_ops != &vdev_root_ops && (!replacing ||
+ pvd->vdev_ops == &vdev_replacing_ops ||
+ pvd->vdev_ops == &vdev_spare_ops))
+ expected_error = ENOTSUP;
+ else if (newvd_is_spare && (!replacing || oldvd_is_log))
+ expected_error = ENOTSUP;
+ else if (newvd == oldvd)
+ expected_error = replacing ? 0 : EBUSY;
+ else if (vdev_lookup_by_path(rvd, newpath) != NULL)
+ expected_error = EBUSY;
+ else if (newsize < oldsize)
+ expected_error = EOVERFLOW;
+ else if (ashift > oldvd->vdev_top->vdev_ashift)
+ expected_error = EDOM;
+ else
+ expected_error = 0;
+
+ spa_config_exit(spa, SCL_ALL, FTAG);
+
+ /*
+ * Build the nvlist describing newpath.
+ */
+ root = make_vdev_root(newpath, NULL, NULL, newvd == NULL ? newsize : 0,
+ ashift, NULL, 0, 0, 1);
+
+ error = spa_vdev_attach(spa, oldguid, root, replacing);
+
+ nvlist_free(root);
+
+ /*
+ * If our parent was the replacing vdev, but the replace completed,
+ * then instead of failing with ENOTSUP we may either succeed,
+ * fail with ENODEV, or fail with EOVERFLOW.
+ */
+ if (expected_error == ENOTSUP &&
+ (error == 0 || error == ENODEV || error == EOVERFLOW))
+ expected_error = error;
+
+ /*
+ * If someone grew the LUN, the replacement may be too small.
+ */
+ if (error == EOVERFLOW || error == EBUSY)
+ expected_error = error;
+
+ if (error == ZFS_ERR_CHECKPOINT_EXISTS ||
+ error == ZFS_ERR_DISCARDING_CHECKPOINT)
+ expected_error = error;
+
+ /* XXX workaround 6690467 */
+ if (error != expected_error && expected_error != EBUSY) {
+ fatal(0, "attach (%s %llu, %s %llu, %d) "
+ "returned %d, expected %d",
+ oldpath, oldsize, newpath,
+ newsize, replacing, error, expected_error);
+ }
+
+ mutex_exit(&ztest_vdev_lock);
+}
+
+/* ARGSUSED */
+void
+ztest_device_removal(ztest_ds_t *zd, uint64_t id)
+{
+ spa_t *spa = ztest_spa;
+ vdev_t *vd;
+ uint64_t guid;
+ int error;
+
+ mutex_enter(&ztest_vdev_lock);
+
+ if (ztest_device_removal_active) {
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ /*
+ * Remove a random top-level vdev and wait for removal to finish.
+ */
+ spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+ vd = vdev_lookup_top(spa, ztest_random_vdev_top(spa, B_FALSE));
+ guid = vd->vdev_guid;
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+
+ error = spa_vdev_remove(spa, guid, B_FALSE);
+ if (error == 0) {
+ ztest_device_removal_active = B_TRUE;
+ mutex_exit(&ztest_vdev_lock);
+
+ while (spa->spa_vdev_removal != NULL)
+ txg_wait_synced(spa_get_dsl(spa), 0);
+ } else {
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ /*
+ * The pool needs to be scrubbed after completing device removal.
+ * Failure to do so may result in checksum errors due to the
+ * strategy employed by ztest_fault_inject() when selecting which
+ * offset are redundant and can be damaged.
+ */
+ error = spa_scan(spa, POOL_SCAN_SCRUB);
+ if (error == 0) {
+ while (dsl_scan_scrubbing(spa_get_dsl(spa)))
+ txg_wait_synced(spa_get_dsl(spa), 0);
+ }
+
+ mutex_enter(&ztest_vdev_lock);
+ ztest_device_removal_active = B_FALSE;
+ mutex_exit(&ztest_vdev_lock);
+}
+
+/*
+ * Callback function which expands the physical size of the vdev.
+ */
+vdev_t *
+grow_vdev(vdev_t *vd, void *arg)
+{
+ spa_t *spa = vd->vdev_spa;
+ size_t *newsize = arg;
+ size_t fsize;
+ int fd;
+
+ ASSERT(spa_config_held(spa, SCL_STATE, RW_READER) == SCL_STATE);
+ ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+ if ((fd = open(vd->vdev_path, O_RDWR)) == -1)
+ return (vd);
+
+ fsize = lseek(fd, 0, SEEK_END);
+ (void) ftruncate(fd, *newsize);
+
+ if (ztest_opts.zo_verbose >= 6) {
+ (void) printf("%s grew from %lu to %lu bytes\n",
+ vd->vdev_path, (ulong_t)fsize, (ulong_t)*newsize);
+ }
+ (void) close(fd);
+ return (NULL);
+}
+
+/*
+ * Callback function which expands a given vdev by calling vdev_online().
+ */
+/* ARGSUSED */
+vdev_t *
+online_vdev(vdev_t *vd, void *arg)
+{
+ spa_t *spa = vd->vdev_spa;
+ vdev_t *tvd = vd->vdev_top;
+ uint64_t guid = vd->vdev_guid;
+ uint64_t generation = spa->spa_config_generation + 1;
+ vdev_state_t newstate = VDEV_STATE_UNKNOWN;
+ int error;
+
+ ASSERT(spa_config_held(spa, SCL_STATE, RW_READER) == SCL_STATE);
+ ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+ /* Calling vdev_online will initialize the new metaslabs */
+ spa_config_exit(spa, SCL_STATE, spa);
+ error = vdev_online(spa, guid, ZFS_ONLINE_EXPAND, &newstate);
+ spa_config_enter(spa, SCL_STATE, spa, RW_READER);
+
+ /*
+ * If vdev_online returned an error or the underlying vdev_open
+ * failed then we abort the expand. The only way to know that
+ * vdev_open fails is by checking the returned newstate.
+ */
+ if (error || newstate != VDEV_STATE_HEALTHY) {
+ if (ztest_opts.zo_verbose >= 5) {
+ (void) printf("Unable to expand vdev, state %llu, "
+ "error %d\n", (u_longlong_t)newstate, error);
+ }
+ return (vd);
+ }
+ ASSERT3U(newstate, ==, VDEV_STATE_HEALTHY);
+
+ /*
+ * Since we dropped the lock we need to ensure that we're
+ * still talking to the original vdev. It's possible this
+ * vdev may have been detached/replaced while we were
+ * trying to online it.
+ */
+ if (generation != spa->spa_config_generation) {
+ if (ztest_opts.zo_verbose >= 5) {
+ (void) printf("vdev configuration has changed, "
+ "guid %llu, state %llu, expected gen %llu, "
+ "got gen %llu\n",
+ (u_longlong_t)guid,
+ (u_longlong_t)tvd->vdev_state,
+ (u_longlong_t)generation,
+ (u_longlong_t)spa->spa_config_generation);
+ }
+ return (vd);
+ }
+ return (NULL);
+}
+
+/*
+ * Traverse the vdev tree calling the supplied function.
+ * We continue to walk the tree until we either have walked all
+ * children or we receive a non-NULL return from the callback.
+ * If a NULL callback is passed, then we just return back the first
+ * leaf vdev we encounter.
+ */
+vdev_t *
+vdev_walk_tree(vdev_t *vd, vdev_t *(*func)(vdev_t *, void *), void *arg)
+{
+ if (vd->vdev_ops->vdev_op_leaf) {
+ if (func == NULL)
+ return (vd);
+ else
+ return (func(vd, arg));
+ }
+
+ for (uint_t c = 0; c < vd->vdev_children; c++) {
+ vdev_t *cvd = vd->vdev_child[c];
+ if ((cvd = vdev_walk_tree(cvd, func, arg)) != NULL)
+ return (cvd);
+ }
+ return (NULL);
+}
+
+/*
+ * Verify that dynamic LUN growth works as expected.
+ */
+/* ARGSUSED */
+void
+ztest_vdev_LUN_growth(ztest_ds_t *zd, uint64_t id)
+{
+ spa_t *spa = ztest_spa;
+ vdev_t *vd, *tvd;
+ metaslab_class_t *mc;
+ metaslab_group_t *mg;
+ size_t psize, newsize;
+ uint64_t top;
+ uint64_t old_class_space, new_class_space, old_ms_count, new_ms_count;
+
+ mutex_enter(&ztest_checkpoint_lock);
+ mutex_enter(&ztest_vdev_lock);
+ spa_config_enter(spa, SCL_STATE, spa, RW_READER);
+
+ /*
+ * If there is a vdev removal in progress, it could complete while
+ * we are running, in which case we would not be able to verify
+ * that the metaslab_class space increased (because it decreases
+ * when the device removal completes).
+ */
+ if (ztest_device_removal_active) {
+ spa_config_exit(spa, SCL_STATE, spa);
+ mutex_exit(&ztest_vdev_lock);
+ mutex_exit(&ztest_checkpoint_lock);
+ return;
+ }
+
+ top = ztest_random_vdev_top(spa, B_TRUE);
+
+ tvd = spa->spa_root_vdev->vdev_child[top];
+ mg = tvd->vdev_mg;
+ mc = mg->mg_class;
+ old_ms_count = tvd->vdev_ms_count;
+ old_class_space = metaslab_class_get_space(mc);
+
+ /*
+ * Determine the size of the first leaf vdev associated with
+ * our top-level device.
+ */
+ vd = vdev_walk_tree(tvd, NULL, NULL);
+ ASSERT3P(vd, !=, NULL);
+ ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+ psize = vd->vdev_psize;
+
+ /*
+ * We only try to expand the vdev if it's healthy, less than 4x its
+ * original size, and it has a valid psize.
+ */
+ if (tvd->vdev_state != VDEV_STATE_HEALTHY ||
+ psize == 0 || psize >= 4 * ztest_opts.zo_vdev_size) {
+ spa_config_exit(spa, SCL_STATE, spa);
+ mutex_exit(&ztest_vdev_lock);
+ mutex_exit(&ztest_checkpoint_lock);
+ return;
+ }
+ ASSERT(psize > 0);
+ newsize = psize + MAX(psize / 8, SPA_MAXBLOCKSIZE);
+ ASSERT3U(newsize, >, psize);
+
+ if (ztest_opts.zo_verbose >= 6) {
+ (void) printf("Expanding LUN %s from %lu to %lu\n",
+ vd->vdev_path, (ulong_t)psize, (ulong_t)newsize);
+ }
+
+ /*
+ * Growing the vdev is a two step process:
+ * 1). expand the physical size (i.e. relabel)
+ * 2). online the vdev to create the new metaslabs
+ */
+ if (vdev_walk_tree(tvd, grow_vdev, &newsize) != NULL ||
+ vdev_walk_tree(tvd, online_vdev, NULL) != NULL ||
+ tvd->vdev_state != VDEV_STATE_HEALTHY) {
+ if (ztest_opts.zo_verbose >= 5) {
+ (void) printf("Could not expand LUN because "
+ "the vdev configuration changed.\n");
+ }
+ spa_config_exit(spa, SCL_STATE, spa);
+ mutex_exit(&ztest_vdev_lock);
+ mutex_exit(&ztest_checkpoint_lock);
+ return;
+ }
+
+ spa_config_exit(spa, SCL_STATE, spa);
+
+ /*
+ * Expanding the LUN will update the config asynchronously,
+ * thus we must wait for the async thread to complete any
+ * pending tasks before proceeding.
+ */
+ for (;;) {
+ boolean_t done;
+ mutex_enter(&spa->spa_async_lock);
+ done = (spa->spa_async_thread == NULL && !spa->spa_async_tasks);
+ mutex_exit(&spa->spa_async_lock);
+ if (done)
+ break;
+ txg_wait_synced(spa_get_dsl(spa), 0);
+ (void) poll(NULL, 0, 100);
+ }
+
+ spa_config_enter(spa, SCL_STATE, spa, RW_READER);
+
+ tvd = spa->spa_root_vdev->vdev_child[top];
+ new_ms_count = tvd->vdev_ms_count;
+ new_class_space = metaslab_class_get_space(mc);
+
+ if (tvd->vdev_mg != mg || mg->mg_class != mc) {
+ if (ztest_opts.zo_verbose >= 5) {
+ (void) printf("Could not verify LUN expansion due to "
+ "intervening vdev offline or remove.\n");
+ }
+ spa_config_exit(spa, SCL_STATE, spa);
+ mutex_exit(&ztest_vdev_lock);
+ mutex_exit(&ztest_checkpoint_lock);
+ return;
+ }
+
+ /*
+ * Make sure we were able to grow the vdev.
+ */
+ if (new_ms_count <= old_ms_count) {
+ fatal(0, "LUN expansion failed: ms_count %llu < %llu\n",
+ old_ms_count, new_ms_count);
+ }
+
+ /*
+ * Make sure we were able to grow the pool.
+ */
+ if (new_class_space <= old_class_space) {
+ fatal(0, "LUN expansion failed: class_space %llu < %llu\n",
+ old_class_space, new_class_space);
+ }
+
+ if (ztest_opts.zo_verbose >= 5) {
+ char oldnumbuf[NN_NUMBUF_SZ], newnumbuf[NN_NUMBUF_SZ];
+
+ nicenum(old_class_space, oldnumbuf, sizeof (oldnumbuf));
+ nicenum(new_class_space, newnumbuf, sizeof (newnumbuf));
+ (void) printf("%s grew from %s to %s\n",
+ spa->spa_name, oldnumbuf, newnumbuf);
+ }
+
+ spa_config_exit(spa, SCL_STATE, spa);
+ mutex_exit(&ztest_vdev_lock);
+ mutex_exit(&ztest_checkpoint_lock);
+}
+
+/*
+ * Verify that dmu_objset_{create,destroy,open,close} work as expected.
+ */
+/* ARGSUSED */
+static void
+ztest_objset_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
+{
+ /*
+ * Create the objects common to all ztest datasets.
+ */
+ VERIFY(zap_create_claim(os, ZTEST_DIROBJ,
+ DMU_OT_ZAP_OTHER, DMU_OT_NONE, 0, tx) == 0);
+}
+
+static int
+ztest_dataset_create(char *dsname)
+{
+ uint64_t zilset = ztest_random(100);
+ int err = dmu_objset_create(dsname, DMU_OST_OTHER, 0,
+ ztest_objset_create_cb, NULL);
+
+ if (err || zilset < 80)
+ return (err);
+
+ if (ztest_opts.zo_verbose >= 6)
+ (void) printf("Setting dataset %s to sync always\n", dsname);
+ return (ztest_dsl_prop_set_uint64(dsname, ZFS_PROP_SYNC,
+ ZFS_SYNC_ALWAYS, B_FALSE));
+}
+
+/* ARGSUSED */
+static int
+ztest_objset_destroy_cb(const char *name, void *arg)
+{
+ objset_t *os;
+ dmu_object_info_t doi;
+ int error;
+
+ /*
+ * Verify that the dataset contains a directory object.
+ */
+ VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, FTAG, &os));
+ error = dmu_object_info(os, ZTEST_DIROBJ, &doi);
+ if (error != ENOENT) {
+ /* We could have crashed in the middle of destroying it */
+ ASSERT0(error);
+ ASSERT3U(doi.doi_type, ==, DMU_OT_ZAP_OTHER);
+ ASSERT3S(doi.doi_physical_blocks_512, >=, 0);
+ }
+ dmu_objset_disown(os, FTAG);
+
+ /*
+ * Destroy the dataset.
+ */
+ if (strchr(name, '@') != NULL) {
+ VERIFY0(dsl_destroy_snapshot(name, B_FALSE));
+ } else {
+ VERIFY0(dsl_destroy_head(name));
+ }
+ return (0);
+}
+
+static boolean_t
+ztest_snapshot_create(char *osname, uint64_t id)
+{
+ char snapname[ZFS_MAX_DATASET_NAME_LEN];
+ int error;
+
+ (void) snprintf(snapname, sizeof (snapname), "%llu", (u_longlong_t)id);
+
+ error = dmu_objset_snapshot_one(osname, snapname);
+ if (error == ENOSPC) {
+ ztest_record_enospc(FTAG);
+ return (B_FALSE);
+ }
+ if (error != 0 && error != EEXIST) {
+ fatal(0, "ztest_snapshot_create(%s@%s) = %d", osname,
+ snapname, error);
+ }
+ return (B_TRUE);
+}
+
+static boolean_t
+ztest_snapshot_destroy(char *osname, uint64_t id)
+{
+ char snapname[ZFS_MAX_DATASET_NAME_LEN];
+ int error;
+
+ (void) snprintf(snapname, sizeof (snapname), "%s@%llu", osname,
+ (u_longlong_t)id);
+
+ error = dsl_destroy_snapshot(snapname, B_FALSE);
+ if (error != 0 && error != ENOENT)
+ fatal(0, "ztest_snapshot_destroy(%s) = %d", snapname, error);
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+void
+ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_ds_t zdtmp;
+ int iters;
+ int error;
+ objset_t *os, *os2;
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ zilog_t *zilog;
+
+ rw_enter(&ztest_name_lock, RW_READER);
+
+ (void) snprintf(name, sizeof (name), "%s/temp_%llu",
+ ztest_opts.zo_pool, (u_longlong_t)id);
+
+ /*
+ * If this dataset exists from a previous run, process its replay log
+ * half of the time. If we don't replay it, then dmu_objset_destroy()
+ * (invoked from ztest_objset_destroy_cb()) should just throw it away.
+ */
+ if (ztest_random(2) == 0 &&
+ dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os) == 0) {
+ ztest_zd_init(&zdtmp, NULL, os);
+ zil_replay(os, &zdtmp, ztest_replay_vector);
+ ztest_zd_fini(&zdtmp);
+ dmu_objset_disown(os, FTAG);
+ }
+
+ /*
+ * There may be an old instance of the dataset we're about to
+ * create lying around from a previous run. If so, destroy it
+ * and all of its snapshots.
+ */
+ (void) dmu_objset_find(name, ztest_objset_destroy_cb, NULL,
+ DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
+
+ /*
+ * Verify that the destroyed dataset is no longer in the namespace.
+ */
+ VERIFY3U(ENOENT, ==, dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
+ FTAG, &os));
+
+ /*
+ * Verify that we can create a new dataset.
+ */
+ error = ztest_dataset_create(name);
+ if (error) {
+ if (error == ENOSPC) {
+ ztest_record_enospc(FTAG);
+ rw_exit(&ztest_name_lock);
+ return;
+ }
+ fatal(0, "dmu_objset_create(%s) = %d", name, error);
+ }
+
+ VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os));
+
+ ztest_zd_init(&zdtmp, NULL, os);
+
+ /*
+ * Open the intent log for it.
+ */
+ zilog = zil_open(os, ztest_get_data);
+
+ /*
+ * Put some objects in there, do a little I/O to them,
+ * and randomly take a couple of snapshots along the way.
+ */
+ iters = ztest_random(5);
+ for (int i = 0; i < iters; i++) {
+ ztest_dmu_object_alloc_free(&zdtmp, id);
+ if (ztest_random(iters) == 0)
+ (void) ztest_snapshot_create(name, i);
+ }
+
+ /*
+ * Verify that we cannot create an existing dataset.
+ */
+ VERIFY3U(EEXIST, ==,
+ dmu_objset_create(name, DMU_OST_OTHER, 0, NULL, NULL));
+
+ /*
+ * Verify that we can hold an objset that is also owned.
+ */
+ VERIFY3U(0, ==, dmu_objset_hold(name, FTAG, &os2));
+ dmu_objset_rele(os2, FTAG);
+
+ /*
+ * Verify that we cannot own an objset that is already owned.
+ */
+ VERIFY3U(EBUSY, ==,
+ dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os2));
+
+ zil_close(zilog);
+ dmu_objset_disown(os, FTAG);
+ ztest_zd_fini(&zdtmp);
+
+ rw_exit(&ztest_name_lock);
+}
+
+/*
+ * Verify that dmu_snapshot_{create,destroy,open,close} work as expected.
+ */
+void
+ztest_dmu_snapshot_create_destroy(ztest_ds_t *zd, uint64_t id)
+{
+ rw_enter(&ztest_name_lock, RW_READER);
+ (void) ztest_snapshot_destroy(zd->zd_name, id);
+ (void) ztest_snapshot_create(zd->zd_name, id);
+ rw_exit(&ztest_name_lock);
+}
+
+/*
+ * Cleanup non-standard snapshots and clones.
+ */
+void
+ztest_dsl_dataset_cleanup(char *osname, uint64_t id)
+{
+ char snap1name[ZFS_MAX_DATASET_NAME_LEN];
+ char clone1name[ZFS_MAX_DATASET_NAME_LEN];
+ char snap2name[ZFS_MAX_DATASET_NAME_LEN];
+ char clone2name[ZFS_MAX_DATASET_NAME_LEN];
+ char snap3name[ZFS_MAX_DATASET_NAME_LEN];
+ int error;
+
+ (void) snprintf(snap1name, sizeof (snap1name),
+ "%s@s1_%llu", osname, id);
+ (void) snprintf(clone1name, sizeof (clone1name),
+ "%s/c1_%llu", osname, id);
+ (void) snprintf(snap2name, sizeof (snap2name),
+ "%s@s2_%llu", clone1name, id);
+ (void) snprintf(clone2name, sizeof (clone2name),
+ "%s/c2_%llu", osname, id);
+ (void) snprintf(snap3name, sizeof (snap3name),
+ "%s@s3_%llu", clone1name, id);
+
+ error = dsl_destroy_head(clone2name);
+ if (error && error != ENOENT)
+ fatal(0, "dsl_destroy_head(%s) = %d", clone2name, error);
+ error = dsl_destroy_snapshot(snap3name, B_FALSE);
+ if (error && error != ENOENT)
+ fatal(0, "dsl_destroy_snapshot(%s) = %d", snap3name, error);
+ error = dsl_destroy_snapshot(snap2name, B_FALSE);
+ if (error && error != ENOENT)
+ fatal(0, "dsl_destroy_snapshot(%s) = %d", snap2name, error);
+ error = dsl_destroy_head(clone1name);
+ if (error && error != ENOENT)
+ fatal(0, "dsl_destroy_head(%s) = %d", clone1name, error);
+ error = dsl_destroy_snapshot(snap1name, B_FALSE);
+ if (error && error != ENOENT)
+ fatal(0, "dsl_destroy_snapshot(%s) = %d", snap1name, error);
+}
+
+/*
+ * Verify dsl_dataset_promote handles EBUSY
+ */
+void
+ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os;
+ char snap1name[ZFS_MAX_DATASET_NAME_LEN];
+ char clone1name[ZFS_MAX_DATASET_NAME_LEN];
+ char snap2name[ZFS_MAX_DATASET_NAME_LEN];
+ char clone2name[ZFS_MAX_DATASET_NAME_LEN];
+ char snap3name[ZFS_MAX_DATASET_NAME_LEN];
+ char *osname = zd->zd_name;
+ int error;
+
+ rw_enter(&ztest_name_lock, RW_READER);
+
+ ztest_dsl_dataset_cleanup(osname, id);
+
+ (void) snprintf(snap1name, sizeof (snap1name),
+ "%s@s1_%llu", osname, id);
+ (void) snprintf(clone1name, sizeof (clone1name),
+ "%s/c1_%llu", osname, id);
+ (void) snprintf(snap2name, sizeof (snap2name),
+ "%s@s2_%llu", clone1name, id);
+ (void) snprintf(clone2name, sizeof (clone2name),
+ "%s/c2_%llu", osname, id);
+ (void) snprintf(snap3name, sizeof (snap3name),
+ "%s@s3_%llu", clone1name, id);
+
+ error = dmu_objset_snapshot_one(osname, strchr(snap1name, '@') + 1);
+ if (error && error != EEXIST) {
+ if (error == ENOSPC) {
+ ztest_record_enospc(FTAG);
+ goto out;
+ }
+ fatal(0, "dmu_take_snapshot(%s) = %d", snap1name, error);
+ }
+
+ error = dmu_objset_clone(clone1name, snap1name);
+ if (error) {
+ if (error == ENOSPC) {
+ ztest_record_enospc(FTAG);
+ goto out;
+ }
+ fatal(0, "dmu_objset_create(%s) = %d", clone1name, error);
+ }
+
+ error = dmu_objset_snapshot_one(clone1name, strchr(snap2name, '@') + 1);
+ if (error && error != EEXIST) {
+ if (error == ENOSPC) {
+ ztest_record_enospc(FTAG);
+ goto out;
+ }
+ fatal(0, "dmu_open_snapshot(%s) = %d", snap2name, error);
+ }
+
+ error = dmu_objset_snapshot_one(clone1name, strchr(snap3name, '@') + 1);
+ if (error && error != EEXIST) {
+ if (error == ENOSPC) {
+ ztest_record_enospc(FTAG);
+ goto out;
+ }
+ fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
+ }
+
+ error = dmu_objset_clone(clone2name, snap3name);
+ if (error) {
+ if (error == ENOSPC) {
+ ztest_record_enospc(FTAG);
+ goto out;
+ }
+ fatal(0, "dmu_objset_create(%s) = %d", clone2name, error);
+ }
+
+ error = dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, FTAG, &os);
+ if (error)
+ fatal(0, "dmu_objset_own(%s) = %d", snap2name, error);
+ error = dsl_dataset_promote(clone2name, NULL);
+ if (error == ENOSPC) {
+ dmu_objset_disown(os, FTAG);
+ ztest_record_enospc(FTAG);
+ goto out;
+ }
+ if (error != EBUSY)
+ fatal(0, "dsl_dataset_promote(%s), %d, not EBUSY", clone2name,
+ error);
+ dmu_objset_disown(os, FTAG);
+
+out:
+ ztest_dsl_dataset_cleanup(osname, id);
+
+ rw_exit(&ztest_name_lock);
+}
+
+/*
+ * Verify that dmu_object_{alloc,free} work as expected.
+ */
+void
+ztest_dmu_object_alloc_free(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_od_t od[4];
+ int batchsize = sizeof (od) / sizeof (od[0]);
+
+ for (int b = 0; b < batchsize; b++) {
+ ztest_od_init(&od[b], id, FTAG, b, DMU_OT_UINT64_OTHER,
+ 0, 0, 0);
+ }
+
+ /*
+ * Destroy the previous batch of objects, create a new batch,
+ * and do some I/O on the new objects.
+ */
+ if (ztest_object_init(zd, od, sizeof (od), B_TRUE) != 0)
+ return;
+
+ while (ztest_random(4 * batchsize) != 0)
+ ztest_io(zd, od[ztest_random(batchsize)].od_object,
+ ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
+}
+
+/*
+ * Rewind the global allocator to verify object allocation backfilling.
+ */
+void
+ztest_dmu_object_next_chunk(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+ int dnodes_per_chunk = 1 << dmu_object_alloc_chunk_shift;
+ uint64_t object;
+
+ /*
+ * Rewind the global allocator randomly back to a lower object number
+ * to force backfilling and reclamation of recently freed dnodes.
+ */
+ mutex_enter(&os->os_obj_lock);
+ object = ztest_random(os->os_obj_next_chunk);
+ os->os_obj_next_chunk = P2ALIGN(object, dnodes_per_chunk);
+ mutex_exit(&os->os_obj_lock);
+}
+
+/*
+ * Verify that dmu_{read,write} work as expected.
+ */
+void
+ztest_dmu_read_write(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+ ztest_od_t od[2];
+ dmu_tx_t *tx;
+ int i, freeit, error;
+ uint64_t n, s, txg;
+ bufwad_t *packbuf, *bigbuf, *pack, *bigH, *bigT;
+ uint64_t packobj, packoff, packsize, bigobj, bigoff, bigsize;
+ uint64_t chunksize = (1000 + ztest_random(1000)) * sizeof (uint64_t);
+ uint64_t regions = 997;
+ uint64_t stride = 123456789ULL;
+ uint64_t width = 40;
+ int free_percent = 5;
+
+ /*
+ * This test uses two objects, packobj and bigobj, that are always
+ * updated together (i.e. in the same tx) so that their contents are
+ * in sync and can be compared. Their contents relate to each other
+ * in a simple way: packobj is a dense array of 'bufwad' structures,
+ * while bigobj is a sparse array of the same bufwads. Specifically,
+ * for any index n, there are three bufwads that should be identical:
+ *
+ * packobj, at offset n * sizeof (bufwad_t)
+ * bigobj, at the head of the nth chunk
+ * bigobj, at the tail of the nth chunk
+ *
+ * The chunk size is arbitrary. It doesn't have to be a power of two,
+ * and it doesn't have any relation to the object blocksize.
+ * The only requirement is that it can hold at least two bufwads.
+ *
+ * Normally, we write the bufwad to each of these locations.
+ * However, free_percent of the time we instead write zeroes to
+ * packobj and perform a dmu_free_range() on bigobj. By comparing
+ * bigobj to packobj, we can verify that the DMU is correctly
+ * tracking which parts of an object are allocated and free,
+ * and that the contents of the allocated blocks are correct.
+ */
+
+ /*
+ * Read the directory info. If it's the first time, set things up.
+ */
+ ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0,
+ chunksize);
+ ztest_od_init(&od[1], id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, 0,
+ chunksize);
+
+ if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0)
+ return;
+
+ bigobj = od[0].od_object;
+ packobj = od[1].od_object;
+ chunksize = od[0].od_gen;
+ ASSERT(chunksize == od[1].od_gen);
+
+ /*
+ * Prefetch a random chunk of the big object.
+ * Our aim here is to get some async reads in flight
+ * for blocks that we may free below; the DMU should
+ * handle this race correctly.
+ */
+ n = ztest_random(regions) * stride + ztest_random(width);
+ s = 1 + ztest_random(2 * width - 1);
+ dmu_prefetch(os, bigobj, 0, n * chunksize, s * chunksize,
+ ZIO_PRIORITY_SYNC_READ);
+
+ /*
+ * Pick a random index and compute the offsets into packobj and bigobj.
+ */
+ n = ztest_random(regions) * stride + ztest_random(width);
+ s = 1 + ztest_random(width - 1);
+
+ packoff = n * sizeof (bufwad_t);
+ packsize = s * sizeof (bufwad_t);
+
+ bigoff = n * chunksize;
+ bigsize = s * chunksize;
+
+ packbuf = umem_alloc(packsize, UMEM_NOFAIL);
+ bigbuf = umem_alloc(bigsize, UMEM_NOFAIL);
+
+ /*
+ * free_percent of the time, free a range of bigobj rather than
+ * overwriting it.
+ */
+ freeit = (ztest_random(100) < free_percent);
+
+ /*
+ * Read the current contents of our objects.
+ */
+ error = dmu_read(os, packobj, packoff, packsize, packbuf,
+ DMU_READ_PREFETCH);
+ ASSERT0(error);
+ error = dmu_read(os, bigobj, bigoff, bigsize, bigbuf,
+ DMU_READ_PREFETCH);
+ ASSERT0(error);
+
+ /*
+ * Get a tx for the mods to both packobj and bigobj.
+ */
+ tx = dmu_tx_create(os);
+
+ dmu_tx_hold_write(tx, packobj, packoff, packsize);
+
+ if (freeit)
+ dmu_tx_hold_free(tx, bigobj, bigoff, bigsize);
+ else
+ dmu_tx_hold_write(tx, bigobj, bigoff, bigsize);
+
+ /* This accounts for setting the checksum/compression. */
+ dmu_tx_hold_bonus(tx, bigobj);
+
+ txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+ if (txg == 0) {
+ umem_free(packbuf, packsize);
+ umem_free(bigbuf, bigsize);
+ return;
+ }
+
+ enum zio_checksum cksum;
+ do {
+ cksum = (enum zio_checksum)
+ ztest_random_dsl_prop(ZFS_PROP_CHECKSUM);
+ } while (cksum >= ZIO_CHECKSUM_LEGACY_FUNCTIONS);
+ dmu_object_set_checksum(os, bigobj, cksum, tx);
+
+ enum zio_compress comp;
+ do {
+ comp = (enum zio_compress)
+ ztest_random_dsl_prop(ZFS_PROP_COMPRESSION);
+ } while (comp >= ZIO_COMPRESS_LEGACY_FUNCTIONS);
+ dmu_object_set_compress(os, bigobj, comp, tx);
+
+ /*
+ * For each index from n to n + s, verify that the existing bufwad
+ * in packobj matches the bufwads at the head and tail of the
+ * corresponding chunk in bigobj. Then update all three bufwads
+ * with the new values we want to write out.
+ */
+ for (i = 0; i < s; i++) {
+ /* LINTED */
+ pack = (bufwad_t *)((char *)packbuf + i * sizeof (bufwad_t));
+ /* LINTED */
+ bigH = (bufwad_t *)((char *)bigbuf + i * chunksize);
+ /* LINTED */
+ bigT = (bufwad_t *)((char *)bigH + chunksize) - 1;
+
+ ASSERT((uintptr_t)bigH - (uintptr_t)bigbuf < bigsize);
+ ASSERT((uintptr_t)bigT - (uintptr_t)bigbuf < bigsize);
+
+ if (pack->bw_txg > txg)
+ fatal(0, "future leak: got %llx, open txg is %llx",
+ pack->bw_txg, txg);
+
+ if (pack->bw_data != 0 && pack->bw_index != n + i)
+ fatal(0, "wrong index: got %llx, wanted %llx+%llx",
+ pack->bw_index, n, i);
+
+ if (bcmp(pack, bigH, sizeof (bufwad_t)) != 0)
+ fatal(0, "pack/bigH mismatch in %p/%p", pack, bigH);
+
+ if (bcmp(pack, bigT, sizeof (bufwad_t)) != 0)
+ fatal(0, "pack/bigT mismatch in %p/%p", pack, bigT);
+
+ if (freeit) {
+ bzero(pack, sizeof (bufwad_t));
+ } else {
+ pack->bw_index = n + i;
+ pack->bw_txg = txg;
+ pack->bw_data = 1 + ztest_random(-2ULL);
+ }
+ *bigH = *pack;
+ *bigT = *pack;
+ }
+
+ /*
+ * We've verified all the old bufwads, and made new ones.
+ * Now write them out.
+ */
+ dmu_write(os, packobj, packoff, packsize, packbuf, tx);
+
+ if (freeit) {
+ if (ztest_opts.zo_verbose >= 7) {
+ (void) printf("freeing offset %llx size %llx"
+ " txg %llx\n",
+ (u_longlong_t)bigoff,
+ (u_longlong_t)bigsize,
+ (u_longlong_t)txg);
+ }
+ VERIFY(0 == dmu_free_range(os, bigobj, bigoff, bigsize, tx));
+ } else {
+ if (ztest_opts.zo_verbose >= 7) {
+ (void) printf("writing offset %llx size %llx"
+ " txg %llx\n",
+ (u_longlong_t)bigoff,
+ (u_longlong_t)bigsize,
+ (u_longlong_t)txg);
+ }
+ dmu_write(os, bigobj, bigoff, bigsize, bigbuf, tx);
+ }
+
+ dmu_tx_commit(tx);
+
+ /*
+ * Sanity check the stuff we just wrote.
+ */
+ {
+ void *packcheck = umem_alloc(packsize, UMEM_NOFAIL);
+ void *bigcheck = umem_alloc(bigsize, UMEM_NOFAIL);
+
+ VERIFY(0 == dmu_read(os, packobj, packoff,
+ packsize, packcheck, DMU_READ_PREFETCH));
+ VERIFY(0 == dmu_read(os, bigobj, bigoff,
+ bigsize, bigcheck, DMU_READ_PREFETCH));
+
+ ASSERT(bcmp(packbuf, packcheck, packsize) == 0);
+ ASSERT(bcmp(bigbuf, bigcheck, bigsize) == 0);
+
+ umem_free(packcheck, packsize);
+ umem_free(bigcheck, bigsize);
+ }
+
+ umem_free(packbuf, packsize);
+ umem_free(bigbuf, bigsize);
+}
+
+void
+compare_and_update_pbbufs(uint64_t s, bufwad_t *packbuf, bufwad_t *bigbuf,
+ uint64_t bigsize, uint64_t n, uint64_t chunksize, uint64_t txg)
+{
+ uint64_t i;
+ bufwad_t *pack;
+ bufwad_t *bigH;
+ bufwad_t *bigT;
+
+ /*
+ * For each index from n to n + s, verify that the existing bufwad
+ * in packobj matches the bufwads at the head and tail of the
+ * corresponding chunk in bigobj. Then update all three bufwads
+ * with the new values we want to write out.
+ */
+ for (i = 0; i < s; i++) {
+ /* LINTED */
+ pack = (bufwad_t *)((char *)packbuf + i * sizeof (bufwad_t));
+ /* LINTED */
+ bigH = (bufwad_t *)((char *)bigbuf + i * chunksize);
+ /* LINTED */
+ bigT = (bufwad_t *)((char *)bigH + chunksize) - 1;
+
+ ASSERT((uintptr_t)bigH - (uintptr_t)bigbuf < bigsize);
+ ASSERT((uintptr_t)bigT - (uintptr_t)bigbuf < bigsize);
+
+ if (pack->bw_txg > txg)
+ fatal(0, "future leak: got %llx, open txg is %llx",
+ pack->bw_txg, txg);
+
+ if (pack->bw_data != 0 && pack->bw_index != n + i)
+ fatal(0, "wrong index: got %llx, wanted %llx+%llx",
+ pack->bw_index, n, i);
+
+ if (bcmp(pack, bigH, sizeof (bufwad_t)) != 0)
+ fatal(0, "pack/bigH mismatch in %p/%p", pack, bigH);
+
+ if (bcmp(pack, bigT, sizeof (bufwad_t)) != 0)
+ fatal(0, "pack/bigT mismatch in %p/%p", pack, bigT);
+
+ pack->bw_index = n + i;
+ pack->bw_txg = txg;
+ pack->bw_data = 1 + ztest_random(-2ULL);
+
+ *bigH = *pack;
+ *bigT = *pack;
+ }
+}
+
+void
+ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+ ztest_od_t od[2];
+ dmu_tx_t *tx;
+ uint64_t i;
+ int error;
+ uint64_t n, s, txg;
+ bufwad_t *packbuf, *bigbuf;
+ uint64_t packobj, packoff, packsize, bigobj, bigoff, bigsize;
+ uint64_t blocksize = ztest_random_blocksize();
+ uint64_t chunksize = blocksize;
+ uint64_t regions = 997;
+ uint64_t stride = 123456789ULL;
+ uint64_t width = 9;
+ dmu_buf_t *bonus_db;
+ arc_buf_t **bigbuf_arcbufs;
+ dmu_object_info_t doi;
+
+ /*
+ * This test uses two objects, packobj and bigobj, that are always
+ * updated together (i.e. in the same tx) so that their contents are
+ * in sync and can be compared. Their contents relate to each other
+ * in a simple way: packobj is a dense array of 'bufwad' structures,
+ * while bigobj is a sparse array of the same bufwads. Specifically,
+ * for any index n, there are three bufwads that should be identical:
+ *
+ * packobj, at offset n * sizeof (bufwad_t)
+ * bigobj, at the head of the nth chunk
+ * bigobj, at the tail of the nth chunk
+ *
+ * The chunk size is set equal to bigobj block size so that
+ * dmu_assign_arcbuf() can be tested for object updates.
+ */
+
+ /*
+ * Read the directory info. If it's the first time, set things up.
+ */
+ ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize,
+ 0, 0);
+ ztest_od_init(&od[1], id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, 0,
+ chunksize);
+
+ if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0)
+ return;
+
+ bigobj = od[0].od_object;
+ packobj = od[1].od_object;
+ blocksize = od[0].od_blocksize;
+ chunksize = blocksize;
+ ASSERT(chunksize == od[1].od_gen);
+
+ VERIFY(dmu_object_info(os, bigobj, &doi) == 0);
+ VERIFY(ISP2(doi.doi_data_block_size));
+ VERIFY(chunksize == doi.doi_data_block_size);
+ VERIFY(chunksize >= 2 * sizeof (bufwad_t));
+
+ /*
+ * Pick a random index and compute the offsets into packobj and bigobj.
+ */
+ n = ztest_random(regions) * stride + ztest_random(width);
+ s = 1 + ztest_random(width - 1);
+
+ packoff = n * sizeof (bufwad_t);
+ packsize = s * sizeof (bufwad_t);
+
+ bigoff = n * chunksize;
+ bigsize = s * chunksize;
+
+ packbuf = umem_zalloc(packsize, UMEM_NOFAIL);
+ bigbuf = umem_zalloc(bigsize, UMEM_NOFAIL);
+
+ VERIFY3U(0, ==, dmu_bonus_hold(os, bigobj, FTAG, &bonus_db));
+
+ bigbuf_arcbufs = umem_zalloc(2 * s * sizeof (arc_buf_t *), UMEM_NOFAIL);
+
+ /*
+ * Iteration 0 test zcopy for DB_UNCACHED dbufs.
+ * Iteration 1 test zcopy to already referenced dbufs.
+ * Iteration 2 test zcopy to dirty dbuf in the same txg.
+ * Iteration 3 test zcopy to dbuf dirty in previous txg.
+ * Iteration 4 test zcopy when dbuf is no longer dirty.
+ * Iteration 5 test zcopy when it can't be done.
+ * Iteration 6 one more zcopy write.
+ */
+ for (i = 0; i < 7; i++) {
+ uint64_t j;
+ uint64_t off;
+
+ /*
+ * In iteration 5 (i == 5) use arcbufs
+ * that don't match bigobj blksz to test
+ * dmu_assign_arcbuf() when it can't directly
+ * assign an arcbuf to a dbuf.
+ */
+ for (j = 0; j < s; j++) {
+ if (i != 5) {
+ bigbuf_arcbufs[j] =
+ dmu_request_arcbuf(bonus_db, chunksize);
+ } else {
+ bigbuf_arcbufs[2 * j] =
+ dmu_request_arcbuf(bonus_db, chunksize / 2);
+ bigbuf_arcbufs[2 * j + 1] =
+ dmu_request_arcbuf(bonus_db, chunksize / 2);
+ }
+ }
+
+ /*
+ * Get a tx for the mods to both packobj and bigobj.
+ */
+ tx = dmu_tx_create(os);
+
+ dmu_tx_hold_write(tx, packobj, packoff, packsize);
+ dmu_tx_hold_write(tx, bigobj, bigoff, bigsize);
+
+ txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+ if (txg == 0) {
+ umem_free(packbuf, packsize);
+ umem_free(bigbuf, bigsize);
+ for (j = 0; j < s; j++) {
+ if (i != 5) {
+ dmu_return_arcbuf(bigbuf_arcbufs[j]);
+ } else {
+ dmu_return_arcbuf(
+ bigbuf_arcbufs[2 * j]);
+ dmu_return_arcbuf(
+ bigbuf_arcbufs[2 * j + 1]);
+ }
+ }
+ umem_free(bigbuf_arcbufs, 2 * s * sizeof (arc_buf_t *));
+ dmu_buf_rele(bonus_db, FTAG);
+ return;
+ }
+
+ /*
+ * 50% of the time don't read objects in the 1st iteration to
+ * test dmu_assign_arcbuf() for the case when there're no
+ * existing dbufs for the specified offsets.
+ */
+ if (i != 0 || ztest_random(2) != 0) {
+ error = dmu_read(os, packobj, packoff,
+ packsize, packbuf, DMU_READ_PREFETCH);
+ ASSERT0(error);
+ error = dmu_read(os, bigobj, bigoff, bigsize,
+ bigbuf, DMU_READ_PREFETCH);
+ ASSERT0(error);
+ }
+ compare_and_update_pbbufs(s, packbuf, bigbuf, bigsize,
+ n, chunksize, txg);
+
+ /*
+ * We've verified all the old bufwads, and made new ones.
+ * Now write them out.
+ */
+ dmu_write(os, packobj, packoff, packsize, packbuf, tx);
+ if (ztest_opts.zo_verbose >= 7) {
+ (void) printf("writing offset %llx size %llx"
+ " txg %llx\n",
+ (u_longlong_t)bigoff,
+ (u_longlong_t)bigsize,
+ (u_longlong_t)txg);
+ }
+ for (off = bigoff, j = 0; j < s; j++, off += chunksize) {
+ dmu_buf_t *dbt;
+ if (i != 5) {
+ bcopy((caddr_t)bigbuf + (off - bigoff),
+ bigbuf_arcbufs[j]->b_data, chunksize);
+ } else {
+ bcopy((caddr_t)bigbuf + (off - bigoff),
+ bigbuf_arcbufs[2 * j]->b_data,
+ chunksize / 2);
+ bcopy((caddr_t)bigbuf + (off - bigoff) +
+ chunksize / 2,
+ bigbuf_arcbufs[2 * j + 1]->b_data,
+ chunksize / 2);
+ }
+
+ if (i == 1) {
+ VERIFY(dmu_buf_hold(os, bigobj, off,
+ FTAG, &dbt, DMU_READ_NO_PREFETCH) == 0);
+ }
+ if (i != 5) {
+ dmu_assign_arcbuf(bonus_db, off,
+ bigbuf_arcbufs[j], tx);
+ } else {
+ dmu_assign_arcbuf(bonus_db, off,
+ bigbuf_arcbufs[2 * j], tx);
+ dmu_assign_arcbuf(bonus_db,
+ off + chunksize / 2,
+ bigbuf_arcbufs[2 * j + 1], tx);
+ }
+ if (i == 1) {
+ dmu_buf_rele(dbt, FTAG);
+ }
+ }
+ dmu_tx_commit(tx);
+
+ /*
+ * Sanity check the stuff we just wrote.
+ */
+ {
+ void *packcheck = umem_alloc(packsize, UMEM_NOFAIL);
+ void *bigcheck = umem_alloc(bigsize, UMEM_NOFAIL);
+
+ VERIFY(0 == dmu_read(os, packobj, packoff,
+ packsize, packcheck, DMU_READ_PREFETCH));
+ VERIFY(0 == dmu_read(os, bigobj, bigoff,
+ bigsize, bigcheck, DMU_READ_PREFETCH));
+
+ ASSERT(bcmp(packbuf, packcheck, packsize) == 0);
+ ASSERT(bcmp(bigbuf, bigcheck, bigsize) == 0);
+
+ umem_free(packcheck, packsize);
+ umem_free(bigcheck, bigsize);
+ }
+ if (i == 2) {
+ txg_wait_open(dmu_objset_pool(os), 0);
+ } else if (i == 3) {
+ txg_wait_synced(dmu_objset_pool(os), 0);
+ }
+ }
+
+ dmu_buf_rele(bonus_db, FTAG);
+ umem_free(packbuf, packsize);
+ umem_free(bigbuf, bigsize);
+ umem_free(bigbuf_arcbufs, 2 * s * sizeof (arc_buf_t *));
+}
+
+/* ARGSUSED */
+void
+ztest_dmu_write_parallel(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_od_t od[1];
+ uint64_t offset = (1ULL << (ztest_random(20) + 43)) +
+ (ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
+
+ /*
+ * Have multiple threads write to large offsets in an object
+ * to verify that parallel writes to an object -- even to the
+ * same blocks within the object -- doesn't cause any trouble.
+ */
+ ztest_od_init(&od[0], ID_PARALLEL, FTAG, 0, DMU_OT_UINT64_OTHER,
+ 0, 0, 0);
+
+ if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0)
+ return;
+
+ while (ztest_random(10) != 0)
+ ztest_io(zd, od[0].od_object, offset);
+}
+
+void
+ztest_dmu_prealloc(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_od_t od[1];
+ uint64_t offset = (1ULL << (ztest_random(4) + SPA_MAXBLOCKSHIFT)) +
+ (ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
+ uint64_t count = ztest_random(20) + 1;
+ uint64_t blocksize = ztest_random_blocksize();
+ void *data;
+
+ ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize,
+ 0, 0);
+
+ if (ztest_object_init(zd, od, sizeof (od), !ztest_random(2)) != 0)
+ return;
+
+ if (ztest_truncate(zd, od[0].od_object, offset, count * blocksize) != 0)
+ return;
+
+ ztest_prealloc(zd, od[0].od_object, offset, count * blocksize);
+
+ data = umem_zalloc(blocksize, UMEM_NOFAIL);
+
+ while (ztest_random(count) != 0) {
+ uint64_t randoff = offset + (ztest_random(count) * blocksize);
+ if (ztest_write(zd, od[0].od_object, randoff, blocksize,
+ data) != 0)
+ break;
+ while (ztest_random(4) != 0)
+ ztest_io(zd, od[0].od_object, randoff);
+ }
+
+ umem_free(data, blocksize);
+}
+
+/*
+ * Verify that zap_{create,destroy,add,remove,update} work as expected.
+ */
+#define ZTEST_ZAP_MIN_INTS 1
+#define ZTEST_ZAP_MAX_INTS 4
+#define ZTEST_ZAP_MAX_PROPS 1000
+
+void
+ztest_zap(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+ ztest_od_t od[1];
+ uint64_t object;
+ uint64_t txg, last_txg;
+ uint64_t value[ZTEST_ZAP_MAX_INTS];
+ uint64_t zl_ints, zl_intsize, prop;
+ int i, ints;
+ dmu_tx_t *tx;
+ char propname[100], txgname[100];
+ int error;
+ char *hc[2] = { "s.acl.h", ".s.open.h.hyLZlg" };
+
+ ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0, 0);
+
+ if (ztest_object_init(zd, od, sizeof (od), !ztest_random(2)) != 0)
+ return;
+
+ object = od[0].od_object;
+
+ /*
+ * Generate a known hash collision, and verify that
+ * we can lookup and remove both entries.
+ */
+ tx = dmu_tx_create(os);
+ dmu_tx_hold_zap(tx, object, B_TRUE, NULL);
+ txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+ if (txg == 0)
+ return;
+ for (i = 0; i < 2; i++) {
+ value[i] = i;
+ VERIFY3U(0, ==, zap_add(os, object, hc[i], sizeof (uint64_t),
+ 1, &value[i], tx));
+ }
+ for (i = 0; i < 2; i++) {
+ VERIFY3U(EEXIST, ==, zap_add(os, object, hc[i],
+ sizeof (uint64_t), 1, &value[i], tx));
+ VERIFY3U(0, ==,
+ zap_length(os, object, hc[i], &zl_intsize, &zl_ints));
+ ASSERT3U(zl_intsize, ==, sizeof (uint64_t));
+ ASSERT3U(zl_ints, ==, 1);
+ }
+ for (i = 0; i < 2; i++) {
+ VERIFY3U(0, ==, zap_remove(os, object, hc[i], tx));
+ }
+ dmu_tx_commit(tx);
+
+ /*
+ * Generate a buch of random entries.
+ */
+ ints = MAX(ZTEST_ZAP_MIN_INTS, object % ZTEST_ZAP_MAX_INTS);
+
+ prop = ztest_random(ZTEST_ZAP_MAX_PROPS);
+ (void) sprintf(propname, "prop_%llu", (u_longlong_t)prop);
+ (void) sprintf(txgname, "txg_%llu", (u_longlong_t)prop);
+ bzero(value, sizeof (value));
+ last_txg = 0;
+
+ /*
+ * If these zap entries already exist, validate their contents.
+ */
+ error = zap_length(os, object, txgname, &zl_intsize, &zl_ints);
+ if (error == 0) {
+ ASSERT3U(zl_intsize, ==, sizeof (uint64_t));
+ ASSERT3U(zl_ints, ==, 1);
+
+ VERIFY(zap_lookup(os, object, txgname, zl_intsize,
+ zl_ints, &last_txg) == 0);
+
+ VERIFY(zap_length(os, object, propname, &zl_intsize,
+ &zl_ints) == 0);
+
+ ASSERT3U(zl_intsize, ==, sizeof (uint64_t));
+ ASSERT3U(zl_ints, ==, ints);
+
+ VERIFY(zap_lookup(os, object, propname, zl_intsize,
+ zl_ints, value) == 0);
+
+ for (i = 0; i < ints; i++) {
+ ASSERT3U(value[i], ==, last_txg + object + i);
+ }
+ } else {
+ ASSERT3U(error, ==, ENOENT);
+ }
+
+ /*
+ * Atomically update two entries in our zap object.
+ * The first is named txg_%llu, and contains the txg
+ * in which the property was last updated. The second
+ * is named prop_%llu, and the nth element of its value
+ * should be txg + object + n.
+ */
+ tx = dmu_tx_create(os);
+ dmu_tx_hold_zap(tx, object, B_TRUE, NULL);
+ txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+ if (txg == 0)
+ return;
+
+ if (last_txg > txg)
+ fatal(0, "zap future leak: old %llu new %llu", last_txg, txg);
+
+ for (i = 0; i < ints; i++)
+ value[i] = txg + object + i;
+
+ VERIFY3U(0, ==, zap_update(os, object, txgname, sizeof (uint64_t),
+ 1, &txg, tx));
+ VERIFY3U(0, ==, zap_update(os, object, propname, sizeof (uint64_t),
+ ints, value, tx));
+
+ dmu_tx_commit(tx);
+
+ /*
+ * Remove a random pair of entries.
+ */
+ prop = ztest_random(ZTEST_ZAP_MAX_PROPS);
+ (void) sprintf(propname, "prop_%llu", (u_longlong_t)prop);
+ (void) sprintf(txgname, "txg_%llu", (u_longlong_t)prop);
+
+ error = zap_length(os, object, txgname, &zl_intsize, &zl_ints);
+
+ if (error == ENOENT)
+ return;
+
+ ASSERT0(error);
+
+ tx = dmu_tx_create(os);
+ dmu_tx_hold_zap(tx, object, B_TRUE, NULL);
+ txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+ if (txg == 0)
+ return;
+ VERIFY3U(0, ==, zap_remove(os, object, txgname, tx));
+ VERIFY3U(0, ==, zap_remove(os, object, propname, tx));
+ dmu_tx_commit(tx);
+}
+
+/*
+ * Testcase to test the upgrading of a microzap to fatzap.
+ */
+void
+ztest_fzap(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+ ztest_od_t od[1];
+ uint64_t object, txg;
+
+ ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0, 0);
+
+ if (ztest_object_init(zd, od, sizeof (od), !ztest_random(2)) != 0)
+ return;
+
+ object = od[0].od_object;
+
+ /*
+ * Add entries to this ZAP and make sure it spills over
+ * and gets upgraded to a fatzap. Also, since we are adding
+ * 2050 entries we should see ptrtbl growth and leaf-block split.
+ */
+ for (int i = 0; i < 2050; i++) {
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ uint64_t value = i;
+ dmu_tx_t *tx;
+ int error;
+
+ (void) snprintf(name, sizeof (name), "fzap-%llu-%llu",
+ id, value);
+
+ tx = dmu_tx_create(os);
+ dmu_tx_hold_zap(tx, object, B_TRUE, name);
+ txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+ if (txg == 0)
+ return;
+ error = zap_add(os, object, name, sizeof (uint64_t), 1,
+ &value, tx);
+ ASSERT(error == 0 || error == EEXIST);
+ dmu_tx_commit(tx);
+ }
+}
+
+/* ARGSUSED */
+void
+ztest_zap_parallel(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+ ztest_od_t od[1];
+ uint64_t txg, object, count, wsize, wc, zl_wsize, zl_wc;
+ dmu_tx_t *tx;
+ int i, namelen, error;
+ int micro = ztest_random(2);
+ char name[20], string_value[20];
+ void *data;
+
+ ztest_od_init(&od[0], ID_PARALLEL, FTAG, micro, DMU_OT_ZAP_OTHER,
+ 0, 0, 0);
+
+ if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0)
+ return;
+
+ object = od[0].od_object;
+
+ /*
+ * Generate a random name of the form 'xxx.....' where each
+ * x is a random printable character and the dots are dots.
+ * There are 94 such characters, and the name length goes from
+ * 6 to 20, so there are 94^3 * 15 = 12,458,760 possible names.
+ */
+ namelen = ztest_random(sizeof (name) - 5) + 5 + 1;
+
+ for (i = 0; i < 3; i++)
+ name[i] = '!' + ztest_random('~' - '!' + 1);
+ for (; i < namelen - 1; i++)
+ name[i] = '.';
+ name[i] = '\0';
+
+ if ((namelen & 1) || micro) {
+ wsize = sizeof (txg);
+ wc = 1;
+ data = &txg;
+ } else {
+ wsize = 1;
+ wc = namelen;
+ data = string_value;
+ }
+
+ count = -1ULL;
+ VERIFY0(zap_count(os, object, &count));
+ ASSERT(count != -1ULL);
+
+ /*
+ * Select an operation: length, lookup, add, update, remove.
+ */
+ i = ztest_random(5);
+
+ if (i >= 2) {
+ tx = dmu_tx_create(os);
+ dmu_tx_hold_zap(tx, object, B_TRUE, NULL);
+ txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+ if (txg == 0)
+ return;
+ bcopy(name, string_value, namelen);
+ } else {
+ tx = NULL;
+ txg = 0;
+ bzero(string_value, namelen);
+ }
+
+ switch (i) {
+
+ case 0:
+ error = zap_length(os, object, name, &zl_wsize, &zl_wc);
+ if (error == 0) {
+ ASSERT3U(wsize, ==, zl_wsize);
+ ASSERT3U(wc, ==, zl_wc);
+ } else {
+ ASSERT3U(error, ==, ENOENT);
+ }
+ break;
+
+ case 1:
+ error = zap_lookup(os, object, name, wsize, wc, data);
+ if (error == 0) {
+ if (data == string_value &&
+ bcmp(name, data, namelen) != 0)
+ fatal(0, "name '%s' != val '%s' len %d",
+ name, data, namelen);
+ } else {
+ ASSERT3U(error, ==, ENOENT);
+ }
+ break;
+
+ case 2:
+ error = zap_add(os, object, name, wsize, wc, data, tx);
+ ASSERT(error == 0 || error == EEXIST);
+ break;
+
+ case 3:
+ VERIFY(zap_update(os, object, name, wsize, wc, data, tx) == 0);
+ break;
+
+ case 4:
+ error = zap_remove(os, object, name, tx);
+ ASSERT(error == 0 || error == ENOENT);
+ break;
+ }
+
+ if (tx != NULL)
+ dmu_tx_commit(tx);
+}
+
+/*
+ * Commit callback data.
+ */
+typedef struct ztest_cb_data {
+ list_node_t zcd_node;
+ uint64_t zcd_txg;
+ int zcd_expected_err;
+ boolean_t zcd_added;
+ boolean_t zcd_called;
+ spa_t *zcd_spa;
+} ztest_cb_data_t;
+
+/* This is the actual commit callback function */
+static void
+ztest_commit_callback(void *arg, int error)
+{
+ ztest_cb_data_t *data = arg;
+ uint64_t synced_txg;
+
+ VERIFY(data != NULL);
+ VERIFY3S(data->zcd_expected_err, ==, error);
+ VERIFY(!data->zcd_called);
+
+ synced_txg = spa_last_synced_txg(data->zcd_spa);
+ if (data->zcd_txg > synced_txg)
+ fatal(0, "commit callback of txg %" PRIu64 " called prematurely"
+ ", last synced txg = %" PRIu64 "\n", data->zcd_txg,
+ synced_txg);
+
+ data->zcd_called = B_TRUE;
+
+ if (error == ECANCELED) {
+ ASSERT0(data->zcd_txg);
+ ASSERT(!data->zcd_added);
+
+ /*
+ * The private callback data should be destroyed here, but
+ * since we are going to check the zcd_called field after
+ * dmu_tx_abort(), we will destroy it there.
+ */
+ return;
+ }
+
+ /* Was this callback added to the global callback list? */
+ if (!data->zcd_added)
+ goto out;
+
+ ASSERT3U(data->zcd_txg, !=, 0);
+
+ /* Remove our callback from the list */
+ mutex_enter(&zcl.zcl_callbacks_lock);
+ list_remove(&zcl.zcl_callbacks, data);
+ mutex_exit(&zcl.zcl_callbacks_lock);
+
+out:
+ umem_free(data, sizeof (ztest_cb_data_t));
+}
+
+/* Allocate and initialize callback data structure */
+static ztest_cb_data_t *
+ztest_create_cb_data(objset_t *os, uint64_t txg)
+{
+ ztest_cb_data_t *cb_data;
+
+ cb_data = umem_zalloc(sizeof (ztest_cb_data_t), UMEM_NOFAIL);
+
+ cb_data->zcd_txg = txg;
+ cb_data->zcd_spa = dmu_objset_spa(os);
+
+ return (cb_data);
+}
+
+/*
+ * If a number of txgs equal to this threshold have been created after a commit
+ * callback has been registered but not called, then we assume there is an
+ * implementation bug.
+ */
+#define ZTEST_COMMIT_CALLBACK_THRESH (TXG_CONCURRENT_STATES + 2)
+
+/*
+ * Commit callback test.
+ */
+void
+ztest_dmu_commit_callbacks(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+ ztest_od_t od[1];
+ dmu_tx_t *tx;
+ ztest_cb_data_t *cb_data[3], *tmp_cb;
+ uint64_t old_txg, txg;
+ int i, error;
+
+ ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0);
+
+ if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0)
+ return;
+
+ tx = dmu_tx_create(os);
+
+ cb_data[0] = ztest_create_cb_data(os, 0);
+ dmu_tx_callback_register(tx, ztest_commit_callback, cb_data[0]);
+
+ dmu_tx_hold_write(tx, od[0].od_object, 0, sizeof (uint64_t));
+
+ /* Every once in a while, abort the transaction on purpose */
+ if (ztest_random(100) == 0)
+ error = -1;
+
+ if (!error)
+ error = dmu_tx_assign(tx, TXG_NOWAIT);
+
+ txg = error ? 0 : dmu_tx_get_txg(tx);
+
+ cb_data[0]->zcd_txg = txg;
+ cb_data[1] = ztest_create_cb_data(os, txg);
+ dmu_tx_callback_register(tx, ztest_commit_callback, cb_data[1]);
+
+ if (error) {
+ /*
+ * It's not a strict requirement to call the registered
+ * callbacks from inside dmu_tx_abort(), but that's what
+ * it's supposed to happen in the current implementation
+ * so we will check for that.
+ */
+ for (i = 0; i < 2; i++) {
+ cb_data[i]->zcd_expected_err = ECANCELED;
+ VERIFY(!cb_data[i]->zcd_called);
+ }
+
+ dmu_tx_abort(tx);
+
+ for (i = 0; i < 2; i++) {
+ VERIFY(cb_data[i]->zcd_called);
+ umem_free(cb_data[i], sizeof (ztest_cb_data_t));
+ }
+
+ return;
+ }
+
+ cb_data[2] = ztest_create_cb_data(os, txg);
+ dmu_tx_callback_register(tx, ztest_commit_callback, cb_data[2]);
+
+ /*
+ * Read existing data to make sure there isn't a future leak.
+ */
+ VERIFY(0 == dmu_read(os, od[0].od_object, 0, sizeof (uint64_t),
+ &old_txg, DMU_READ_PREFETCH));
+
+ if (old_txg > txg)
+ fatal(0, "future leak: got %" PRIu64 ", open txg is %" PRIu64,
+ old_txg, txg);
+
+ dmu_write(os, od[0].od_object, 0, sizeof (uint64_t), &txg, tx);
+
+ mutex_enter(&zcl.zcl_callbacks_lock);
+
+ /*
+ * Since commit callbacks don't have any ordering requirement and since
+ * it is theoretically possible for a commit callback to be called
+ * after an arbitrary amount of time has elapsed since its txg has been
+ * synced, it is difficult to reliably determine whether a commit
+ * callback hasn't been called due to high load or due to a flawed
+ * implementation.
+ *
+ * In practice, we will assume that if after a certain number of txgs a
+ * commit callback hasn't been called, then most likely there's an
+ * implementation bug..
+ */
+ tmp_cb = list_head(&zcl.zcl_callbacks);
+ if (tmp_cb != NULL &&
+ (txg - ZTEST_COMMIT_CALLBACK_THRESH) > tmp_cb->zcd_txg) {
+ fatal(0, "Commit callback threshold exceeded, oldest txg: %"
+ PRIu64 ", open txg: %" PRIu64 "\n", tmp_cb->zcd_txg, txg);
+ }
+
+ /*
+ * Let's find the place to insert our callbacks.
+ *
+ * Even though the list is ordered by txg, it is possible for the
+ * insertion point to not be the end because our txg may already be
+ * quiescing at this point and other callbacks in the open txg
+ * (from other objsets) may have sneaked in.
+ */
+ tmp_cb = list_tail(&zcl.zcl_callbacks);
+ while (tmp_cb != NULL && tmp_cb->zcd_txg > txg)
+ tmp_cb = list_prev(&zcl.zcl_callbacks, tmp_cb);
+
+ /* Add the 3 callbacks to the list */
+ for (i = 0; i < 3; i++) {
+ if (tmp_cb == NULL)
+ list_insert_head(&zcl.zcl_callbacks, cb_data[i]);
+ else
+ list_insert_after(&zcl.zcl_callbacks, tmp_cb,
+ cb_data[i]);
+
+ cb_data[i]->zcd_added = B_TRUE;
+ VERIFY(!cb_data[i]->zcd_called);
+
+ tmp_cb = cb_data[i];
+ }
+
+ mutex_exit(&zcl.zcl_callbacks_lock);
+
+ dmu_tx_commit(tx);
+}
+
+/*
+ * Visit each object in the dataset. Verify that its properties
+ * are consistent what was stored in the block tag when it was created,
+ * and that its unused bonus buffer space has not been overwritten.
+ */
+void
+ztest_verify_dnode_bt(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+ uint64_t obj;
+ int err = 0;
+
+ for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 0)) {
+ ztest_block_tag_t *bt = NULL;
+ dmu_object_info_t doi;
+ dmu_buf_t *db;
+
+ if (dmu_bonus_hold(os, obj, FTAG, &db) != 0)
+ continue;
+
+ dmu_object_info_from_db(db, &doi);
+ if (doi.doi_bonus_size >= sizeof (*bt))
+ bt = ztest_bt_bonus(db);
+
+ if (bt && bt->bt_magic == BT_MAGIC) {
+ ztest_bt_verify(bt, os, obj, doi.doi_dnodesize,
+ bt->bt_offset, bt->bt_gen, bt->bt_txg,
+ bt->bt_crtxg);
+ ztest_verify_unused_bonus(db, bt, obj, os, bt->bt_gen);
+ }
+
+ dmu_buf_rele(db, FTAG);
+ }
+}
+
+/* ARGSUSED */
+void
+ztest_dsl_prop_get_set(ztest_ds_t *zd, uint64_t id)
+{
+ zfs_prop_t proplist[] = {
+ ZFS_PROP_CHECKSUM,
+ ZFS_PROP_COMPRESSION,
+ ZFS_PROP_COPIES,
+ ZFS_PROP_DEDUP
+ };
+
+ rw_enter(&ztest_name_lock, RW_READER);
+
+ for (int p = 0; p < sizeof (proplist) / sizeof (proplist[0]); p++)
+ (void) ztest_dsl_prop_set_uint64(zd->zd_name, proplist[p],
+ ztest_random_dsl_prop(proplist[p]), (int)ztest_random(2));
+
+ rw_exit(&ztest_name_lock);
+}
+
+/* ARGSUSED */
+void
+ztest_remap_blocks(ztest_ds_t *zd, uint64_t id)
+{
+ rw_enter(&ztest_name_lock, RW_READER);
+
+ int error = dmu_objset_remap_indirects(zd->zd_name);
+ if (error == ENOSPC)
+ error = 0;
+ ASSERT0(error);
+
+ rw_exit(&ztest_name_lock);
+}
+
+/* ARGSUSED */
+void
+ztest_spa_prop_get_set(ztest_ds_t *zd, uint64_t id)
+{
+ nvlist_t *props = NULL;
+
+ rw_enter(&ztest_name_lock, RW_READER);
+
+ (void) ztest_spa_prop_set_uint64(ZPOOL_PROP_DEDUPDITTO,
+ ZIO_DEDUPDITTO_MIN + ztest_random(ZIO_DEDUPDITTO_MIN));
+
+ VERIFY0(spa_prop_get(ztest_spa, &props));
+
+ if (ztest_opts.zo_verbose >= 6)
+ dump_nvlist(props, 4);
+
+ nvlist_free(props);
+
+ rw_exit(&ztest_name_lock);
+}
+
+static int
+user_release_one(const char *snapname, const char *holdname)
+{
+ nvlist_t *snaps, *holds;
+ int error;
+
+ snaps = fnvlist_alloc();
+ holds = fnvlist_alloc();
+ fnvlist_add_boolean(holds, holdname);
+ fnvlist_add_nvlist(snaps, snapname, holds);
+ fnvlist_free(holds);
+ error = dsl_dataset_user_release(snaps, NULL);
+ fnvlist_free(snaps);
+ return (error);
+}
+
+/*
+ * Test snapshot hold/release and deferred destroy.
+ */
+void
+ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
+{
+ int error;
+ objset_t *os = zd->zd_os;
+ objset_t *origin;
+ char snapname[100];
+ char fullname[100];
+ char clonename[100];
+ char tag[100];
+ char osname[ZFS_MAX_DATASET_NAME_LEN];
+ nvlist_t *holds;
+
+ rw_enter(&ztest_name_lock, RW_READER);
+
+ dmu_objset_name(os, osname);
+
+ (void) snprintf(snapname, sizeof (snapname), "sh1_%llu", id);
+ (void) snprintf(fullname, sizeof (fullname), "%s@%s", osname, snapname);
+ (void) snprintf(clonename, sizeof (clonename),
+ "%s/ch1_%llu", osname, id);
+ (void) snprintf(tag, sizeof (tag), "tag_%llu", id);
+
+ /*
+ * Clean up from any previous run.
+ */
+ error = dsl_destroy_head(clonename);
+ if (error != ENOENT)
+ ASSERT0(error);
+ error = user_release_one(fullname, tag);
+ if (error != ESRCH && error != ENOENT)
+ ASSERT0(error);
+ error = dsl_destroy_snapshot(fullname, B_FALSE);
+ if (error != ENOENT)
+ ASSERT0(error);
+
+ /*
+ * Create snapshot, clone it, mark snap for deferred destroy,
+ * destroy clone, verify snap was also destroyed.
+ */
+ error = dmu_objset_snapshot_one(osname, snapname);
+ if (error) {
+ if (error == ENOSPC) {
+ ztest_record_enospc("dmu_objset_snapshot");
+ goto out;
+ }
+ fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
+ }
+
+ error = dmu_objset_clone(clonename, fullname);
+ if (error) {
+ if (error == ENOSPC) {
+ ztest_record_enospc("dmu_objset_clone");
+ goto out;
+ }
+ fatal(0, "dmu_objset_clone(%s) = %d", clonename, error);
+ }
+
+ error = dsl_destroy_snapshot(fullname, B_TRUE);
+ if (error) {
+ fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
+ fullname, error);
+ }
+
+ error = dsl_destroy_head(clonename);
+ if (error)
+ fatal(0, "dsl_destroy_head(%s) = %d", clonename, error);
+
+ error = dmu_objset_hold(fullname, FTAG, &origin);
+ if (error != ENOENT)
+ fatal(0, "dmu_objset_hold(%s) = %d", fullname, error);
+
+ /*
+ * Create snapshot, add temporary hold, verify that we can't
+ * destroy a held snapshot, mark for deferred destroy,
+ * release hold, verify snapshot was destroyed.
+ */
+ error = dmu_objset_snapshot_one(osname, snapname);
+ if (error) {
+ if (error == ENOSPC) {
+ ztest_record_enospc("dmu_objset_snapshot");
+ goto out;
+ }
+ fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
+ }
+
+ holds = fnvlist_alloc();
+ fnvlist_add_string(holds, fullname, tag);
+ error = dsl_dataset_user_hold(holds, 0, NULL);
+ fnvlist_free(holds);
+
+ if (error == ENOSPC) {
+ ztest_record_enospc("dsl_dataset_user_hold");
+ goto out;
+ } else if (error) {
+ fatal(0, "dsl_dataset_user_hold(%s, %s) = %u",
+ fullname, tag, error);
+ }
+
+ error = dsl_destroy_snapshot(fullname, B_FALSE);
+ if (error != EBUSY) {
+ fatal(0, "dsl_destroy_snapshot(%s, B_FALSE) = %d",
+ fullname, error);
+ }
+
+ error = dsl_destroy_snapshot(fullname, B_TRUE);
+ if (error) {
+ fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
+ fullname, error);
+ }
+
+ error = user_release_one(fullname, tag);
+ if (error)
+ fatal(0, "user_release_one(%s, %s) = %d", fullname, tag, error);
+
+ VERIFY3U(dmu_objset_hold(fullname, FTAG, &origin), ==, ENOENT);
+
+out:
+ rw_exit(&ztest_name_lock);
+}
+
+/*
+ * Inject random faults into the on-disk data.
+ */
+/* ARGSUSED */
+void
+ztest_fault_inject(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_t *zs = ztest_shared;
+ spa_t *spa = ztest_spa;
+ int fd;
+ uint64_t offset;
+ uint64_t leaves;
+ uint64_t bad = 0x1990c0ffeedecadeULL;
+ uint64_t top, leaf;
+ char path0[MAXPATHLEN];
+ char pathrand[MAXPATHLEN];
+ size_t fsize;
+ int bshift = SPA_MAXBLOCKSHIFT + 2;
+ int iters = 1000;
+ int maxfaults;
+ int mirror_save;
+ vdev_t *vd0 = NULL;
+ uint64_t guid0 = 0;
+ boolean_t islog = B_FALSE;
+
+ mutex_enter(&ztest_vdev_lock);
+
+ /*
+ * Device removal is in progress, fault injection must be disabled
+ * until it completes and the pool is scrubbed. The fault injection
+ * strategy for damaging blocks does not take in to account evacuated
+ * blocks which may have already been damaged.
+ */
+ if (ztest_device_removal_active) {
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ maxfaults = MAXFAULTS();
+ leaves = MAX(zs->zs_mirrors, 1) * ztest_opts.zo_raidz;
+ mirror_save = zs->zs_mirrors;
+ mutex_exit(&ztest_vdev_lock);
+
+ ASSERT(leaves >= 1);
+
+ /*
+ * Grab the name lock as reader. There are some operations
+ * which don't like to have their vdevs changed while
+ * they are in progress (i.e. spa_change_guid). Those
+ * operations will have grabbed the name lock as writer.
+ */
+ rw_enter(&ztest_name_lock, RW_READER);
+
+ /*
+ * We need SCL_STATE here because we're going to look at vd0->vdev_tsd.
+ */
+ spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+
+ if (ztest_random(2) == 0) {
+ /*
+ * Inject errors on a normal data device or slog device.
+ */
+ top = ztest_random_vdev_top(spa, B_TRUE);
+ leaf = ztest_random(leaves) + zs->zs_splits;
+
+ /*
+ * Generate paths to the first leaf in this top-level vdev,
+ * and to the random leaf we selected. We'll induce transient
+ * write failures and random online/offline activity on leaf 0,
+ * and we'll write random garbage to the randomly chosen leaf.
+ */
+ (void) snprintf(path0, sizeof (path0), ztest_dev_template,
+ ztest_opts.zo_dir, ztest_opts.zo_pool,
+ top * leaves + zs->zs_splits);
+ (void) snprintf(pathrand, sizeof (pathrand), ztest_dev_template,
+ ztest_opts.zo_dir, ztest_opts.zo_pool,
+ top * leaves + leaf);
+
+ vd0 = vdev_lookup_by_path(spa->spa_root_vdev, path0);
+ if (vd0 != NULL && vd0->vdev_top->vdev_islog)
+ islog = B_TRUE;
+
+ /*
+ * If the top-level vdev needs to be resilvered
+ * then we only allow faults on the device that is
+ * resilvering.
+ */
+ if (vd0 != NULL && maxfaults != 1 &&
+ (!vdev_resilver_needed(vd0->vdev_top, NULL, NULL) ||
+ vd0->vdev_resilver_txg != 0)) {
+ /*
+ * Make vd0 explicitly claim to be unreadable,
+ * or unwriteable, or reach behind its back
+ * and close the underlying fd. We can do this if
+ * maxfaults == 0 because we'll fail and reexecute,
+ * and we can do it if maxfaults >= 2 because we'll
+ * have enough redundancy. If maxfaults == 1, the
+ * combination of this with injection of random data
+ * corruption below exceeds the pool's fault tolerance.
+ */
+ vdev_file_t *vf = vd0->vdev_tsd;
+
+ zfs_dbgmsg("injecting fault to vdev %llu; maxfaults=%d",
+ (long long)vd0->vdev_id, (int)maxfaults);
+
+ if (vf != NULL && ztest_random(3) == 0) {
+ (void) close(vf->vf_vnode->v_fd);
+ vf->vf_vnode->v_fd = -1;
+ } else if (ztest_random(2) == 0) {
+ vd0->vdev_cant_read = B_TRUE;
+ } else {
+ vd0->vdev_cant_write = B_TRUE;
+ }
+ guid0 = vd0->vdev_guid;
+ }
+ } else {
+ /*
+ * Inject errors on an l2cache device.
+ */
+ spa_aux_vdev_t *sav = &spa->spa_l2cache;
+
+ if (sav->sav_count == 0) {
+ spa_config_exit(spa, SCL_STATE, FTAG);
+ rw_exit(&ztest_name_lock);
+ return;
+ }
+ vd0 = sav->sav_vdevs[ztest_random(sav->sav_count)];
+ guid0 = vd0->vdev_guid;
+ (void) strcpy(path0, vd0->vdev_path);
+ (void) strcpy(pathrand, vd0->vdev_path);
+
+ leaf = 0;
+ leaves = 1;
+ maxfaults = INT_MAX; /* no limit on cache devices */
+ }
+
+ spa_config_exit(spa, SCL_STATE, FTAG);
+ rw_exit(&ztest_name_lock);
+
+ /*
+ * If we can tolerate two or more faults, or we're dealing
+ * with a slog, randomly online/offline vd0.
+ */
+ if ((maxfaults >= 2 || islog) && guid0 != 0) {
+ if (ztest_random(10) < 6) {
+ int flags = (ztest_random(2) == 0 ?
+ ZFS_OFFLINE_TEMPORARY : 0);
+
+ /*
+ * We have to grab the zs_name_lock as writer to
+ * prevent a race between offlining a slog and
+ * destroying a dataset. Offlining the slog will
+ * grab a reference on the dataset which may cause
+ * dmu_objset_destroy() to fail with EBUSY thus
+ * leaving the dataset in an inconsistent state.
+ */
+ if (islog)
+ rw_enter(&ztest_name_lock, RW_WRITER);
+
+ VERIFY(vdev_offline(spa, guid0, flags) != EBUSY);
+
+ if (islog)
+ rw_exit(&ztest_name_lock);
+ } else {
+ /*
+ * Ideally we would like to be able to randomly
+ * call vdev_[on|off]line without holding locks
+ * to force unpredictable failures but the side
+ * effects of vdev_[on|off]line prevent us from
+ * doing so. We grab the ztest_vdev_lock here to
+ * prevent a race between injection testing and
+ * aux_vdev removal.
+ */
+ mutex_enter(&ztest_vdev_lock);
+ (void) vdev_online(spa, guid0, 0, NULL);
+ mutex_exit(&ztest_vdev_lock);
+ }
+ }
+
+ if (maxfaults == 0)
+ return;
+
+ /*
+ * We have at least single-fault tolerance, so inject data corruption.
+ */
+ fd = open(pathrand, O_RDWR);
+
+ if (fd == -1) /* we hit a gap in the device namespace */
+ return;
+
+ fsize = lseek(fd, 0, SEEK_END);
+
+ while (--iters != 0) {
+ /*
+ * The offset must be chosen carefully to ensure that
+ * we do not inject a given logical block with errors
+ * on two different leaf devices, because ZFS can not
+ * tolerate that (if maxfaults==1).
+ *
+ * We divide each leaf into chunks of size
+ * (# leaves * SPA_MAXBLOCKSIZE * 4). Within each chunk
+ * there is a series of ranges to which we can inject errors.
+ * Each range can accept errors on only a single leaf vdev.
+ * The error injection ranges are separated by ranges
+ * which we will not inject errors on any device (DMZs).
+ * Each DMZ must be large enough such that a single block
+ * can not straddle it, so that a single block can not be
+ * a target in two different injection ranges (on different
+ * leaf vdevs).
+ *
+ * For example, with 3 leaves, each chunk looks like:
+ * 0 to 32M: injection range for leaf 0
+ * 32M to 64M: DMZ - no injection allowed
+ * 64M to 96M: injection range for leaf 1
+ * 96M to 128M: DMZ - no injection allowed
+ * 128M to 160M: injection range for leaf 2
+ * 160M to 192M: DMZ - no injection allowed
+ */
+ offset = ztest_random(fsize / (leaves << bshift)) *
+ (leaves << bshift) + (leaf << bshift) +
+ (ztest_random(1ULL << (bshift - 1)) & -8ULL);
+
+ /*
+ * Only allow damage to the labels at one end of the vdev.
+ *
+ * If all labels are damaged, the device will be totally
+ * inaccessible, which will result in loss of data,
+ * because we also damage (parts of) the other side of
+ * the mirror/raidz.
+ *
+ * Additionally, we will always have both an even and an
+ * odd label, so that we can handle crashes in the
+ * middle of vdev_config_sync().
+ */
+ if ((leaf & 1) == 0 && offset < VDEV_LABEL_START_SIZE)
+ continue;
+
+ /*
+ * The two end labels are stored at the "end" of the disk, but
+ * the end of the disk (vdev_psize) is aligned to
+ * sizeof (vdev_label_t).
+ */
+ uint64_t psize = P2ALIGN(fsize, sizeof (vdev_label_t));
+ if ((leaf & 1) == 1 &&
+ offset + sizeof (bad) > psize - VDEV_LABEL_END_SIZE)
+ continue;
+
+ mutex_enter(&ztest_vdev_lock);
+ if (mirror_save != zs->zs_mirrors) {
+ mutex_exit(&ztest_vdev_lock);
+ (void) close(fd);
+ return;
+ }
+
+ if (pwrite(fd, &bad, sizeof (bad), offset) != sizeof (bad))
+ fatal(1, "can't inject bad word at 0x%llx in %s",
+ offset, pathrand);
+
+ mutex_exit(&ztest_vdev_lock);
+
+ if (ztest_opts.zo_verbose >= 7)
+ (void) printf("injected bad word into %s,"
+ " offset 0x%llx\n", pathrand, (u_longlong_t)offset);
+ }
+
+ (void) close(fd);
+}
+
+/*
+ * Verify that DDT repair works as expected.
+ */
+void
+ztest_ddt_repair(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_t *zs = ztest_shared;
+ spa_t *spa = ztest_spa;
+ objset_t *os = zd->zd_os;
+ ztest_od_t od[1];
+ uint64_t object, blocksize, txg, pattern, psize;
+ enum zio_checksum checksum = spa_dedup_checksum(spa);
+ dmu_buf_t *db;
+ dmu_tx_t *tx;
+ abd_t *abd;
+ blkptr_t blk;
+ int copies = 2 * ZIO_DEDUPDITTO_MIN;
+
+ blocksize = ztest_random_blocksize();
+ blocksize = MIN(blocksize, 2048); /* because we write so many */
+
+ ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize,
+ 0, 0);
+
+ if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0)
+ return;
+
+ /*
+ * Take the name lock as writer to prevent anyone else from changing
+ * the pool and dataset properies we need to maintain during this test.
+ */
+ rw_enter(&ztest_name_lock, RW_WRITER);
+
+ if (ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_DEDUP, checksum,
+ B_FALSE) != 0 ||
+ ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_COPIES, 1,
+ B_FALSE) != 0) {
+ rw_exit(&ztest_name_lock);
+ return;
+ }
+
+ dmu_objset_stats_t dds;
+ dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
+ dmu_objset_fast_stat(os, &dds);
+ dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
+
+ object = od[0].od_object;
+ blocksize = od[0].od_blocksize;
+ pattern = zs->zs_guid ^ dds.dds_guid;
+
+ ASSERT(object != 0);
+
+ tx = dmu_tx_create(os);
+ dmu_tx_hold_write(tx, object, 0, copies * blocksize);
+ txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+ if (txg == 0) {
+ rw_exit(&ztest_name_lock);
+ return;
+ }
+
+ /*
+ * Write all the copies of our block.
+ */
+ for (int i = 0; i < copies; i++) {
+ uint64_t offset = i * blocksize;
+ int error = dmu_buf_hold(os, object, offset, FTAG, &db,
+ DMU_READ_NO_PREFETCH);
+ if (error != 0) {
+ fatal(B_FALSE, "dmu_buf_hold(%p, %llu, %llu) = %u",
+ os, (long long)object, (long long) offset, error);
+ }
+ ASSERT(db->db_offset == offset);
+ ASSERT(db->db_size == blocksize);
+ ASSERT(ztest_pattern_match(db->db_data, db->db_size, pattern) ||
+ ztest_pattern_match(db->db_data, db->db_size, 0ULL));
+ dmu_buf_will_fill(db, tx);
+ ztest_pattern_set(db->db_data, db->db_size, pattern);
+ dmu_buf_rele(db, FTAG);
+ }
+
+ dmu_tx_commit(tx);
+ txg_wait_synced(spa_get_dsl(spa), txg);
+
+ /*
+ * Find out what block we got.
+ */
+ VERIFY0(dmu_buf_hold(os, object, 0, FTAG, &db,
+ DMU_READ_NO_PREFETCH));
+ blk = *((dmu_buf_impl_t *)db)->db_blkptr;
+ dmu_buf_rele(db, FTAG);
+
+ /*
+ * Damage the block. Dedup-ditto will save us when we read it later.
+ */
+ psize = BP_GET_PSIZE(&blk);
+ abd = abd_alloc_linear(psize, B_TRUE);
+ ztest_pattern_set(abd_to_buf(abd), psize, ~pattern);
+
+ (void) zio_wait(zio_rewrite(NULL, spa, 0, &blk,
+ abd, psize, NULL, NULL, ZIO_PRIORITY_SYNC_WRITE,
+ ZIO_FLAG_CANFAIL | ZIO_FLAG_INDUCE_DAMAGE, NULL));
+
+ abd_free(abd);
+
+ rw_exit(&ztest_name_lock);
+}
+
+/*
+ * Scrub the pool.
+ */
+/* ARGSUSED */
+void
+ztest_scrub(ztest_ds_t *zd, uint64_t id)
+{
+ spa_t *spa = ztest_spa;
+
+ /*
+ * Scrub in progress by device removal.
+ */
+ if (ztest_device_removal_active)
+ return;
+
+ (void) spa_scan(spa, POOL_SCAN_SCRUB);
+ (void) poll(NULL, 0, 100); /* wait a moment, then force a restart */
+ (void) spa_scan(spa, POOL_SCAN_SCRUB);
+}
+
+/*
+ * Change the guid for the pool.
+ */
+/* ARGSUSED */
+void
+ztest_reguid(ztest_ds_t *zd, uint64_t id)
+{
+ spa_t *spa = ztest_spa;
+ uint64_t orig, load;
+ int error;
+
+ if (ztest_opts.zo_mmp_test)
+ return;
+
+ orig = spa_guid(spa);
+ load = spa_load_guid(spa);
+
+ rw_enter(&ztest_name_lock, RW_WRITER);
+ error = spa_change_guid(spa);
+ rw_exit(&ztest_name_lock);
+
+ if (error != 0)
+ return;
+
+ if (ztest_opts.zo_verbose >= 4) {
+ (void) printf("Changed guid old %llu -> %llu\n",
+ (u_longlong_t)orig, (u_longlong_t)spa_guid(spa));
+ }
+
+ VERIFY3U(orig, !=, spa_guid(spa));
+ VERIFY3U(load, ==, spa_load_guid(spa));
+}
+
+static vdev_t *
+ztest_random_concrete_vdev_leaf(vdev_t *vd)
+{
+ if (vd == NULL)
+ return (NULL);
+
+ if (vd->vdev_children == 0)
+ return (vd);
+
+ vdev_t *eligible[vd->vdev_children];
+ int eligible_idx = 0, i;
+ for (i = 0; i < vd->vdev_children; i++) {
+ vdev_t *cvd = vd->vdev_child[i];
+ if (cvd->vdev_top->vdev_removing)
+ continue;
+ if (cvd->vdev_children > 0 ||
+ (vdev_is_concrete(cvd) && !cvd->vdev_detached)) {
+ eligible[eligible_idx++] = cvd;
+ }
+ }
+ VERIFY(eligible_idx > 0);
+
+ uint64_t child_no = ztest_random(eligible_idx);
+ return (ztest_random_concrete_vdev_leaf(eligible[child_no]));
+}
+
+/* ARGSUSED */
+void
+ztest_initialize(ztest_ds_t *zd, uint64_t id)
+{
+ spa_t *spa = ztest_spa;
+ int error = 0;
+
+ mutex_enter(&ztest_vdev_lock);
+
+ spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+ /* Random leaf vdev */
+ vdev_t *rand_vd = ztest_random_concrete_vdev_leaf(spa->spa_root_vdev);
+ if (rand_vd == NULL) {
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ /*
+ * The random vdev we've selected may change as soon as we
+ * drop the spa_config_lock. We create local copies of things
+ * we're interested in.
+ */
+ uint64_t guid = rand_vd->vdev_guid;
+ char *path = strdup(rand_vd->vdev_path);
+ boolean_t active = rand_vd->vdev_initialize_thread != NULL;
+
+ zfs_dbgmsg("vd %p, guid %llu", rand_vd, guid);
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+
+ uint64_t cmd = ztest_random(POOL_INITIALIZE_FUNCS);
+ error = spa_vdev_initialize(spa, guid, cmd);
+ switch (cmd) {
+ case POOL_INITIALIZE_CANCEL:
+ if (ztest_opts.zo_verbose >= 4) {
+ (void) printf("Cancel initialize %s", path);
+ if (!active)
+ (void) printf(" failed (no initialize active)");
+ (void) printf("\n");
+ }
+ break;
+ case POOL_INITIALIZE_DO:
+ if (ztest_opts.zo_verbose >= 4) {
+ (void) printf("Start initialize %s", path);
+ if (active && error == 0)
+ (void) printf(" failed (already active)");
+ else if (error != 0)
+ (void) printf(" failed (error %d)", error);
+ (void) printf("\n");
+ }
+ break;
+ case POOL_INITIALIZE_SUSPEND:
+ if (ztest_opts.zo_verbose >= 4) {
+ (void) printf("Suspend initialize %s", path);
+ if (!active)
+ (void) printf(" failed (no initialize active)");
+ (void) printf("\n");
+ }
+ break;
+ }
+ free(path);
+ mutex_exit(&ztest_vdev_lock);
+}
+
+/*
+ * Verify pool integrity by running zdb.
+ */
+static void
+ztest_run_zdb(char *pool)
+{
+ int status;
+ char zdb[MAXPATHLEN + MAXNAMELEN + 20];
+ char zbuf[1024];
+ char *bin;
+ char *ztest;
+ char *isa;
+ int isalen;
+ FILE *fp;
+
+ strlcpy(zdb, "/usr/bin/ztest", sizeof(zdb));
+
+ /* zdb lives in /usr/sbin, while ztest lives in /usr/bin */
+ bin = strstr(zdb, "/usr/bin/");
+ ztest = strstr(bin, "/ztest");
+ isa = bin + 8;
+ isalen = ztest - isa;
+ isa = strdup(isa);
+ /* LINTED */
+ (void) sprintf(bin,
+ "/usr/sbin%.*s/zdb -bcc%s%s -G -d -U %s "
+ "-o zfs_reconstruct_indirect_combinations_max=65536 %s",
+ isalen,
+ isa,
+ ztest_opts.zo_verbose >= 3 ? "s" : "",
+ ztest_opts.zo_verbose >= 4 ? "v" : "",
+ spa_config_path,
+ pool);
+ free(isa);
+
+ if (ztest_opts.zo_verbose >= 5)
+ (void) printf("Executing %s\n", strstr(zdb, "zdb "));
+
+ fp = popen(zdb, "r");
+ assert(fp != NULL);
+
+ while (fgets(zbuf, sizeof (zbuf), fp) != NULL)
+ if (ztest_opts.zo_verbose >= 3)
+ (void) printf("%s", zbuf);
+
+ status = pclose(fp);
+
+ if (status == 0)
+ return;
+
+ ztest_dump_core = 0;
+ if (WIFEXITED(status))
+ fatal(0, "'%s' exit code %d", zdb, WEXITSTATUS(status));
+ else
+ fatal(0, "'%s' died with signal %d", zdb, WTERMSIG(status));
+}
+
+static void
+ztest_walk_pool_directory(char *header)
+{
+ spa_t *spa = NULL;
+
+ if (ztest_opts.zo_verbose >= 6)
+ (void) printf("%s\n", header);
+
+ mutex_enter(&spa_namespace_lock);
+ while ((spa = spa_next(spa)) != NULL)
+ if (ztest_opts.zo_verbose >= 6)
+ (void) printf("\t%s\n", spa_name(spa));
+ mutex_exit(&spa_namespace_lock);
+}
+
+static void
+ztest_spa_import_export(char *oldname, char *newname)
+{
+ nvlist_t *config, *newconfig;
+ uint64_t pool_guid;
+ spa_t *spa;
+ int error;
+
+ if (ztest_opts.zo_verbose >= 4) {
+ (void) printf("import/export: old = %s, new = %s\n",
+ oldname, newname);
+ }
+
+ /*
+ * Clean up from previous runs.
+ */
+ (void) spa_destroy(newname);
+
+ /*
+ * Get the pool's configuration and guid.
+ */
+ VERIFY3U(0, ==, spa_open(oldname, &spa, FTAG));
+
+ /*
+ * Kick off a scrub to tickle scrub/export races.
+ */
+ if (ztest_random(2) == 0)
+ (void) spa_scan(spa, POOL_SCAN_SCRUB);
+
+ pool_guid = spa_guid(spa);
+ spa_close(spa, FTAG);
+
+ ztest_walk_pool_directory("pools before export");
+
+ /*
+ * Export it.
+ */
+ VERIFY3U(0, ==, spa_export(oldname, &config, B_FALSE, B_FALSE));
+
+ ztest_walk_pool_directory("pools after export");
+
+ /*
+ * Try to import it.
+ */
+ newconfig = spa_tryimport(config);
+ ASSERT(newconfig != NULL);
+ nvlist_free(newconfig);
+
+ /*
+ * Import it under the new name.
+ */
+ error = spa_import(newname, config, NULL, 0);
+ if (error != 0) {
+ dump_nvlist(config, 0);
+ fatal(B_FALSE, "couldn't import pool %s as %s: error %u",
+ oldname, newname, error);
+ }
+
+ ztest_walk_pool_directory("pools after import");
+
+ /*
+ * Try to import it again -- should fail with EEXIST.
+ */
+ VERIFY3U(EEXIST, ==, spa_import(newname, config, NULL, 0));
+
+ /*
+ * Try to import it under a different name -- should fail with EEXIST.
+ */
+ VERIFY3U(EEXIST, ==, spa_import(oldname, config, NULL, 0));
+
+ /*
+ * Verify that the pool is no longer visible under the old name.
+ */
+ VERIFY3U(ENOENT, ==, spa_open(oldname, &spa, FTAG));
+
+ /*
+ * Verify that we can open and close the pool using the new name.
+ */
+ VERIFY3U(0, ==, spa_open(newname, &spa, FTAG));
+ ASSERT(pool_guid == spa_guid(spa));
+ spa_close(spa, FTAG);
+
+ nvlist_free(config);
+}
+
+static void
+ztest_resume(spa_t *spa)
+{
+ if (spa_suspended(spa) && ztest_opts.zo_verbose >= 6)
+ (void) printf("resuming from suspended state\n");
+ spa_vdev_state_enter(spa, SCL_NONE);
+ vdev_clear(spa, NULL);
+ (void) spa_vdev_state_exit(spa, NULL, 0);
+ (void) zio_resume(spa);
+}
+
+static void *
+ztest_resume_thread(void *arg)
+{
+ spa_t *spa = arg;
+
+ while (!ztest_exiting) {
+ if (spa_suspended(spa))
+ ztest_resume(spa);
+ (void) poll(NULL, 0, 100);
+
+ /*
+ * Periodically change the zfs_compressed_arc_enabled setting.
+ */
+ if (ztest_random(10) == 0)
+ zfs_compressed_arc_enabled = ztest_random(2);
+
+ /*
+ * Periodically change the zfs_abd_scatter_enabled setting.
+ */
+ if (ztest_random(10) == 0)
+ zfs_abd_scatter_enabled = ztest_random(2);
+ }
+ return (NULL);
+}
+
+static void *
+ztest_deadman_thread(void *arg)
+{
+ ztest_shared_t *zs = arg;
+ spa_t *spa = ztest_spa;
+ hrtime_t delta, total = 0;
+
+ for (;;) {
+ delta = zs->zs_thread_stop - zs->zs_thread_start +
+ MSEC2NSEC(zfs_deadman_synctime_ms);
+
+ (void) poll(NULL, 0, (int)NSEC2MSEC(delta));
+
+ /*
+ * If the pool is suspended then fail immediately. Otherwise,
+ * check to see if the pool is making any progress. If
+ * vdev_deadman() discovers that there hasn't been any recent
+ * I/Os then it will end up aborting the tests.
+ */
+ if (spa_suspended(spa) || spa->spa_root_vdev == NULL) {
+ fatal(0, "aborting test after %llu seconds because "
+ "pool has transitioned to a suspended state.",
+ zfs_deadman_synctime_ms / 1000);
+ return (NULL);
+ }
+ vdev_deadman(spa->spa_root_vdev);
+
+ total += zfs_deadman_synctime_ms/1000;
+ (void) printf("ztest has been running for %lld seconds\n",
+ total);
+ }
+}
+
+static void
+ztest_execute(int test, ztest_info_t *zi, uint64_t id)
+{
+ ztest_ds_t *zd = &ztest_ds[id % ztest_opts.zo_datasets];
+ ztest_shared_callstate_t *zc = ZTEST_GET_SHARED_CALLSTATE(test);
+ hrtime_t functime = gethrtime();
+
+ for (int i = 0; i < zi->zi_iters; i++)
+ zi->zi_func(zd, id);
+
+ functime = gethrtime() - functime;
+
+ atomic_add_64(&zc->zc_count, 1);
+ atomic_add_64(&zc->zc_time, functime);
+
+ if (ztest_opts.zo_verbose >= 4) {
+ Dl_info dli;
+ (void) dladdr((void *)zi->zi_func, &dli);
+ (void) printf("%6.2f sec in %s\n",
+ (double)functime / NANOSEC, dli.dli_sname);
+ }
+}
+
+static void *
+ztest_thread(void *arg)
+{
+ int rand;
+ uint64_t id = (uintptr_t)arg;
+ ztest_shared_t *zs = ztest_shared;
+ uint64_t call_next;
+ hrtime_t now;
+ ztest_info_t *zi;
+ ztest_shared_callstate_t *zc;
+
+ while ((now = gethrtime()) < zs->zs_thread_stop) {
+ /*
+ * See if it's time to force a crash.
+ */
+ if (now > zs->zs_thread_kill)
+ ztest_kill(zs);
+
+ /*
+ * If we're getting ENOSPC with some regularity, stop.
+ */
+ if (zs->zs_enospc_count > 10)
+ break;
+
+ /*
+ * Pick a random function to execute.
+ */
+ rand = ztest_random(ZTEST_FUNCS);
+ zi = &ztest_info[rand];
+ zc = ZTEST_GET_SHARED_CALLSTATE(rand);
+ call_next = zc->zc_next;
+
+ if (now >= call_next &&
+ atomic_cas_64(&zc->zc_next, call_next, call_next +
+ ztest_random(2 * zi->zi_interval[0] + 1)) == call_next) {
+ ztest_execute(rand, zi, id);
+ }
+ }
+
+ return (NULL);
+}
+
+static void
+ztest_dataset_name(char *dsname, char *pool, int d)
+{
+ (void) snprintf(dsname, ZFS_MAX_DATASET_NAME_LEN, "%s/ds_%d", pool, d);
+}
+
+static void
+ztest_dataset_destroy(int d)
+{
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+
+ ztest_dataset_name(name, ztest_opts.zo_pool, d);
+
+ if (ztest_opts.zo_verbose >= 3)
+ (void) printf("Destroying %s to free up space\n", name);
+
+ /*
+ * Cleanup any non-standard clones and snapshots. In general,
+ * ztest thread t operates on dataset (t % zopt_datasets),
+ * so there may be more than one thing to clean up.
+ */
+ for (int t = d; t < ztest_opts.zo_threads;
+ t += ztest_opts.zo_datasets) {
+ ztest_dsl_dataset_cleanup(name, t);
+ }
+
+ (void) dmu_objset_find(name, ztest_objset_destroy_cb, NULL,
+ DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
+}
+
+static void
+ztest_dataset_dirobj_verify(ztest_ds_t *zd)
+{
+ uint64_t usedobjs, dirobjs, scratch;
+
+ /*
+ * ZTEST_DIROBJ is the object directory for the entire dataset.
+ * Therefore, the number of objects in use should equal the
+ * number of ZTEST_DIROBJ entries, +1 for ZTEST_DIROBJ itself.
+ * If not, we have an object leak.
+ *
+ * Note that we can only check this in ztest_dataset_open(),
+ * when the open-context and syncing-context values agree.
+ * That's because zap_count() returns the open-context value,
+ * while dmu_objset_space() returns the rootbp fill count.
+ */
+ VERIFY3U(0, ==, zap_count(zd->zd_os, ZTEST_DIROBJ, &dirobjs));
+ dmu_objset_space(zd->zd_os, &scratch, &scratch, &usedobjs, &scratch);
+ ASSERT3U(dirobjs + 1, ==, usedobjs);
+}
+
+static int
+ztest_dataset_open(int d)
+{
+ ztest_ds_t *zd = &ztest_ds[d];
+ uint64_t committed_seq = ZTEST_GET_SHARED_DS(d)->zd_seq;
+ objset_t *os;
+ zilog_t *zilog;
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ int error;
+
+ ztest_dataset_name(name, ztest_opts.zo_pool, d);
+
+ rw_enter(&ztest_name_lock, RW_READER);
+
+ error = ztest_dataset_create(name);
+ if (error == ENOSPC) {
+ rw_exit(&ztest_name_lock);
+ ztest_record_enospc(FTAG);
+ return (error);
+ }
+ ASSERT(error == 0 || error == EEXIST);
+
+ VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, zd, &os));
+ rw_exit(&ztest_name_lock);
+
+ ztest_zd_init(zd, ZTEST_GET_SHARED_DS(d), os);
+
+ zilog = zd->zd_zilog;
+
+ if (zilog->zl_header->zh_claim_lr_seq != 0 &&
+ zilog->zl_header->zh_claim_lr_seq < committed_seq)
+ fatal(0, "missing log records: claimed %llu < committed %llu",
+ zilog->zl_header->zh_claim_lr_seq, committed_seq);
+
+ ztest_dataset_dirobj_verify(zd);
+
+ zil_replay(os, zd, ztest_replay_vector);
+
+ ztest_dataset_dirobj_verify(zd);
+
+ if (ztest_opts.zo_verbose >= 6)
+ (void) printf("%s replay %llu blocks, %llu records, seq %llu\n",
+ zd->zd_name,
+ (u_longlong_t)zilog->zl_parse_blk_count,
+ (u_longlong_t)zilog->zl_parse_lr_count,
+ (u_longlong_t)zilog->zl_replaying_seq);
+
+ zilog = zil_open(os, ztest_get_data);
+
+ if (zilog->zl_replaying_seq != 0 &&
+ zilog->zl_replaying_seq < committed_seq)
+ fatal(0, "missing log records: replayed %llu < committed %llu",
+ zilog->zl_replaying_seq, committed_seq);
+
+ return (0);
+}
+
+static void
+ztest_dataset_close(int d)
+{
+ ztest_ds_t *zd = &ztest_ds[d];
+
+ zil_close(zd->zd_zilog);
+ dmu_objset_disown(zd->zd_os, zd);
+
+ ztest_zd_fini(zd);
+}
+
+/*
+ * Kick off threads to run tests on all datasets in parallel.
+ */
+static void
+ztest_run(ztest_shared_t *zs)
+{
+ thread_t *tid;
+ spa_t *spa;
+ objset_t *os;
+ thread_t resume_tid;
+ int error;
+
+ ztest_exiting = B_FALSE;
+
+ /*
+ * Initialize parent/child shared state.
+ */
+ mutex_init(&ztest_checkpoint_lock, NULL, USYNC_THREAD, NULL);
+ mutex_init(&ztest_vdev_lock, NULL, USYNC_THREAD, NULL);
+ rw_init(&ztest_name_lock, NULL, USYNC_THREAD, NULL);
+
+ zs->zs_thread_start = gethrtime();
+ zs->zs_thread_stop =
+ zs->zs_thread_start + ztest_opts.zo_passtime * NANOSEC;
+ zs->zs_thread_stop = MIN(zs->zs_thread_stop, zs->zs_proc_stop);
+ zs->zs_thread_kill = zs->zs_thread_stop;
+ if (ztest_random(100) < ztest_opts.zo_killrate) {
+ zs->zs_thread_kill -=
+ ztest_random(ztest_opts.zo_passtime * NANOSEC);
+ }
+
+ mutex_init(&zcl.zcl_callbacks_lock, NULL, USYNC_THREAD, NULL);
+
+ list_create(&zcl.zcl_callbacks, sizeof (ztest_cb_data_t),
+ offsetof(ztest_cb_data_t, zcd_node));
+
+ /*
+ * Open our pool.
+ */
+ kernel_init(FREAD | FWRITE);
+ VERIFY0(spa_open(ztest_opts.zo_pool, &spa, FTAG));
+ metaslab_preload_limit = ztest_random(20) + 1;
+ ztest_spa = spa;
+
+ dmu_objset_stats_t dds;
+ VERIFY0(dmu_objset_own(ztest_opts.zo_pool,
+ DMU_OST_ANY, B_TRUE, FTAG, &os));
+ dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
+ dmu_objset_fast_stat(os, &dds);
+ dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
+ zs->zs_guid = dds.dds_guid;
+ dmu_objset_disown(os, FTAG);
+
+ spa->spa_dedup_ditto = 2 * ZIO_DEDUPDITTO_MIN;
+
+ /*
+ * We don't expect the pool to suspend unless maxfaults == 0,
+ * in which case ztest_fault_inject() temporarily takes away
+ * the only valid replica.
+ */
+ if (MAXFAULTS() == 0)
+ spa->spa_failmode = ZIO_FAILURE_MODE_WAIT;
+ else
+ spa->spa_failmode = ZIO_FAILURE_MODE_PANIC;
+
+ /*
+ * Create a thread to periodically resume suspended I/O.
+ */
+ VERIFY(thr_create(0, 0, ztest_resume_thread, spa, THR_BOUND,
+ &resume_tid) == 0);
+
+ /*
+ * Create a deadman thread to abort() if we hang.
+ */
+ VERIFY(thr_create(0, 0, ztest_deadman_thread, zs, THR_BOUND,
+ NULL) == 0);
+
+ /*
+ * Verify that we can safely inquire about any object,
+ * whether it's allocated or not. To make it interesting,
+ * we probe a 5-wide window around each power of two.
+ * This hits all edge cases, including zero and the max.
+ */
+ for (int t = 0; t < 64; t++) {
+ for (int d = -5; d <= 5; d++) {
+ error = dmu_object_info(spa->spa_meta_objset,
+ (1ULL << t) + d, NULL);
+ ASSERT(error == 0 || error == ENOENT ||
+ error == EINVAL);
+ }
+ }
+
+ /*
+ * If we got any ENOSPC errors on the previous run, destroy something.
+ */
+ if (zs->zs_enospc_count != 0) {
+ int d = ztest_random(ztest_opts.zo_datasets);
+ ztest_dataset_destroy(d);
+ }
+ zs->zs_enospc_count = 0;
+
+ tid = umem_zalloc(ztest_opts.zo_threads * sizeof (thread_t),
+ UMEM_NOFAIL);
+
+ if (ztest_opts.zo_verbose >= 4)
+ (void) printf("starting main threads...\n");
+
+ /*
+ * Kick off all the tests that run in parallel.
+ */
+ for (int t = 0; t < ztest_opts.zo_threads; t++) {
+ if (t < ztest_opts.zo_datasets &&
+ ztest_dataset_open(t) != 0)
+ return;
+ VERIFY(thr_create(0, 0, ztest_thread, (void *)(uintptr_t)t,
+ THR_BOUND, &tid[t]) == 0);
+ }
+
+ /*
+ * Wait for all of the tests to complete. We go in reverse order
+ * so we don't close datasets while threads are still using them.
+ */
+ for (int t = ztest_opts.zo_threads - 1; t >= 0; t--) {
+ VERIFY(thr_join(tid[t], NULL, NULL) == 0);
+ if (t < ztest_opts.zo_datasets)
+ ztest_dataset_close(t);
+ }
+
+ txg_wait_synced(spa_get_dsl(spa), 0);
+
+ zs->zs_alloc = metaslab_class_get_alloc(spa_normal_class(spa));
+ zs->zs_space = metaslab_class_get_space(spa_normal_class(spa));
+ zfs_dbgmsg_print(FTAG);
+
+ umem_free(tid, ztest_opts.zo_threads * sizeof (thread_t));
+
+ /* Kill the resume thread */
+ ztest_exiting = B_TRUE;
+ VERIFY(thr_join(resume_tid, NULL, NULL) == 0);
+ ztest_resume(spa);
+
+ /*
+ * Right before closing the pool, kick off a bunch of async I/O;
+ * spa_close() should wait for it to complete.
+ */
+ for (uint64_t object = 1; object < 50; object++) {
+ dmu_prefetch(spa->spa_meta_objset, object, 0, 0, 1ULL << 20,
+ ZIO_PRIORITY_SYNC_READ);
+ }
+
+ spa_close(spa, FTAG);
+
+ /*
+ * Verify that we can loop over all pools.
+ */
+ mutex_enter(&spa_namespace_lock);
+ for (spa = spa_next(NULL); spa != NULL; spa = spa_next(spa))
+ if (ztest_opts.zo_verbose > 3)
+ (void) printf("spa_next: found %s\n", spa_name(spa));
+ mutex_exit(&spa_namespace_lock);
+
+ /*
+ * Verify that we can export the pool and reimport it under a
+ * different name.
+ */
+ if ((ztest_random(2) == 0) && !ztest_opts.zo_mmp_test) {
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ (void) snprintf(name, sizeof (name), "%s_import",
+ ztest_opts.zo_pool);
+ ztest_spa_import_export(ztest_opts.zo_pool, name);
+ ztest_spa_import_export(name, ztest_opts.zo_pool);
+ }
+
+ kernel_fini();
+
+ list_destroy(&zcl.zcl_callbacks);
+
+ mutex_destroy(&zcl.zcl_callbacks_lock);
+
+ rw_destroy(&ztest_name_lock);
+ mutex_destroy(&ztest_vdev_lock);
+ mutex_destroy(&ztest_checkpoint_lock);
+}
+
+static void
+ztest_freeze(void)
+{
+ ztest_ds_t *zd = &ztest_ds[0];
+ spa_t *spa;
+ int numloops = 0;
+
+ if (ztest_opts.zo_verbose >= 3)
+ (void) printf("testing spa_freeze()...\n");
+
+ kernel_init(FREAD | FWRITE);
+ VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
+ VERIFY3U(0, ==, ztest_dataset_open(0));
+ ztest_spa = spa;
+
+ /*
+ * Force the first log block to be transactionally allocated.
+ * We have to do this before we freeze the pool -- otherwise
+ * the log chain won't be anchored.
+ */
+ while (BP_IS_HOLE(&zd->zd_zilog->zl_header->zh_log)) {
+ ztest_dmu_object_alloc_free(zd, 0);
+ zil_commit(zd->zd_zilog, 0);
+ }
+
+ txg_wait_synced(spa_get_dsl(spa), 0);
+
+ /*
+ * Freeze the pool. This stops spa_sync() from doing anything,
+ * so that the only way to record changes from now on is the ZIL.
+ */
+ spa_freeze(spa);
+
+ /*
+ * Because it is hard to predict how much space a write will actually
+ * require beforehand, we leave ourselves some fudge space to write over
+ * capacity.
+ */
+ uint64_t capacity = metaslab_class_get_space(spa_normal_class(spa)) / 2;
+
+ /*
+ * Run tests that generate log records but don't alter the pool config
+ * or depend on DSL sync tasks (snapshots, objset create/destroy, etc).
+ * We do a txg_wait_synced() after each iteration to force the txg
+ * to increase well beyond the last synced value in the uberblock.
+ * The ZIL should be OK with that.
+ *
+ * Run a random number of times less than zo_maxloops and ensure we do
+ * not run out of space on the pool.
+ */
+ while (ztest_random(10) != 0 &&
+ numloops++ < ztest_opts.zo_maxloops &&
+ metaslab_class_get_alloc(spa_normal_class(spa)) < capacity) {
+ ztest_od_t od;
+ ztest_od_init(&od, 0, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0);
+ VERIFY0(ztest_object_init(zd, &od, sizeof (od), B_FALSE));
+ ztest_io(zd, od.od_object,
+ ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
+ txg_wait_synced(spa_get_dsl(spa), 0);
+ }
+
+ /*
+ * Commit all of the changes we just generated.
+ */
+ zil_commit(zd->zd_zilog, 0);
+ txg_wait_synced(spa_get_dsl(spa), 0);
+
+ /*
+ * Close our dataset and close the pool.
+ */
+ ztest_dataset_close(0);
+ spa_close(spa, FTAG);
+ kernel_fini();
+
+ /*
+ * Open and close the pool and dataset to induce log replay.
+ */
+ kernel_init(FREAD | FWRITE);
+ VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
+ ASSERT(spa_freeze_txg(spa) == UINT64_MAX);
+ VERIFY3U(0, ==, ztest_dataset_open(0));
+ ztest_dataset_close(0);
+
+ ztest_spa = spa;
+ txg_wait_synced(spa_get_dsl(spa), 0);
+ ztest_reguid(NULL, 0);
+
+ spa_close(spa, FTAG);
+ kernel_fini();
+}
+
+void
+print_time(hrtime_t t, char *timebuf)
+{
+ hrtime_t s = t / NANOSEC;
+ hrtime_t m = s / 60;
+ hrtime_t h = m / 60;
+ hrtime_t d = h / 24;
+
+ s -= m * 60;
+ m -= h * 60;
+ h -= d * 24;
+
+ timebuf[0] = '\0';
+
+ if (d)
+ (void) sprintf(timebuf,
+ "%llud%02lluh%02llum%02llus", d, h, m, s);
+ else if (h)
+ (void) sprintf(timebuf, "%lluh%02llum%02llus", h, m, s);
+ else if (m)
+ (void) sprintf(timebuf, "%llum%02llus", m, s);
+ else
+ (void) sprintf(timebuf, "%llus", s);
+}
+
+static nvlist_t *
+make_random_props()
+{
+ nvlist_t *props;
+
+ VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
+
+ if (ztest_random(2) == 0)
+ return (props);
+ VERIFY(nvlist_add_uint64(props, "autoreplace", 1) == 0);
+
+ return (props);
+}
+
+/*
+ * Import a storage pool with the given name.
+ */
+static void
+ztest_import(ztest_shared_t *zs)
+{
+ libzfs_handle_t *hdl;
+ importargs_t args = { 0 };
+ spa_t *spa;
+ nvlist_t *cfg = NULL;
+ int nsearch = 1;
+ char *searchdirs[nsearch];
+ char *name = ztest_opts.zo_pool;
+ int flags = ZFS_IMPORT_MISSING_LOG;
+ int error;
+
+ mutex_init(&ztest_vdev_lock, NULL, MUTEX_DEFAULT, NULL);
+ rw_init(&ztest_name_lock, NULL, USYNC_THREAD, NULL);
+
+ kernel_init(FREAD | FWRITE);
+ hdl = libzfs_init();
+
+ searchdirs[0] = ztest_opts.zo_dir;
+ args.paths = nsearch;
+ args.path = searchdirs;
+ args.can_be_active = B_FALSE;
+
+ error = zpool_tryimport(hdl, name, &cfg, &args);
+ if (error)
+ (void) fatal(0, "No pools found\n");
+
+ VERIFY0(spa_import(name, cfg, NULL, flags));
+ VERIFY0(spa_open(name, &spa, FTAG));
+ zs->zs_metaslab_sz =
+ 1ULL << spa->spa_root_vdev->vdev_child[0]->vdev_ms_shift;
+ spa_close(spa, FTAG);
+
+ libzfs_fini(hdl);
+ kernel_fini();
+
+ if (!ztest_opts.zo_mmp_test) {
+ ztest_run_zdb(ztest_opts.zo_pool);
+ ztest_freeze();
+ ztest_run_zdb(ztest_opts.zo_pool);
+ }
+
+ rw_destroy(&ztest_name_lock);
+ mutex_destroy(&ztest_vdev_lock);
+}
+
+/*
+ * Create a storage pool with the given name and initial vdev size.
+ * Then test spa_freeze() functionality.
+ */
+static void
+ztest_init(ztest_shared_t *zs)
+{
+ spa_t *spa;
+ nvlist_t *nvroot, *props;
+
+ mutex_init(&ztest_vdev_lock, NULL, USYNC_THREAD, NULL);
+ mutex_init(&ztest_checkpoint_lock, NULL, USYNC_THREAD, NULL);
+ rw_init(&ztest_name_lock, NULL, USYNC_THREAD, NULL);
+
+ kernel_init(FREAD | FWRITE);
+
+ /*
+ * Create the storage pool.
+ */
+ (void) spa_destroy(ztest_opts.zo_pool);
+ ztest_shared->zs_vdev_next_leaf = 0;
+ zs->zs_splits = 0;
+ zs->zs_mirrors = ztest_opts.zo_mirrors;
+ nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0,
+ NULL, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
+ props = make_random_props();
+ for (int i = 0; i < SPA_FEATURES; i++) {
+ char buf[1024];
+ (void) snprintf(buf, sizeof (buf), "feature@%s",
+ spa_feature_table[i].fi_uname);
+ VERIFY3U(0, ==, nvlist_add_uint64(props, buf, 0));
+ }
+ VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props, NULL));
+ nvlist_free(nvroot);
+ nvlist_free(props);
+
+ VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
+ zs->zs_metaslab_sz =
+ 1ULL << spa->spa_root_vdev->vdev_child[0]->vdev_ms_shift;
+
+ spa_close(spa, FTAG);
+
+ kernel_fini();
+
+ if (!ztest_opts.zo_mmp_test) {
+ ztest_run_zdb(ztest_opts.zo_pool);
+ ztest_freeze();
+ ztest_run_zdb(ztest_opts.zo_pool);
+ }
+
+ rw_destroy(&ztest_name_lock);
+ mutex_destroy(&ztest_vdev_lock);
+ mutex_destroy(&ztest_checkpoint_lock);
+}
+
+static void
+setup_data_fd(void)
+{
+ static char ztest_name_data[] = "/tmp/ztest.data.XXXXXX";
+
+ ztest_fd_data = mkstemp(ztest_name_data);
+ ASSERT3S(ztest_fd_data, >=, 0);
+ (void) unlink(ztest_name_data);
+}
+
+
+static int
+shared_data_size(ztest_shared_hdr_t *hdr)
+{
+ int size;
+
+ size = hdr->zh_hdr_size;
+ size += hdr->zh_opts_size;
+ size += hdr->zh_size;
+ size += hdr->zh_stats_size * hdr->zh_stats_count;
+ size += hdr->zh_ds_size * hdr->zh_ds_count;
+
+ return (size);
+}
+
+static void
+setup_hdr(void)
+{
+ int size;
+ ztest_shared_hdr_t *hdr;
+
+ hdr = (void *)mmap(0, P2ROUNDUP(sizeof (*hdr), getpagesize()),
+ PROT_READ | PROT_WRITE, MAP_SHARED, ztest_fd_data, 0);
+ ASSERT(hdr != MAP_FAILED);
+
+ VERIFY3U(0, ==, ftruncate(ztest_fd_data, sizeof (ztest_shared_hdr_t)));
+
+ hdr->zh_hdr_size = sizeof (ztest_shared_hdr_t);
+ hdr->zh_opts_size = sizeof (ztest_shared_opts_t);
+ hdr->zh_size = sizeof (ztest_shared_t);
+ hdr->zh_stats_size = sizeof (ztest_shared_callstate_t);
+ hdr->zh_stats_count = ZTEST_FUNCS;
+ hdr->zh_ds_size = sizeof (ztest_shared_ds_t);
+ hdr->zh_ds_count = ztest_opts.zo_datasets;
+
+ size = shared_data_size(hdr);
+ VERIFY3U(0, ==, ftruncate(ztest_fd_data, size));
+
+ (void) munmap((caddr_t)hdr, P2ROUNDUP(sizeof (*hdr), getpagesize()));
+}
+
+static void
+setup_data(void)
+{
+ int size, offset;
+ ztest_shared_hdr_t *hdr;
+ uint8_t *buf;
+
+ hdr = (void *)mmap(0, P2ROUNDUP(sizeof (*hdr), getpagesize()),
+ PROT_READ, MAP_SHARED, ztest_fd_data, 0);
+ ASSERT(hdr != MAP_FAILED);
+
+ size = shared_data_size(hdr);
+
+ (void) munmap((caddr_t)hdr, P2ROUNDUP(sizeof (*hdr), getpagesize()));
+ hdr = ztest_shared_hdr = (void *)mmap(0, P2ROUNDUP(size, getpagesize()),
+ PROT_READ | PROT_WRITE, MAP_SHARED, ztest_fd_data, 0);
+ ASSERT(hdr != MAP_FAILED);
+ buf = (uint8_t *)hdr;
+
+ offset = hdr->zh_hdr_size;
+ ztest_shared_opts = (void *)&buf[offset];
+ offset += hdr->zh_opts_size;
+ ztest_shared = (void *)&buf[offset];
+ offset += hdr->zh_size;
+ ztest_shared_callstate = (void *)&buf[offset];
+ offset += hdr->zh_stats_size * hdr->zh_stats_count;
+ ztest_shared_ds = (void *)&buf[offset];
+}
+
+static boolean_t
+exec_child(char *cmd, char *libpath, boolean_t ignorekill, int *statusp)
+{
+ pid_t pid;
+ int status;
+ char *cmdbuf = NULL;
+
+ pid = fork();
+
+ if (cmd == NULL) {
+ cmdbuf = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+ (void) strlcpy(cmdbuf, getexecname(), MAXPATHLEN);
+ cmd = cmdbuf;
+ }
+
+ if (pid == -1)
+ fatal(1, "fork failed");
+
+ if (pid == 0) { /* child */
+ char *emptyargv[2] = { cmd, NULL };
+ char fd_data_str[12];
+
+ struct rlimit rl = { 1024, 1024 };
+ (void) setrlimit(RLIMIT_NOFILE, &rl);
+
+ (void) close(ztest_fd_rand);
+ VERIFY3U(11, >=,
+ snprintf(fd_data_str, 12, "%d", ztest_fd_data));
+ VERIFY0(setenv("ZTEST_FD_DATA", fd_data_str, 1));
+
+ (void) enable_extended_FILE_stdio(-1, -1);
+ if (libpath != NULL)
+ VERIFY(0 == setenv("LD_LIBRARY_PATH", libpath, 1));
+#ifdef illumos
+ (void) execv(cmd, emptyargv);
+#else
+ (void) execvp(cmd, emptyargv);
+#endif
+ ztest_dump_core = B_FALSE;
+ fatal(B_TRUE, "exec failed: %s", cmd);
+ }
+
+ if (cmdbuf != NULL) {
+ umem_free(cmdbuf, MAXPATHLEN);
+ cmd = NULL;
+ }
+
+ while (waitpid(pid, &status, 0) != pid)
+ continue;
+ if (statusp != NULL)
+ *statusp = status;
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0) {
+ (void) fprintf(stderr, "child exited with code %d\n",
+ WEXITSTATUS(status));
+ exit(2);
+ }
+ return (B_FALSE);
+ } else if (WIFSIGNALED(status)) {
+ if (!ignorekill || WTERMSIG(status) != SIGKILL) {
+ (void) fprintf(stderr, "child died with signal %d\n",
+ WTERMSIG(status));
+ exit(3);
+ }
+ return (B_TRUE);
+ } else {
+ (void) fprintf(stderr, "something strange happened to child\n");
+ exit(4);
+ /* NOTREACHED */
+ }
+}
+
+static void
+ztest_run_init(void)
+{
+ ztest_shared_t *zs = ztest_shared;
+
+ /*
+ * Blow away any existing copy of zpool.cache
+ */
+ (void) remove(spa_config_path);
+
+ if (ztest_opts.zo_init == 0) {
+ if (ztest_opts.zo_verbose >= 1)
+ (void) printf("Importing pool %s\n",
+ ztest_opts.zo_pool);
+ ztest_import(zs);
+ return;
+ }
+
+ /*
+ * Create and initialize our storage pool.
+ */
+ for (int i = 1; i <= ztest_opts.zo_init; i++) {
+ bzero(zs, sizeof (ztest_shared_t));
+ if (ztest_opts.zo_verbose >= 3 &&
+ ztest_opts.zo_init != 1) {
+ (void) printf("ztest_init(), pass %d\n", i);
+ }
+ ztest_init(zs);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int kills = 0;
+ int iters = 0;
+ int older = 0;
+ int newer = 0;
+ ztest_shared_t *zs;
+ ztest_info_t *zi;
+ ztest_shared_callstate_t *zc;
+ char timebuf[100];
+ char numbuf[NN_NUMBUF_SZ];
+ char *cmd;
+ boolean_t hasalt;
+ char *fd_data_str = getenv("ZTEST_FD_DATA");
+
+ (void) setvbuf(stdout, NULL, _IOLBF, 0);
+
+ dprintf_setup(&argc, argv);
+ zfs_deadman_synctime_ms = 300000;
+ /*
+ * As two-word space map entries may not come up often (especially
+ * if pool and vdev sizes are small) we want to force at least some
+ * of them so the feature get tested.
+ */
+ zfs_force_some_double_word_sm_entries = B_TRUE;
+
+ /*
+ * Verify that even extensively damaged split blocks with many
+ * segments can be reconstructed in a reasonable amount of time
+ * when reconstruction is known to be possible.
+ */
+ zfs_reconstruct_indirect_damage_fraction = 4;
+
+ ztest_fd_rand = open("/dev/urandom", O_RDONLY);
+ ASSERT3S(ztest_fd_rand, >=, 0);
+
+ if (!fd_data_str) {
+ process_options(argc, argv);
+
+ setup_data_fd();
+ setup_hdr();
+ setup_data();
+ bcopy(&ztest_opts, ztest_shared_opts,
+ sizeof (*ztest_shared_opts));
+ } else {
+ ztest_fd_data = atoi(fd_data_str);
+ setup_data();
+ bcopy(ztest_shared_opts, &ztest_opts, sizeof (ztest_opts));
+ }
+ ASSERT3U(ztest_opts.zo_datasets, ==, ztest_shared_hdr->zh_ds_count);
+
+ /* Override location of zpool.cache */
+ VERIFY3U(asprintf((char **)&spa_config_path, "%s/zpool.cache",
+ ztest_opts.zo_dir), !=, -1);
+
+ ztest_ds = umem_alloc(ztest_opts.zo_datasets * sizeof (ztest_ds_t),
+ UMEM_NOFAIL);
+ zs = ztest_shared;
+
+ if (fd_data_str) {
+ metaslab_force_ganging = ztest_opts.zo_metaslab_force_ganging;
+ metaslab_df_alloc_threshold =
+ zs->zs_metaslab_df_alloc_threshold;
+
+ if (zs->zs_do_init)
+ ztest_run_init();
+ else
+ ztest_run(zs);
+ exit(0);
+ }
+
+ hasalt = (strlen(ztest_opts.zo_alt_ztest) != 0);
+
+ if (ztest_opts.zo_verbose >= 1) {
+ (void) printf("%llu vdevs, %d datasets, %d threads,"
+ " %llu seconds...\n",
+ (u_longlong_t)ztest_opts.zo_vdevs,
+ ztest_opts.zo_datasets,
+ ztest_opts.zo_threads,
+ (u_longlong_t)ztest_opts.zo_time);
+ }
+
+ cmd = umem_alloc(MAXNAMELEN, UMEM_NOFAIL);
+ (void) strlcpy(cmd, getexecname(), MAXNAMELEN);
+
+ zs->zs_do_init = B_TRUE;
+ if (strlen(ztest_opts.zo_alt_ztest) != 0) {
+ if (ztest_opts.zo_verbose >= 1) {
+ (void) printf("Executing older ztest for "
+ "initialization: %s\n", ztest_opts.zo_alt_ztest);
+ }
+ VERIFY(!exec_child(ztest_opts.zo_alt_ztest,
+ ztest_opts.zo_alt_libpath, B_FALSE, NULL));
+ } else {
+ VERIFY(!exec_child(NULL, NULL, B_FALSE, NULL));
+ }
+ zs->zs_do_init = B_FALSE;
+
+ zs->zs_proc_start = gethrtime();
+ zs->zs_proc_stop = zs->zs_proc_start + ztest_opts.zo_time * NANOSEC;
+
+ for (int f = 0; f < ZTEST_FUNCS; f++) {
+ zi = &ztest_info[f];
+ zc = ZTEST_GET_SHARED_CALLSTATE(f);
+ if (zs->zs_proc_start + zi->zi_interval[0] > zs->zs_proc_stop)
+ zc->zc_next = UINT64_MAX;
+ else
+ zc->zc_next = zs->zs_proc_start +
+ ztest_random(2 * zi->zi_interval[0] + 1);
+ }
+
+ /*
+ * Run the tests in a loop. These tests include fault injection
+ * to verify that self-healing data works, and forced crashes
+ * to verify that we never lose on-disk consistency.
+ */
+ while (gethrtime() < zs->zs_proc_stop) {
+ int status;
+ boolean_t killed;
+
+ /*
+ * Initialize the workload counters for each function.
+ */
+ for (int f = 0; f < ZTEST_FUNCS; f++) {
+ zc = ZTEST_GET_SHARED_CALLSTATE(f);
+ zc->zc_count = 0;
+ zc->zc_time = 0;
+ }
+
+ /* Set the allocation switch size */
+ zs->zs_metaslab_df_alloc_threshold =
+ ztest_random(zs->zs_metaslab_sz / 4) + 1;
+
+ if (!hasalt || ztest_random(2) == 0) {
+ if (hasalt && ztest_opts.zo_verbose >= 1) {
+ (void) printf("Executing newer ztest: %s\n",
+ cmd);
+ }
+ newer++;
+ killed = exec_child(cmd, NULL, B_TRUE, &status);
+ } else {
+ if (hasalt && ztest_opts.zo_verbose >= 1) {
+ (void) printf("Executing older ztest: %s\n",
+ ztest_opts.zo_alt_ztest);
+ }
+ older++;
+ killed = exec_child(ztest_opts.zo_alt_ztest,
+ ztest_opts.zo_alt_libpath, B_TRUE, &status);
+ }
+
+ if (killed)
+ kills++;
+ iters++;
+
+ if (ztest_opts.zo_verbose >= 1) {
+ hrtime_t now = gethrtime();
+
+ now = MIN(now, zs->zs_proc_stop);
+ print_time(zs->zs_proc_stop - now, timebuf);
+ nicenum(zs->zs_space, numbuf, sizeof (numbuf));
+
+ (void) printf("Pass %3d, %8s, %3llu ENOSPC, "
+ "%4.1f%% of %5s used, %3.0f%% done, %8s to go\n",
+ iters,
+ WIFEXITED(status) ? "Complete" : "SIGKILL",
+ (u_longlong_t)zs->zs_enospc_count,
+ 100.0 * zs->zs_alloc / zs->zs_space,
+ numbuf,
+ 100.0 * (now - zs->zs_proc_start) /
+ (ztest_opts.zo_time * NANOSEC), timebuf);
+ }
+
+ if (ztest_opts.zo_verbose >= 2) {
+ (void) printf("\nWorkload summary:\n\n");
+ (void) printf("%7s %9s %s\n",
+ "Calls", "Time", "Function");
+ (void) printf("%7s %9s %s\n",
+ "-----", "----", "--------");
+ for (int f = 0; f < ZTEST_FUNCS; f++) {
+ Dl_info dli;
+
+ zi = &ztest_info[f];
+ zc = ZTEST_GET_SHARED_CALLSTATE(f);
+ print_time(zc->zc_time, timebuf);
+ (void) dladdr((void *)zi->zi_func, &dli);
+ (void) printf("%7llu %9s %s\n",
+ (u_longlong_t)zc->zc_count, timebuf,
+ dli.dli_sname);
+ }
+ (void) printf("\n");
+ }
+
+ if (!ztest_opts.zo_mmp_test)
+ ztest_run_zdb(ztest_opts.zo_pool);
+ }
+
+ if (ztest_opts.zo_verbose >= 1) {
+ if (hasalt) {
+ (void) printf("%d runs of older ztest: %s\n", older,
+ ztest_opts.zo_alt_ztest);
+ (void) printf("%d runs of newer ztest: %s\n", newer,
+ cmd);
+ }
+ (void) printf("%d killed, %d completed, %.0f%% kill rate\n",
+ kills, iters - kills, (100.0 * kills) / MAX(1, iters));
+ }
+
+ umem_free(cmd, MAXNAMELEN);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_create.c b/cddl/contrib/opensolaris/common/ctf/ctf_create.c
new file mode 100644
index 000000000000..a2ca81960f73
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_create.c
@@ -0,0 +1,1558 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <ctf_impl.h>
+#include <sys/debug.h>
+
+/*
+ * This static string is used as the template for initially populating a
+ * dynamic container's string table. We always store \0 in the first byte,
+ * and we use the generic string "PARENT" to mark this container's parent
+ * if one is associated with the container using ctf_import().
+ */
+static const char _CTF_STRTAB_TEMPLATE[] = "\0PARENT";
+
+/*
+ * To create an empty CTF container, we just declare a zeroed header and call
+ * ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new container r/w
+ * and initialize the dynamic members. We set dtstrlen to 1 to reserve the
+ * first byte of the string table for a \0 byte, and we start assigning type
+ * IDs at 1 because type ID 0 is used as a sentinel.
+ */
+ctf_file_t *
+ctf_create(int *errp)
+{
+ static const ctf_header_t hdr = { { CTF_MAGIC, CTF_VERSION, 0 } };
+
+ const ulong_t hashlen = 128;
+ ctf_dtdef_t **hash = ctf_alloc(hashlen * sizeof (ctf_dtdef_t *));
+ ctf_sect_t cts;
+ ctf_file_t *fp;
+
+ if (hash == NULL)
+ return (ctf_set_open_errno(errp, EAGAIN));
+
+ cts.cts_name = _CTF_SECTION;
+ cts.cts_type = SHT_PROGBITS;
+ cts.cts_flags = 0;
+ cts.cts_data = (void *)&hdr;
+ cts.cts_size = sizeof (hdr);
+ cts.cts_entsize = 1;
+ cts.cts_offset = 0;
+
+ if ((fp = ctf_bufopen(&cts, NULL, NULL, errp)) == NULL) {
+ ctf_free(hash, hashlen * sizeof (ctf_dtdef_t *));
+ return (NULL);
+ }
+
+ fp->ctf_flags |= LCTF_RDWR;
+ fp->ctf_dthashlen = hashlen;
+ bzero(hash, hashlen * sizeof (ctf_dtdef_t *));
+ fp->ctf_dthash = hash;
+ fp->ctf_dtstrlen = sizeof (_CTF_STRTAB_TEMPLATE);
+ fp->ctf_dtnextid = 1;
+ fp->ctf_dtoldid = 0;
+
+ return (fp);
+}
+
+static uchar_t *
+ctf_copy_smembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t)
+{
+ ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+ ctf_member_t ctm;
+
+ for (; dmd != NULL; dmd = ctf_list_next(dmd)) {
+ if (dmd->dmd_name) {
+ ctm.ctm_name = soff;
+ soff += strlen(dmd->dmd_name) + 1;
+ } else
+ ctm.ctm_name = 0;
+
+ ctm.ctm_type = (ushort_t)dmd->dmd_type;
+ ctm.ctm_offset = (ushort_t)dmd->dmd_offset;
+
+ bcopy(&ctm, t, sizeof (ctm));
+ t += sizeof (ctm);
+ }
+
+ return (t);
+}
+
+static uchar_t *
+ctf_copy_lmembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t)
+{
+ ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+ ctf_lmember_t ctlm;
+
+ for (; dmd != NULL; dmd = ctf_list_next(dmd)) {
+ if (dmd->dmd_name) {
+ ctlm.ctlm_name = soff;
+ soff += strlen(dmd->dmd_name) + 1;
+ } else
+ ctlm.ctlm_name = 0;
+
+ ctlm.ctlm_type = (ushort_t)dmd->dmd_type;
+ ctlm.ctlm_pad = 0;
+ ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI(dmd->dmd_offset);
+ ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO(dmd->dmd_offset);
+
+ bcopy(&ctlm, t, sizeof (ctlm));
+ t += sizeof (ctlm);
+ }
+
+ return (t);
+}
+
+static uchar_t *
+ctf_copy_emembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t)
+{
+ ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+ ctf_enum_t cte;
+
+ for (; dmd != NULL; dmd = ctf_list_next(dmd)) {
+ cte.cte_name = soff;
+ cte.cte_value = dmd->dmd_value;
+ soff += strlen(dmd->dmd_name) + 1;
+ bcopy(&cte, t, sizeof (cte));
+ t += sizeof (cte);
+ }
+
+ return (t);
+}
+
+static uchar_t *
+ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s)
+{
+ ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+ size_t len;
+
+ for (; dmd != NULL; dmd = ctf_list_next(dmd)) {
+ if (dmd->dmd_name == NULL)
+ continue; /* skip anonymous members */
+ len = strlen(dmd->dmd_name) + 1;
+ bcopy(dmd->dmd_name, s, len);
+ s += len;
+ }
+
+ return (s);
+}
+
+/*
+ * Only types of dyanmic CTF containers contain reference counts. These
+ * containers are marked RD/WR. Because of that we basically make this a no-op
+ * for compatability with non-dynamic CTF sections. This is also a no-op for
+ * types which are not dynamic types. It is the responsibility of the caller to
+ * make sure it is a valid type. We help that caller out on debug builds.
+ *
+ * Note that the reference counts are not maintained for types that are not
+ * within this container. In other words if we have a type in a parent, that
+ * will not have its reference count increased. On the flip side, the parent
+ * will not be allowed to remove dynamic types if it has children.
+ */
+static void
+ctf_ref_inc(ctf_file_t *fp, ctf_id_t tid)
+{
+ ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid);
+
+ if (dtd == NULL)
+ return;
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return;
+
+ dtd->dtd_ref++;
+}
+
+/*
+ * Just as with ctf_ref_inc, this is a no-op on non-writeable containers and the
+ * caller should ensure that this is already a valid type.
+ */
+static void
+ctf_ref_dec(ctf_file_t *fp, ctf_id_t tid)
+{
+ ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid);
+
+ if (dtd == NULL)
+ return;
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return;
+
+ ASSERT(dtd->dtd_ref >= 1);
+ dtd->dtd_ref--;
+}
+
+/*
+ * If the specified CTF container is writable and has been modified, reload
+ * this container with the updated type definitions. In order to make this
+ * code and the rest of libctf as simple as possible, we perform updates by
+ * taking the dynamic type definitions and creating an in-memory CTF file
+ * containing the definitions, and then call ctf_bufopen() on it. This not
+ * only leverages ctf_bufopen(), but also avoids having to bifurcate the rest
+ * of the library code with different lookup paths for static and dynamic
+ * type definitions. We are therefore optimizing greatly for lookup over
+ * update, which we assume will be an uncommon operation. We perform one
+ * extra trick here for the benefit of callers and to keep our code simple:
+ * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp
+ * constant for the caller, so after ctf_bufopen() returns, we use bcopy to
+ * swap the interior of the old and new ctf_file_t's, and then free the old.
+ *
+ * Note that the lists of dynamic types stays around and the resulting container
+ * is still writeable. Furthermore, the reference counts that are on the dtd's
+ * are still valid.
+ */
+int
+ctf_update(ctf_file_t *fp)
+{
+ ctf_file_t ofp, *nfp;
+ ctf_header_t hdr;
+ ctf_dtdef_t *dtd;
+ ctf_sect_t cts;
+
+ uchar_t *s, *s0, *t;
+ size_t size;
+ void *buf;
+ int err;
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (!(fp->ctf_flags & LCTF_DIRTY))
+ return (0); /* no update required */
+
+ /*
+ * Fill in an initial CTF header. We will leave the label, object,
+ * and function sections empty and only output a header, type section,
+ * and string table. The type section begins at a 4-byte aligned
+ * boundary past the CTF header itself (at relative offset zero).
+ */
+ bzero(&hdr, sizeof (hdr));
+ hdr.cth_magic = CTF_MAGIC;
+ hdr.cth_version = CTF_VERSION;
+
+ if (fp->ctf_flags & LCTF_CHILD)
+ hdr.cth_parname = 1; /* i.e. _CTF_STRTAB_TEMPLATE[1] */
+
+ /*
+ * Iterate through the dynamic type definition list and compute the
+ * size of the CTF type section we will need to generate.
+ */
+ for (size = 0, dtd = ctf_list_next(&fp->ctf_dtdefs);
+ dtd != NULL; dtd = ctf_list_next(dtd)) {
+
+ uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);
+
+ if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+ size += sizeof (ctf_stype_t);
+ else
+ size += sizeof (ctf_type_t);
+
+ switch (kind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ size += sizeof (uint_t);
+ break;
+ case CTF_K_ARRAY:
+ size += sizeof (ctf_array_t);
+ break;
+ case CTF_K_FUNCTION:
+ size += sizeof (ushort_t) * (vlen + (vlen & 1));
+ break;
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
+ size += sizeof (ctf_member_t) * vlen;
+ else
+ size += sizeof (ctf_lmember_t) * vlen;
+ break;
+ case CTF_K_ENUM:
+ size += sizeof (ctf_enum_t) * vlen;
+ break;
+ }
+ }
+
+ /*
+ * Fill in the string table offset and size, compute the size of the
+ * entire CTF buffer we need, and then allocate a new buffer and
+ * bcopy the finished header to the start of the buffer.
+ */
+ hdr.cth_stroff = hdr.cth_typeoff + size;
+ hdr.cth_strlen = fp->ctf_dtstrlen;
+ size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
+
+ if ((buf = ctf_data_alloc(size)) == MAP_FAILED)
+ return (ctf_set_errno(fp, EAGAIN));
+
+ bcopy(&hdr, buf, sizeof (ctf_header_t));
+ t = (uchar_t *)buf + sizeof (ctf_header_t);
+ s = s0 = (uchar_t *)buf + sizeof (ctf_header_t) + hdr.cth_stroff;
+
+ bcopy(_CTF_STRTAB_TEMPLATE, s, sizeof (_CTF_STRTAB_TEMPLATE));
+ s += sizeof (_CTF_STRTAB_TEMPLATE);
+
+ /*
+ * We now take a final lap through the dynamic type definition list and
+ * copy the appropriate type records and strings to the output buffer.
+ */
+ for (dtd = ctf_list_next(&fp->ctf_dtdefs);
+ dtd != NULL; dtd = ctf_list_next(dtd)) {
+
+ uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);
+
+ ctf_array_t cta;
+ uint_t encoding;
+ size_t len;
+
+ if (dtd->dtd_name != NULL) {
+ dtd->dtd_data.ctt_name = (uint_t)(s - s0);
+ len = strlen(dtd->dtd_name) + 1;
+ bcopy(dtd->dtd_name, s, len);
+ s += len;
+ } else
+ dtd->dtd_data.ctt_name = 0;
+
+ if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+ len = sizeof (ctf_stype_t);
+ else
+ len = sizeof (ctf_type_t);
+
+ bcopy(&dtd->dtd_data, t, len);
+ t += len;
+
+ switch (kind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ if (kind == CTF_K_INTEGER) {
+ encoding = CTF_INT_DATA(
+ dtd->dtd_u.dtu_enc.cte_format,
+ dtd->dtd_u.dtu_enc.cte_offset,
+ dtd->dtd_u.dtu_enc.cte_bits);
+ } else {
+ encoding = CTF_FP_DATA(
+ dtd->dtd_u.dtu_enc.cte_format,
+ dtd->dtd_u.dtu_enc.cte_offset,
+ dtd->dtd_u.dtu_enc.cte_bits);
+ }
+ bcopy(&encoding, t, sizeof (encoding));
+ t += sizeof (encoding);
+ break;
+
+ case CTF_K_ARRAY:
+ cta.cta_contents = (ushort_t)
+ dtd->dtd_u.dtu_arr.ctr_contents;
+ cta.cta_index = (ushort_t)
+ dtd->dtd_u.dtu_arr.ctr_index;
+ cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems;
+ bcopy(&cta, t, sizeof (cta));
+ t += sizeof (cta);
+ break;
+
+ case CTF_K_FUNCTION: {
+ ushort_t *argv = (ushort_t *)(uintptr_t)t;
+ uint_t argc;
+
+ for (argc = 0; argc < vlen; argc++)
+ *argv++ = (ushort_t)dtd->dtd_u.dtu_argv[argc];
+
+ if (vlen & 1)
+ *argv++ = 0; /* pad to 4-byte boundary */
+
+ t = (uchar_t *)argv;
+ break;
+ }
+
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
+ t = ctf_copy_smembers(dtd, (uint_t)(s - s0), t);
+ else
+ t = ctf_copy_lmembers(dtd, (uint_t)(s - s0), t);
+ s = ctf_copy_membnames(dtd, s);
+ break;
+
+ case CTF_K_ENUM:
+ t = ctf_copy_emembers(dtd, (uint_t)(s - s0), t);
+ s = ctf_copy_membnames(dtd, s);
+ break;
+ }
+ }
+
+ /*
+ * Finally, we are ready to ctf_bufopen() the new container. If this
+ * is successful, we then switch nfp and fp and free the old container.
+ */
+ ctf_data_protect(buf, size);
+ cts.cts_name = _CTF_SECTION;
+ cts.cts_type = SHT_PROGBITS;
+ cts.cts_flags = 0;
+ cts.cts_data = buf;
+ cts.cts_size = size;
+ cts.cts_entsize = 1;
+ cts.cts_offset = 0;
+
+ if ((nfp = ctf_bufopen(&cts, NULL, NULL, &err)) == NULL) {
+ ctf_data_free(buf, size);
+ return (ctf_set_errno(fp, err));
+ }
+
+ (void) ctf_setmodel(nfp, ctf_getmodel(fp));
+ (void) ctf_import(nfp, fp->ctf_parent);
+
+ nfp->ctf_refcnt = fp->ctf_refcnt;
+ nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY;
+ nfp->ctf_data.cts_data = NULL; /* force ctf_data_free() on close */
+ nfp->ctf_dthash = fp->ctf_dthash;
+ nfp->ctf_dthashlen = fp->ctf_dthashlen;
+ nfp->ctf_dtdefs = fp->ctf_dtdefs;
+ nfp->ctf_dtstrlen = fp->ctf_dtstrlen;
+ nfp->ctf_dtnextid = fp->ctf_dtnextid;
+ nfp->ctf_dtoldid = fp->ctf_dtnextid - 1;
+ nfp->ctf_specific = fp->ctf_specific;
+
+ fp->ctf_dthash = NULL;
+ fp->ctf_dthashlen = 0;
+ bzero(&fp->ctf_dtdefs, sizeof (ctf_list_t));
+
+ bcopy(fp, &ofp, sizeof (ctf_file_t));
+ bcopy(nfp, fp, sizeof (ctf_file_t));
+ bcopy(&ofp, nfp, sizeof (ctf_file_t));
+
+ /*
+ * Initialize the ctf_lookup_by_name top-level dictionary. We keep an
+ * array of type name prefixes and the corresponding ctf_hash to use.
+ * NOTE: This code must be kept in sync with the code in ctf_bufopen().
+ */
+ fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs;
+ fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions;
+ fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums;
+ fp->ctf_lookups[3].ctl_hash = &fp->ctf_names;
+
+ nfp->ctf_refcnt = 1; /* force nfp to be freed */
+ ctf_close(nfp);
+
+ return (0);
+}
+
+void
+ctf_dtd_insert(ctf_file_t *fp, ctf_dtdef_t *dtd)
+{
+ ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1);
+
+ dtd->dtd_hash = fp->ctf_dthash[h];
+ fp->ctf_dthash[h] = dtd;
+ ctf_list_append(&fp->ctf_dtdefs, dtd);
+}
+
+void
+ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd)
+{
+ ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1);
+ ctf_dtdef_t *p, **q = &fp->ctf_dthash[h];
+ ctf_dmdef_t *dmd, *nmd;
+ size_t len;
+ int kind, i;
+
+ for (p = *q; p != NULL; p = p->dtd_hash) {
+ if (p != dtd)
+ q = &p->dtd_hash;
+ else
+ break;
+ }
+
+ if (p != NULL)
+ *q = p->dtd_hash;
+
+ kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ switch (kind) {
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ case CTF_K_ENUM:
+ for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+ dmd != NULL; dmd = nmd) {
+ if (dmd->dmd_name != NULL) {
+ len = strlen(dmd->dmd_name) + 1;
+ ctf_free(dmd->dmd_name, len);
+ fp->ctf_dtstrlen -= len;
+ }
+ if (kind != CTF_K_ENUM)
+ ctf_ref_dec(fp, dmd->dmd_type);
+ nmd = ctf_list_next(dmd);
+ ctf_free(dmd, sizeof (ctf_dmdef_t));
+ }
+ break;
+ case CTF_K_FUNCTION:
+ ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
+ for (i = 0; i < CTF_INFO_VLEN(dtd->dtd_data.ctt_info); i++)
+ if (dtd->dtd_u.dtu_argv[i] != 0)
+ ctf_ref_dec(fp, dtd->dtd_u.dtu_argv[i]);
+ ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) *
+ CTF_INFO_VLEN(dtd->dtd_data.ctt_info));
+ break;
+ case CTF_K_ARRAY:
+ ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents);
+ ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index);
+ break;
+ case CTF_K_TYPEDEF:
+ ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
+ break;
+ case CTF_K_POINTER:
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
+ break;
+ }
+
+ if (dtd->dtd_name) {
+ len = strlen(dtd->dtd_name) + 1;
+ ctf_free(dtd->dtd_name, len);
+ fp->ctf_dtstrlen -= len;
+ }
+
+ ctf_list_delete(&fp->ctf_dtdefs, dtd);
+ ctf_free(dtd, sizeof (ctf_dtdef_t));
+}
+
+ctf_dtdef_t *
+ctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type)
+{
+ ulong_t h = type & (fp->ctf_dthashlen - 1);
+ ctf_dtdef_t *dtd;
+
+ if (fp->ctf_dthash == NULL)
+ return (NULL);
+
+ for (dtd = fp->ctf_dthash[h]; dtd != NULL; dtd = dtd->dtd_hash) {
+ if (dtd->dtd_type == type)
+ break;
+ }
+
+ return (dtd);
+}
+
+/*
+ * Discard all of the dynamic type definitions that have been added to the
+ * container since the last call to ctf_update(). We locate such types by
+ * scanning the list and deleting elements that have type IDs greater than
+ * ctf_dtoldid, which is set by ctf_update(), above. Note that to work properly
+ * with our reference counting schemes, we must delete the dynamic list in
+ * reverse.
+ */
+int
+ctf_discard(ctf_file_t *fp)
+{
+ ctf_dtdef_t *dtd, *ntd;
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (!(fp->ctf_flags & LCTF_DIRTY))
+ return (0); /* no update required */
+
+ for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
+ ntd = ctf_list_prev(dtd);
+ if (CTF_TYPE_TO_INDEX(dtd->dtd_type) <= fp->ctf_dtoldid)
+ continue; /* skip types that have been committed */
+
+ ctf_dtd_delete(fp, dtd);
+ }
+
+ fp->ctf_dtnextid = fp->ctf_dtoldid + 1;
+ fp->ctf_flags &= ~LCTF_DIRTY;
+
+ return (0);
+}
+
+static ctf_id_t
+ctf_add_generic(ctf_file_t *fp, uint_t flag, const char *name, ctf_dtdef_t **rp)
+{
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+ char *s = NULL;
+
+ if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
+ return (ctf_set_errno(fp, EINVAL));
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (CTF_INDEX_TO_TYPE(fp->ctf_dtnextid, 1) > CTF_MAX_TYPE)
+ return (ctf_set_errno(fp, ECTF_FULL));
+
+ if ((dtd = ctf_alloc(sizeof (ctf_dtdef_t))) == NULL)
+ return (ctf_set_errno(fp, EAGAIN));
+
+ if (name != NULL && (s = ctf_strdup(name)) == NULL) {
+ ctf_free(dtd, sizeof (ctf_dtdef_t));
+ return (ctf_set_errno(fp, EAGAIN));
+ }
+
+ type = fp->ctf_dtnextid++;
+ type = CTF_INDEX_TO_TYPE(type, (fp->ctf_flags & LCTF_CHILD));
+
+ bzero(dtd, sizeof (ctf_dtdef_t));
+ dtd->dtd_name = s;
+ dtd->dtd_type = type;
+
+ if (s != NULL)
+ fp->ctf_dtstrlen += strlen(s) + 1;
+
+ ctf_dtd_insert(fp, dtd);
+ fp->ctf_flags |= LCTF_DIRTY;
+
+ *rp = dtd;
+ return (type);
+}
+
+/*
+ * When encoding integer sizes, we want to convert a byte count in the range
+ * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function
+ * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.
+ */
+static size_t
+clp2(size_t x)
+{
+ x--;
+
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+
+ return (x + 1);
+}
+
+static ctf_id_t
+ctf_add_encoded(ctf_file_t *fp, uint_t flag,
+ const char *name, const ctf_encoding_t *ep, uint_t kind)
+{
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+
+ if (ep == NULL)
+ return (ctf_set_errno(fp, EINVAL));
+
+ if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0);
+ dtd->dtd_data.ctt_size = clp2(P2ROUNDUP(ep->cte_bits, NBBY) / NBBY);
+ dtd->dtd_u.dtu_enc = *ep;
+
+ return (type);
+}
+
+static ctf_id_t
+ctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind)
+{
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+
+ if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
+ return (ctf_set_errno(fp, EINVAL));
+
+ if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ ctf_ref_inc(fp, ref);
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0);
+ dtd->dtd_data.ctt_type = (ushort_t)ref;
+
+ return (type);
+}
+
+ctf_id_t
+ctf_add_integer(ctf_file_t *fp, uint_t flag,
+ const char *name, const ctf_encoding_t *ep)
+{
+ return (ctf_add_encoded(fp, flag, name, ep, CTF_K_INTEGER));
+}
+
+ctf_id_t
+ctf_add_float(ctf_file_t *fp, uint_t flag,
+ const char *name, const ctf_encoding_t *ep)
+{
+ return (ctf_add_encoded(fp, flag, name, ep, CTF_K_FLOAT));
+}
+
+ctf_id_t
+ctf_add_pointer(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
+{
+ return (ctf_add_reftype(fp, flag, ref, CTF_K_POINTER));
+}
+
+ctf_id_t
+ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp)
+{
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+ ctf_file_t *fpd;
+
+ if (arp == NULL)
+ return (ctf_set_errno(fp, EINVAL));
+
+ fpd = fp;
+ if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL &&
+ ctf_dtd_lookup(fp, arp->ctr_contents) == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ fpd = fp;
+ if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL &&
+ ctf_dtd_lookup(fp, arp->ctr_index) == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0);
+ dtd->dtd_data.ctt_size = 0;
+ dtd->dtd_u.dtu_arr = *arp;
+ ctf_ref_inc(fp, arp->ctr_contents);
+ ctf_ref_inc(fp, arp->ctr_index);
+
+ return (type);
+}
+
+int
+ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
+{
+ ctf_file_t *fpd;
+ ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type);
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ fpd = fp;
+ if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL &&
+ ctf_dtd_lookup(fp, arp->ctr_contents) == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ fpd = fp;
+ if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL &&
+ ctf_dtd_lookup(fp, arp->ctr_index) == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents);
+ ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index);
+ fp->ctf_flags |= LCTF_DIRTY;
+ dtd->dtd_u.dtu_arr = *arp;
+ ctf_ref_inc(fp, arp->ctr_contents);
+ ctf_ref_inc(fp, arp->ctr_index);
+
+ return (0);
+}
+
+ctf_id_t
+ctf_add_function(ctf_file_t *fp, uint_t flag,
+ const ctf_funcinfo_t *ctc, const ctf_id_t *argv)
+{
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+ uint_t vlen;
+ int i;
+ ctf_id_t *vdat = NULL;
+ ctf_file_t *fpd;
+
+ if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 ||
+ (ctc->ctc_argc != 0 && argv == NULL))
+ return (ctf_set_errno(fp, EINVAL));
+
+ vlen = ctc->ctc_argc;
+ if (ctc->ctc_flags & CTF_FUNC_VARARG)
+ vlen++; /* add trailing zero to indicate varargs (see below) */
+
+ if (vlen > CTF_MAX_VLEN)
+ return (ctf_set_errno(fp, EOVERFLOW));
+
+ fpd = fp;
+ if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL &&
+ ctf_dtd_lookup(fp, ctc->ctc_return) == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ for (i = 0; i < ctc->ctc_argc; i++) {
+ fpd = fp;
+ if (ctf_lookup_by_id(&fpd, argv[i]) == NULL &&
+ ctf_dtd_lookup(fp, argv[i]) == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+ }
+
+ if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL)
+ return (ctf_set_errno(fp, EAGAIN));
+
+ if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) {
+ ctf_free(vdat, sizeof (ctf_id_t) * vlen);
+ return (CTF_ERR); /* errno is set for us */
+ }
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen);
+ dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return;
+
+ ctf_ref_inc(fp, ctc->ctc_return);
+ for (i = 0; i < ctc->ctc_argc; i++)
+ ctf_ref_inc(fp, argv[i]);
+
+ bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc);
+ if (ctc->ctc_flags & CTF_FUNC_VARARG)
+ vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */
+ dtd->dtd_u.dtu_argv = vdat;
+
+ return (type);
+}
+
+ctf_id_t
+ctf_add_struct(ctf_file_t *fp, uint_t flag, const char *name)
+{
+ ctf_hash_t *hp = &fp->ctf_structs;
+ ctf_helem_t *hep = NULL;
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+
+ if (name != NULL)
+ hep = ctf_hash_lookup(hp, fp, name, strlen(name));
+
+ if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD)
+ dtd = ctf_dtd_lookup(fp, type = hep->h_type);
+ else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, flag, 0);
+ dtd->dtd_data.ctt_size = 0;
+
+ return (type);
+}
+
+ctf_id_t
+ctf_add_union(ctf_file_t *fp, uint_t flag, const char *name)
+{
+ ctf_hash_t *hp = &fp->ctf_unions;
+ ctf_helem_t *hep = NULL;
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+
+ if (name != NULL)
+ hep = ctf_hash_lookup(hp, fp, name, strlen(name));
+
+ if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD)
+ dtd = ctf_dtd_lookup(fp, type = hep->h_type);
+ else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, flag, 0);
+ dtd->dtd_data.ctt_size = 0;
+
+ return (type);
+}
+
+ctf_id_t
+ctf_add_enum(ctf_file_t *fp, uint_t flag, const char *name)
+{
+ ctf_hash_t *hp = &fp->ctf_enums;
+ ctf_helem_t *hep = NULL;
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+
+ if (name != NULL)
+ hep = ctf_hash_lookup(hp, fp, name, strlen(name));
+
+ if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD)
+ dtd = ctf_dtd_lookup(fp, type = hep->h_type);
+ else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, flag, 0);
+ dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int;
+
+ return (type);
+}
+
+ctf_id_t
+ctf_add_forward(ctf_file_t *fp, uint_t flag, const char *name, uint_t kind)
+{
+ ctf_hash_t *hp;
+ ctf_helem_t *hep;
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+
+ switch (kind) {
+ case CTF_K_STRUCT:
+ hp = &fp->ctf_structs;
+ break;
+ case CTF_K_UNION:
+ hp = &fp->ctf_unions;
+ break;
+ case CTF_K_ENUM:
+ hp = &fp->ctf_enums;
+ break;
+ default:
+ return (ctf_set_errno(fp, ECTF_NOTSUE));
+ }
+
+ /*
+ * If the type is already defined or exists as a forward tag, just
+ * return the ctf_id_t of the existing definition.
+ */
+ if (name != NULL && (hep = ctf_hash_lookup(hp,
+ fp, name, strlen(name))) != NULL)
+ return (hep->h_type);
+
+ if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FORWARD, flag, 0);
+ dtd->dtd_data.ctt_type = kind;
+
+ return (type);
+}
+
+ctf_id_t
+ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref)
+{
+ ctf_dtdef_t *dtd;
+ ctf_id_t type;
+ ctf_file_t *fpd;
+
+ fpd = fp;
+ if (ref == CTF_ERR || (ctf_lookup_by_id(&fpd, ref) == NULL &&
+ ctf_dtd_lookup(fp, ref) == NULL))
+ return (ctf_set_errno(fp, EINVAL));
+
+ if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0);
+ dtd->dtd_data.ctt_type = (ushort_t)ref;
+ ctf_ref_inc(fp, ref);
+
+ return (type);
+}
+
+ctf_id_t
+ctf_add_volatile(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
+{
+ return (ctf_add_reftype(fp, flag, ref, CTF_K_VOLATILE));
+}
+
+ctf_id_t
+ctf_add_const(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
+{
+ return (ctf_add_reftype(fp, flag, ref, CTF_K_CONST));
+}
+
+ctf_id_t
+ctf_add_restrict(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
+{
+ return (ctf_add_reftype(fp, flag, ref, CTF_K_RESTRICT));
+}
+
+int
+ctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value)
+{
+ ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, enid);
+ ctf_dmdef_t *dmd;
+
+ uint_t kind, vlen, root;
+ char *s;
+
+ if (name == NULL)
+ return (ctf_set_errno(fp, EINVAL));
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (dtd == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info);
+ vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);
+
+ if (kind != CTF_K_ENUM)
+ return (ctf_set_errno(fp, ECTF_NOTENUM));
+
+ if (vlen == CTF_MAX_VLEN)
+ return (ctf_set_errno(fp, ECTF_DTFULL));
+
+ for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+ dmd != NULL; dmd = ctf_list_next(dmd)) {
+ if (strcmp(dmd->dmd_name, name) == 0)
+ return (ctf_set_errno(fp, ECTF_DUPMEMBER));
+ }
+
+ if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
+ return (ctf_set_errno(fp, EAGAIN));
+
+ if ((s = ctf_strdup(name)) == NULL) {
+ ctf_free(dmd, sizeof (ctf_dmdef_t));
+ return (ctf_set_errno(fp, EAGAIN));
+ }
+
+ dmd->dmd_name = s;
+ dmd->dmd_type = CTF_ERR;
+ dmd->dmd_offset = 0;
+ dmd->dmd_value = value;
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1);
+ ctf_list_append(&dtd->dtd_u.dtu_members, dmd);
+
+ fp->ctf_dtstrlen += strlen(s) + 1;
+ fp->ctf_flags |= LCTF_DIRTY;
+
+ return (0);
+}
+
+int
+ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type)
+{
+ ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, souid);
+ ctf_dmdef_t *dmd;
+
+ ssize_t msize, malign, ssize;
+ uint_t kind, vlen, root;
+ char *s = NULL;
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (dtd == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info);
+ vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);
+
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+ return (ctf_set_errno(fp, ECTF_NOTSOU));
+
+ if (vlen == CTF_MAX_VLEN)
+ return (ctf_set_errno(fp, ECTF_DTFULL));
+
+ if (name != NULL) {
+ for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+ dmd != NULL; dmd = ctf_list_next(dmd)) {
+ if (dmd->dmd_name != NULL &&
+ strcmp(dmd->dmd_name, name) == 0)
+ return (ctf_set_errno(fp, ECTF_DUPMEMBER));
+ }
+ }
+
+ if ((msize = ctf_type_size(fp, type)) == CTF_ERR ||
+ (malign = ctf_type_align(fp, type)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
+ return (ctf_set_errno(fp, EAGAIN));
+
+ if (name != NULL && (s = ctf_strdup(name)) == NULL) {
+ ctf_free(dmd, sizeof (ctf_dmdef_t));
+ return (ctf_set_errno(fp, EAGAIN));
+ }
+
+ dmd->dmd_name = s;
+ dmd->dmd_type = type;
+ dmd->dmd_value = -1;
+
+ if (kind == CTF_K_STRUCT && vlen != 0) {
+ ctf_dmdef_t *lmd = ctf_list_prev(&dtd->dtd_u.dtu_members);
+ ctf_id_t ltype = ctf_type_resolve(fp, lmd->dmd_type);
+ size_t off = lmd->dmd_offset;
+
+ ctf_encoding_t linfo;
+ ssize_t lsize;
+
+ if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR)
+ off += linfo.cte_bits;
+ else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR)
+ off += lsize * NBBY;
+
+ /*
+ * Round up the offset of the end of the last member to the
+ * next byte boundary, convert 'off' to bytes, and then round
+ * it up again to the next multiple of the alignment required
+ * by the new member. Finally, convert back to bits and store
+ * the result in dmd_offset. Technically we could do more
+ * efficient packing if the new member is a bit-field, but
+ * we're the "compiler" and ANSI says we can do as we choose.
+ */
+ off = roundup(off, NBBY) / NBBY;
+ off = roundup(off, MAX(malign, 1));
+ dmd->dmd_offset = off * NBBY;
+ ssize = off + msize;
+ } else {
+ dmd->dmd_offset = 0;
+ ssize = ctf_get_ctt_size(fp, &dtd->dtd_data, NULL, NULL);
+ ssize = MAX(ssize, msize);
+ }
+
+ if (ssize > CTF_MAX_SIZE) {
+ dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+ dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(ssize);
+ dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(ssize);
+ } else
+ dtd->dtd_data.ctt_size = (ushort_t)ssize;
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1);
+ ctf_list_append(&dtd->dtd_u.dtu_members, dmd);
+
+ if (s != NULL)
+ fp->ctf_dtstrlen += strlen(s) + 1;
+
+ ctf_ref_inc(fp, type);
+ fp->ctf_flags |= LCTF_DIRTY;
+ return (0);
+}
+
+/*
+ * This removes a type from the dynamic section. This will fail if the type is
+ * referenced by another type. Note that the CTF ID is never reused currently by
+ * CTF. Note that if this container is a parent container then we just outright
+ * refuse to remove the type. There currently is no notion of searching for the
+ * ctf_dtdef_t in parent containers. If there is, then this constraint could
+ * become finer grained.
+ */
+int
+ctf_delete_type(ctf_file_t *fp, ctf_id_t type)
+{
+ ctf_file_t *fpd;
+ ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type);
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ /*
+ * We want to give as useful an errno as possible. That means that we
+ * want to distinguish between a type which does not exist and one for
+ * which the type is not dynamic.
+ */
+ fpd = fp;
+ if (ctf_lookup_by_id(&fpd, type) == NULL &&
+ ctf_dtd_lookup(fp, type) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (dtd == NULL)
+ return (ctf_set_errno(fp, ECTF_NOTDYN));
+
+ if (dtd->dtd_ref != 0 || fp->ctf_refcnt > 1)
+ return (ctf_set_errno(fp, ECTF_REFERENCED));
+
+ ctf_dtd_delete(fp, dtd);
+ fp->ctf_flags |= LCTF_DIRTY;
+ return (0);
+}
+
+static int
+enumcmp(const char *name, int value, void *arg)
+{
+ ctf_bundle_t *ctb = arg;
+ int bvalue;
+
+ return (ctf_enum_value(ctb->ctb_file, ctb->ctb_type,
+ name, &bvalue) == CTF_ERR || value != bvalue);
+}
+
+static int
+enumadd(const char *name, int value, void *arg)
+{
+ ctf_bundle_t *ctb = arg;
+
+ return (ctf_add_enumerator(ctb->ctb_file, ctb->ctb_type,
+ name, value) == CTF_ERR);
+}
+
+/*ARGSUSED*/
+static int
+membcmp(const char *name, ctf_id_t type, ulong_t offset, void *arg)
+{
+ ctf_bundle_t *ctb = arg;
+ ctf_membinfo_t ctm;
+
+ return (ctf_member_info(ctb->ctb_file, ctb->ctb_type,
+ name, &ctm) == CTF_ERR || ctm.ctm_offset != offset);
+}
+
+static int
+membadd(const char *name, ctf_id_t type, ulong_t offset, void *arg)
+{
+ ctf_bundle_t *ctb = arg;
+ ctf_dmdef_t *dmd;
+ char *s = NULL;
+
+ if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
+ return (ctf_set_errno(ctb->ctb_file, EAGAIN));
+
+ if (name != NULL && (s = ctf_strdup(name)) == NULL) {
+ ctf_free(dmd, sizeof (ctf_dmdef_t));
+ return (ctf_set_errno(ctb->ctb_file, EAGAIN));
+ }
+
+ /*
+ * For now, dmd_type is copied as the src_fp's type; it is reset to an
+ * equivalent dst_fp type by a final loop in ctf_add_type(), below.
+ */
+ dmd->dmd_name = s;
+ dmd->dmd_type = type;
+ dmd->dmd_offset = offset;
+ dmd->dmd_value = -1;
+
+ ctf_list_append(&ctb->ctb_dtd->dtd_u.dtu_members, dmd);
+
+ if (s != NULL)
+ ctb->ctb_file->ctf_dtstrlen += strlen(s) + 1;
+
+ ctb->ctb_file->ctf_flags |= LCTF_DIRTY;
+ return (0);
+}
+
+/*
+ * The ctf_add_type routine is used to copy a type from a source CTF container
+ * to a dynamic destination container. This routine operates recursively by
+ * following the source type's links and embedded member types. If the
+ * destination container already contains a named type which has the same
+ * attributes, then we succeed and return this type but no changes occur.
+ */
+ctf_id_t
+ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
+{
+ ctf_id_t dst_type = CTF_ERR;
+ uint_t dst_kind = CTF_K_UNKNOWN;
+
+ const ctf_type_t *tp;
+ const char *name;
+ uint_t kind, flag, vlen;
+
+ ctf_bundle_t src, dst;
+ ctf_encoding_t src_en, dst_en;
+ ctf_arinfo_t src_ar, dst_ar;
+
+ ctf_dtdef_t *dtd;
+ ctf_funcinfo_t ctc;
+ ssize_t size;
+
+ ctf_hash_t *hp;
+ ctf_helem_t *hep;
+
+ if (dst_fp == src_fp)
+ return (src_type);
+
+ if (!(dst_fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(dst_fp, ECTF_RDONLY));
+
+ if ((tp = ctf_lookup_by_id(&src_fp, src_type)) == NULL)
+ return (ctf_set_errno(dst_fp, ctf_errno(src_fp)));
+
+ name = ctf_strptr(src_fp, tp->ctt_name);
+ kind = LCTF_INFO_KIND(src_fp, tp->ctt_info);
+ flag = LCTF_INFO_ROOT(src_fp, tp->ctt_info);
+ vlen = LCTF_INFO_VLEN(src_fp, tp->ctt_info);
+
+ switch (kind) {
+ case CTF_K_STRUCT:
+ hp = &dst_fp->ctf_structs;
+ break;
+ case CTF_K_UNION:
+ hp = &dst_fp->ctf_unions;
+ break;
+ case CTF_K_ENUM:
+ hp = &dst_fp->ctf_enums;
+ break;
+ default:
+ hp = &dst_fp->ctf_names;
+ break;
+ }
+
+ /*
+ * If the source type has a name and is a root type (visible at the
+ * top-level scope), lookup the name in the destination container and
+ * verify that it is of the same kind before we do anything else.
+ */
+ if ((flag & CTF_ADD_ROOT) && name[0] != '\0' &&
+ (hep = ctf_hash_lookup(hp, dst_fp, name, strlen(name))) != NULL) {
+ dst_type = (ctf_id_t)hep->h_type;
+ dst_kind = ctf_type_kind(dst_fp, dst_type);
+ }
+
+ /*
+ * If an identically named dst_type exists, fail with ECTF_CONFLICT
+ * unless dst_type is a forward declaration and src_type is a struct,
+ * union, or enum (i.e. the definition of the previous forward decl).
+ */
+ if (dst_type != CTF_ERR && dst_kind != kind) {
+ if (dst_kind != CTF_K_FORWARD || (kind != CTF_K_ENUM &&
+ kind != CTF_K_STRUCT && kind != CTF_K_UNION))
+ return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
+ else
+ dst_type = CTF_ERR;
+ }
+
+ /*
+ * If the non-empty name was not found in the appropriate hash, search
+ * the list of pending dynamic definitions that are not yet committed.
+ * If a matching name and kind are found, assume this is the type that
+ * we are looking for. This is necessary to permit ctf_add_type() to
+ * operate recursively on entities such as a struct that contains a
+ * pointer member that refers to the same struct type.
+ *
+ * In the case of integer and floating point types, we match using the
+ * type encoding as well - else we may incorrectly return a bitfield
+ * type, for instance.
+ */
+ if (dst_type == CTF_ERR && name[0] != '\0') {
+ for (dtd = ctf_list_prev(&dst_fp->ctf_dtdefs); dtd != NULL &&
+ CTF_TYPE_TO_INDEX(dtd->dtd_type) > dst_fp->ctf_dtoldid;
+ dtd = ctf_list_prev(dtd)) {
+ if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) != kind ||
+ dtd->dtd_name == NULL ||
+ strcmp(dtd->dtd_name, name) != 0)
+ continue;
+ if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT) {
+ if (ctf_type_encoding(src_fp, src_type,
+ &src_en) != 0)
+ continue;
+ if (bcmp(&src_en, &dtd->dtd_u.dtu_enc,
+ sizeof (ctf_encoding_t)) != 0)
+ continue;
+ }
+ return (dtd->dtd_type);
+ }
+ }
+
+ src.ctb_file = src_fp;
+ src.ctb_type = src_type;
+ src.ctb_dtd = NULL;
+
+ dst.ctb_file = dst_fp;
+ dst.ctb_type = dst_type;
+ dst.ctb_dtd = NULL;
+
+ /*
+ * Now perform kind-specific processing. If dst_type is CTF_ERR, then
+ * we add a new type with the same properties as src_type to dst_fp.
+ * If dst_type is not CTF_ERR, then we verify that dst_type has the
+ * same attributes as src_type. We recurse for embedded references.
+ */
+ switch (kind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ if (ctf_type_encoding(src_fp, src_type, &src_en) != 0)
+ return (ctf_set_errno(dst_fp, ctf_errno(src_fp)));
+
+ if (dst_type != CTF_ERR) {
+ if (ctf_type_encoding(dst_fp, dst_type, &dst_en) != 0)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (bcmp(&src_en, &dst_en, sizeof (ctf_encoding_t)))
+ return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
+
+ } else if (kind == CTF_K_INTEGER) {
+ dst_type = ctf_add_integer(dst_fp, flag, name, &src_en);
+ } else
+ dst_type = ctf_add_float(dst_fp, flag, name, &src_en);
+ break;
+
+ case CTF_K_POINTER:
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ src_type = ctf_type_reference(src_fp, src_type);
+ src_type = ctf_add_type(dst_fp, src_fp, src_type);
+
+ if (src_type == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dst_type = ctf_add_reftype(dst_fp, flag, src_type, kind);
+ break;
+
+ case CTF_K_ARRAY:
+ if (ctf_array_info(src_fp, src_type, &src_ar) == CTF_ERR)
+ return (ctf_set_errno(dst_fp, ctf_errno(src_fp)));
+
+ src_ar.ctr_contents =
+ ctf_add_type(dst_fp, src_fp, src_ar.ctr_contents);
+ src_ar.ctr_index =
+ ctf_add_type(dst_fp, src_fp, src_ar.ctr_index);
+ src_ar.ctr_nelems = src_ar.ctr_nelems;
+
+ if (src_ar.ctr_contents == CTF_ERR ||
+ src_ar.ctr_index == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (dst_type != CTF_ERR) {
+ if (ctf_array_info(dst_fp, dst_type, &dst_ar) != 0)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (bcmp(&src_ar, &dst_ar, sizeof (ctf_arinfo_t)))
+ return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
+ } else
+ dst_type = ctf_add_array(dst_fp, flag, &src_ar);
+ break;
+
+ case CTF_K_FUNCTION:
+ ctc.ctc_return = ctf_add_type(dst_fp, src_fp, tp->ctt_type);
+ ctc.ctc_argc = 0;
+ ctc.ctc_flags = 0;
+
+ if (ctc.ctc_return == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dst_type = ctf_add_function(dst_fp, flag, &ctc, NULL);
+ break;
+
+ case CTF_K_STRUCT:
+ case CTF_K_UNION: {
+ ctf_dmdef_t *dmd;
+ int errs = 0;
+
+ /*
+ * Technically to match a struct or union we need to check both
+ * ways (src members vs. dst, dst members vs. src) but we make
+ * this more optimal by only checking src vs. dst and comparing
+ * the total size of the structure (which we must do anyway)
+ * which covers the possibility of dst members not in src.
+ * This optimization can be defeated for unions, but is so
+ * pathological as to render it irrelevant for our purposes.
+ */
+ if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) {
+ if (ctf_type_size(src_fp, src_type) !=
+ ctf_type_size(dst_fp, dst_type))
+ return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
+
+ if (ctf_member_iter(src_fp, src_type, membcmp, &dst))
+ return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
+
+ break;
+ }
+
+ /*
+ * Unlike the other cases, copying structs and unions is done
+ * manually so as to avoid repeated lookups in ctf_add_member
+ * and to ensure the exact same member offsets as in src_type.
+ */
+ dst_type = ctf_add_generic(dst_fp, flag, name, &dtd);
+ if (dst_type == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ dst.ctb_type = dst_type;
+ dst.ctb_dtd = dtd;
+
+ if (ctf_member_iter(src_fp, src_type, membadd, &dst) != 0)
+ errs++; /* increment errs and fail at bottom of case */
+
+ if ((size = ctf_type_size(src_fp, src_type)) > CTF_MAX_SIZE) {
+ dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+ dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size);
+ dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size);
+ } else
+ dtd->dtd_data.ctt_size = (ushort_t)size;
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, vlen);
+
+ /*
+ * Make a final pass through the members changing each dmd_type
+ * (a src_fp type) to an equivalent type in dst_fp. We pass
+ * through all members, leaving any that fail set to CTF_ERR.
+ */
+ for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+ dmd != NULL; dmd = ctf_list_next(dmd)) {
+ if ((dmd->dmd_type = ctf_add_type(dst_fp, src_fp,
+ dmd->dmd_type)) == CTF_ERR)
+ errs++;
+ }
+
+ if (errs)
+ return (CTF_ERR); /* errno is set for us */
+
+ /*
+ * Now that we know that we can't fail, we go through and bump
+ * all the reference counts on the member types.
+ */
+ for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+ dmd != NULL; dmd = ctf_list_next(dmd))
+ ctf_ref_inc(dst_fp, dmd->dmd_type);
+ break;
+ }
+
+ case CTF_K_ENUM:
+ if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) {
+ if (ctf_enum_iter(src_fp, src_type, enumcmp, &dst) ||
+ ctf_enum_iter(dst_fp, dst_type, enumcmp, &src))
+ return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
+ } else {
+ dst_type = ctf_add_enum(dst_fp, flag, name);
+ if ((dst.ctb_type = dst_type) == CTF_ERR ||
+ ctf_enum_iter(src_fp, src_type, enumadd, &dst))
+ return (CTF_ERR); /* errno is set for us */
+ }
+ break;
+
+ case CTF_K_FORWARD:
+ if (dst_type == CTF_ERR) {
+ dst_type = ctf_add_forward(dst_fp,
+ flag, name, CTF_K_STRUCT); /* assume STRUCT */
+ }
+ break;
+
+ case CTF_K_TYPEDEF:
+ src_type = ctf_type_reference(src_fp, src_type);
+ src_type = ctf_add_type(dst_fp, src_fp, src_type);
+
+ if (src_type == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ /*
+ * If dst_type is not CTF_ERR at this point, we should check if
+ * ctf_type_reference(dst_fp, dst_type) != src_type and if so
+ * fail with ECTF_CONFLICT. However, this causes problems with
+ * <sys/types.h> typedefs that vary based on things like if
+ * _ILP32x then pid_t is int otherwise long. We therefore omit
+ * this check and assume that if the identically named typedef
+ * already exists in dst_fp, it is correct or equivalent.
+ */
+ if (dst_type == CTF_ERR) {
+ dst_type = ctf_add_typedef(dst_fp, flag,
+ name, src_type);
+ }
+ break;
+
+ default:
+ return (ctf_set_errno(dst_fp, ECTF_CORRUPT));
+ }
+
+ return (dst_type);
+}
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_decl.c b/cddl/contrib/opensolaris/common/ctf/ctf_decl.c
new file mode 100644
index 000000000000..6bf57001570f
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_decl.c
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * CTF Declaration Stack
+ *
+ * In order to implement ctf_type_name(), we must convert a type graph back
+ * into a C type declaration. Unfortunately, a type graph represents a storage
+ * class ordering of the type whereas a type declaration must obey the C rules
+ * for operator precedence, and the two orderings are frequently in conflict.
+ * For example, consider these CTF type graphs and their C declarations:
+ *
+ * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER : int (*)()
+ * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER : int (*)[]
+ *
+ * In each case, parentheses are used to raise operator * to higher lexical
+ * precedence, so the string form of the C declaration cannot be constructed by
+ * walking the type graph links and forming the string from left to right.
+ *
+ * The functions in this file build a set of stacks from the type graph nodes
+ * corresponding to the C operator precedence levels in the appropriate order.
+ * The code in ctf_type_name() can then iterate over the levels and nodes in
+ * lexical precedence order and construct the final C declaration string.
+ */
+
+#include <ctf_impl.h>
+
+void
+ctf_decl_init(ctf_decl_t *cd, char *buf, size_t len)
+{
+ int i;
+
+ bzero(cd, sizeof (ctf_decl_t));
+
+ for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++)
+ cd->cd_order[i] = CTF_PREC_BASE - 1;
+
+ cd->cd_qualp = CTF_PREC_BASE;
+ cd->cd_ordp = CTF_PREC_BASE;
+
+ cd->cd_buf = buf;
+ cd->cd_ptr = buf;
+ cd->cd_end = buf + len;
+}
+
+void
+ctf_decl_fini(ctf_decl_t *cd)
+{
+ ctf_decl_node_t *cdp, *ndp;
+ int i;
+
+ for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) {
+ for (cdp = ctf_list_next(&cd->cd_nodes[i]);
+ cdp != NULL; cdp = ndp) {
+ ndp = ctf_list_next(cdp);
+ ctf_free(cdp, sizeof (ctf_decl_node_t));
+ }
+ }
+}
+
+void
+ctf_decl_push(ctf_decl_t *cd, ctf_file_t *fp, ctf_id_t type)
+{
+ ctf_decl_node_t *cdp;
+ ctf_decl_prec_t prec;
+ uint_t kind, n = 1;
+ int is_qual = 0;
+
+ const ctf_type_t *tp;
+ ctf_arinfo_t ar;
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) {
+ cd->cd_err = fp->ctf_errno;
+ return;
+ }
+
+ switch (kind = LCTF_INFO_KIND(fp, tp->ctt_info)) {
+ case CTF_K_ARRAY:
+ (void) ctf_array_info(fp, type, &ar);
+ ctf_decl_push(cd, fp, ar.ctr_contents);
+ n = ar.ctr_nelems;
+ prec = CTF_PREC_ARRAY;
+ break;
+
+ case CTF_K_TYPEDEF:
+ if (ctf_strptr(fp, tp->ctt_name)[0] == '\0') {
+ ctf_decl_push(cd, fp, tp->ctt_type);
+ return;
+ }
+ prec = CTF_PREC_BASE;
+ break;
+
+ case CTF_K_FUNCTION:
+ ctf_decl_push(cd, fp, tp->ctt_type);
+ prec = CTF_PREC_FUNCTION;
+ break;
+
+ case CTF_K_POINTER:
+ ctf_decl_push(cd, fp, tp->ctt_type);
+ prec = CTF_PREC_POINTER;
+ break;
+
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ ctf_decl_push(cd, fp, tp->ctt_type);
+ prec = cd->cd_qualp;
+ is_qual++;
+ break;
+
+ default:
+ prec = CTF_PREC_BASE;
+ }
+
+ if ((cdp = ctf_alloc(sizeof (ctf_decl_node_t))) == NULL) {
+ cd->cd_err = EAGAIN;
+ return;
+ }
+
+ cdp->cd_type = type;
+ cdp->cd_kind = kind;
+ cdp->cd_n = n;
+
+ if (ctf_list_next(&cd->cd_nodes[prec]) == NULL)
+ cd->cd_order[prec] = cd->cd_ordp++;
+
+ /*
+ * Reset cd_qualp to the highest precedence level that we've seen so
+ * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER).
+ */
+ if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY)
+ cd->cd_qualp = prec;
+
+ /*
+ * C array declarators are ordered inside out so prepend them. Also by
+ * convention qualifiers of base types precede the type specifier (e.g.
+ * const int vs. int const) even though the two forms are equivalent.
+ */
+ if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE))
+ ctf_list_prepend(&cd->cd_nodes[prec], cdp);
+ else
+ ctf_list_append(&cd->cd_nodes[prec], cdp);
+}
+
+/*PRINTFLIKE2*/
+void
+ctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...)
+{
+ size_t len = (size_t)(cd->cd_end - cd->cd_ptr);
+ va_list ap;
+ size_t n;
+
+ va_start(ap, format);
+ n = vsnprintf(cd->cd_ptr, len, format, ap);
+ va_end(ap);
+
+ cd->cd_ptr += MIN(n, len);
+ cd->cd_len += n;
+}
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_error.c b/cddl/contrib/opensolaris/common/ctf/ctf_error.c
new file mode 100644
index 000000000000..fe3d0de0cb93
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_error.c
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2012, Joyent, Inc.
+ */
+
+#include <ctf_impl.h>
+
+static const char *const _ctf_errlist[] = {
+ "File is not in CTF or ELF format", /* ECTF_FMT */
+ "File uses more recent ELF version than libctf", /* ECTF_ELFVERS */
+ "File uses more recent CTF version than libctf", /* ECTF_CTFVERS */
+ "File is a different endian-ness than libctf", /* ECTF_ENDIAN */
+ "Symbol table uses invalid entry size", /* ECTF_SYMTAB */
+ "Symbol table data buffer is not valid", /* ECTF_SYMBAD */
+ "String table data buffer is not valid", /* ECTF_STRBAD */
+ "File data structure corruption detected", /* ECTF_CORRUPT */
+ "File does not contain CTF data", /* ECTF_NOCTFDATA */
+ "Buffer does not contain CTF data", /* ECTF_NOCTFBUF */
+ "Symbol table information is not available", /* ECTF_NOSYMTAB */
+ "Type information is in parent and unavailable", /* ECTF_NOPARENT */
+ "Cannot import types with different data model", /* ECTF_DMODEL */
+ "Failed to mmap a needed data section", /* ECTF_MMAP */
+ "Decompression package SUNWzlib not installed", /* ECTF_ZMISSING */
+ "Failed to initialize decompression library", /* ECTF_ZINIT */
+ "Failed to allocate decompression buffer", /* ECTF_ZALLOC */
+ "Failed to decompress CTF data", /* ECTF_DECOMPRESS */
+ "External string table is not available", /* ECTF_STRTAB */
+ "String name offset is corrupt", /* ECTF_BADNAME */
+ "Invalid type identifier", /* ECTF_BADID */
+ "Type is not a struct or union", /* ECTF_NOTSOU */
+ "Type is not an enum", /* ECTF_NOTENUM */
+ "Type is not a struct, union, or enum", /* ECTF_NOTSUE */
+ "Type is not an integer or float", /* ECTF_NOTINTFP */
+ "Type is not an array", /* ECTF_NOTARRAY */
+ "Type does not reference another type", /* ECTF_NOTREF */
+ "Input buffer is too small for type name", /* ECTF_NAMELEN */
+ "No type information available for that name", /* ECTF_NOTYPE */
+ "Syntax error in type name", /* ECTF_SYNTAX */
+ "Symbol table entry is not a function", /* ECTF_NOTFUNC */
+ "No function information available for symbol", /* ECTF_NOFUNCDAT */
+ "Symbol table entry is not a data object", /* ECTF_NOTDATA */
+ "No type information available for symbol", /* ECTF_NOTYPEDAT */
+ "No label information available for that name", /* ECTF_NOLABEL */
+ "File does not contain any labels", /* ECTF_NOLABELDATA */
+ "Feature not supported", /* ECTF_NOTSUP */
+ "Invalid enum element name", /* ECTF_NOENUMNAM */
+ "Invalid member name", /* ECTF_NOMEMBNAM */
+ "CTF container is read-only", /* ECTF_RDONLY */
+ "Limit on number of dynamic type members reached", /* ECTF_DTFULL */
+ "Limit on number of dynamic types reached", /* ECTF_FULL */
+ "Duplicate member name definition", /* ECTF_DUPMEMBER */
+ "Conflicting type is already defined", /* ECTF_CONFLICT */
+ "Type has outstanding references", /* ECTF_REFERENCED */
+ "Type is not a dynamic type" /* ECTF_NOTDYN */
+};
+
+static const int _ctf_nerr = sizeof (_ctf_errlist) / sizeof (_ctf_errlist[0]);
+
+const char *
+ctf_errmsg(int error)
+{
+ const char *str;
+
+ if (error >= ECTF_BASE && (error - ECTF_BASE) < _ctf_nerr)
+ str = _ctf_errlist[error - ECTF_BASE];
+ else
+ str = ctf_strerror(error);
+
+ return (str ? str : "Unknown error");
+}
+
+int
+ctf_errno(ctf_file_t *fp)
+{
+ return (fp->ctf_errno);
+}
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_hash.c b/cddl/contrib/opensolaris/common/ctf/ctf_hash.c
new file mode 100644
index 000000000000..b10a7618f66e
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_hash.c
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ctf_impl.h>
+
+static const ushort_t _CTF_EMPTY[1] = { 0 };
+
+int
+ctf_hash_create(ctf_hash_t *hp, ulong_t nelems)
+{
+ if (nelems > USHRT_MAX)
+ return (EOVERFLOW);
+
+ /*
+ * If the hash table is going to be empty, don't bother allocating any
+ * memory and make the only bucket point to a zero so lookups fail.
+ */
+ if (nelems == 0) {
+ bzero(hp, sizeof (ctf_hash_t));
+ hp->h_buckets = (ushort_t *)_CTF_EMPTY;
+ hp->h_nbuckets = 1;
+ return (0);
+ }
+
+ hp->h_nbuckets = 211; /* use a prime number of hash buckets */
+ hp->h_nelems = nelems + 1; /* we use index zero as a sentinel */
+ hp->h_free = 1; /* first free element is index 1 */
+
+ hp->h_buckets = ctf_alloc(sizeof (ushort_t) * hp->h_nbuckets);
+ hp->h_chains = ctf_alloc(sizeof (ctf_helem_t) * hp->h_nelems);
+
+ if (hp->h_buckets == NULL || hp->h_chains == NULL) {
+ ctf_hash_destroy(hp);
+ return (EAGAIN);
+ }
+
+ bzero(hp->h_buckets, sizeof (ushort_t) * hp->h_nbuckets);
+ bzero(hp->h_chains, sizeof (ctf_helem_t) * hp->h_nelems);
+
+ return (0);
+}
+
+uint_t
+ctf_hash_size(const ctf_hash_t *hp)
+{
+ return (hp->h_nelems ? hp->h_nelems - 1 : 0);
+}
+
+static ulong_t
+ctf_hash_compute(const char *key, size_t len)
+{
+ ulong_t g, h = 0;
+ const char *p, *q = key + len;
+ size_t n = 0;
+
+ for (p = key; p < q; p++, n++) {
+ h = (h << 4) + *p;
+
+ if ((g = (h & 0xf0000000)) != 0) {
+ h ^= (g >> 24);
+ h ^= g;
+ }
+ }
+
+ return (h);
+}
+
+int
+ctf_hash_insert(ctf_hash_t *hp, ctf_file_t *fp, ushort_t type, uint_t name)
+{
+ ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID(name)];
+ const char *str = ctsp->cts_strs + CTF_NAME_OFFSET(name);
+ ctf_helem_t *hep = &hp->h_chains[hp->h_free];
+ ulong_t h;
+
+ if (type == 0)
+ return (EINVAL);
+
+ if (hp->h_free >= hp->h_nelems)
+ return (EOVERFLOW);
+
+ if (ctsp->cts_strs == NULL)
+ return (ECTF_STRTAB);
+
+ if (ctsp->cts_len <= CTF_NAME_OFFSET(name))
+ return (ECTF_BADNAME);
+
+ if (str[0] == '\0')
+ return (0); /* just ignore empty strings on behalf of caller */
+
+ hep->h_name = name;
+ hep->h_type = type;
+ h = ctf_hash_compute(str, strlen(str)) % hp->h_nbuckets;
+ hep->h_next = hp->h_buckets[h];
+ hp->h_buckets[h] = hp->h_free++;
+
+ return (0);
+}
+
+/*
+ * Wrapper for ctf_hash_lookup/ctf_hash_insert: if the key is already in the
+ * hash, override the previous definition with this new official definition.
+ * If the key is not present, then call ctf_hash_insert() and hash it in.
+ */
+int
+ctf_hash_define(ctf_hash_t *hp, ctf_file_t *fp, ushort_t type, uint_t name)
+{
+ const char *str = ctf_strptr(fp, name);
+ ctf_helem_t *hep = ctf_hash_lookup(hp, fp, str, strlen(str));
+
+ if (hep == NULL)
+ return (ctf_hash_insert(hp, fp, type, name));
+
+ hep->h_type = type;
+ return (0);
+}
+
+ctf_helem_t *
+ctf_hash_lookup(ctf_hash_t *hp, ctf_file_t *fp, const char *key, size_t len)
+{
+ ctf_helem_t *hep;
+ ctf_strs_t *ctsp;
+ const char *str;
+ ushort_t i;
+
+ ulong_t h = ctf_hash_compute(key, len) % hp->h_nbuckets;
+
+ for (i = hp->h_buckets[h]; i != 0; i = hep->h_next) {
+ hep = &hp->h_chains[i];
+ ctsp = &fp->ctf_str[CTF_NAME_STID(hep->h_name)];
+ str = ctsp->cts_strs + CTF_NAME_OFFSET(hep->h_name);
+
+ if (strncmp(key, str, len) == 0 && str[len] == '\0')
+ return (hep);
+ }
+
+ return (NULL);
+}
+
+void
+ctf_hash_destroy(ctf_hash_t *hp)
+{
+ if (hp->h_buckets != NULL && hp->h_nbuckets != 1) {
+ ctf_free(hp->h_buckets, sizeof (ushort_t) * hp->h_nbuckets);
+ hp->h_buckets = NULL;
+ }
+
+ if (hp->h_chains != NULL) {
+ ctf_free(hp->h_chains, sizeof (ctf_helem_t) * hp->h_nelems);
+ hp->h_chains = NULL;
+ }
+}
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_impl.h b/cddl/contrib/opensolaris/common/ctf/ctf_impl.h
new file mode 100644
index 000000000000..f56fa6a00548
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_impl.h
@@ -0,0 +1,340 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _CTF_IMPL_H
+#define _CTF_IMPL_H
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/sysmacros.h>
+#include <sys/ctf_api.h>
+
+#ifdef _KERNEL
+
+#include <sys/systm.h>
+#include <sys/cmn_err.h>
+#include <sys/varargs.h>
+
+#define isspace(c) \
+ ((c) == ' ' || (c) == '\t' || (c) == '\n' || \
+ (c) == '\r' || (c) == '\f' || (c) == '\v')
+
+#define MAP_FAILED ((void *)-1)
+
+#else /* _KERNEL */
+
+#include <strings.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ctf_helem {
+ uint_t h_name; /* reference to name in string table */
+ ushort_t h_type; /* corresponding type ID number */
+ ushort_t h_next; /* index of next element in hash chain */
+} ctf_helem_t;
+
+typedef struct ctf_hash {
+ ushort_t *h_buckets; /* hash bucket array (chain indices) */
+ ctf_helem_t *h_chains; /* hash chains buffer */
+ ushort_t h_nbuckets; /* number of elements in bucket array */
+ ushort_t h_nelems; /* number of elements in hash table */
+ uint_t h_free; /* index of next free hash element */
+} ctf_hash_t;
+
+typedef struct ctf_strs {
+ const char *cts_strs; /* base address of string table */
+ size_t cts_len; /* size of string table in bytes */
+} ctf_strs_t;
+
+typedef struct ctf_dmodel {
+ const char *ctd_name; /* data model name */
+ int ctd_code; /* data model code */
+ size_t ctd_pointer; /* size of void * in bytes */
+ size_t ctd_char; /* size of char in bytes */
+ size_t ctd_short; /* size of short in bytes */
+ size_t ctd_int; /* size of int in bytes */
+ size_t ctd_long; /* size of long in bytes */
+} ctf_dmodel_t;
+
+typedef struct ctf_lookup {
+ const char *ctl_prefix; /* string prefix for this lookup */
+ size_t ctl_len; /* length of prefix string in bytes */
+ ctf_hash_t *ctl_hash; /* pointer to hash table for lookup */
+} ctf_lookup_t;
+
+typedef struct ctf_fileops {
+ ushort_t (*ctfo_get_kind)(ushort_t);
+ ushort_t (*ctfo_get_root)(ushort_t);
+ ushort_t (*ctfo_get_vlen)(ushort_t);
+} ctf_fileops_t;
+
+typedef struct ctf_list {
+ struct ctf_list *l_prev; /* previous pointer or tail pointer */
+ struct ctf_list *l_next; /* next pointer or head pointer */
+} ctf_list_t;
+
+typedef enum {
+ CTF_PREC_BASE,
+ CTF_PREC_POINTER,
+ CTF_PREC_ARRAY,
+ CTF_PREC_FUNCTION,
+ CTF_PREC_MAX
+} ctf_decl_prec_t;
+
+typedef struct ctf_decl_node {
+ ctf_list_t cd_list; /* linked list pointers */
+ ctf_id_t cd_type; /* type identifier */
+ uint_t cd_kind; /* type kind */
+ uint_t cd_n; /* type dimension if array */
+} ctf_decl_node_t;
+
+typedef struct ctf_decl {
+ ctf_list_t cd_nodes[CTF_PREC_MAX]; /* declaration node stacks */
+ int cd_order[CTF_PREC_MAX]; /* storage order of decls */
+ ctf_decl_prec_t cd_qualp; /* qualifier precision */
+ ctf_decl_prec_t cd_ordp; /* ordered precision */
+ char *cd_buf; /* buffer for output */
+ char *cd_ptr; /* buffer location */
+ char *cd_end; /* buffer limit */
+ size_t cd_len; /* buffer space required */
+ int cd_err; /* saved error value */
+} ctf_decl_t;
+
+typedef struct ctf_dmdef {
+ ctf_list_t dmd_list; /* list forward/back pointers */
+ char *dmd_name; /* name of this member */
+ ctf_id_t dmd_type; /* type of this member (for sou) */
+ ulong_t dmd_offset; /* offset of this member in bits (for sou) */
+ int dmd_value; /* value of this member (for enum) */
+} ctf_dmdef_t;
+
+typedef struct ctf_dtdef {
+ ctf_list_t dtd_list; /* list forward/back pointers */
+ struct ctf_dtdef *dtd_hash; /* hash chain pointer for ctf_dthash */
+ char *dtd_name; /* name associated with definition (if any) */
+ ctf_id_t dtd_type; /* type identifier for this definition */
+ ctf_type_t dtd_data; /* type node (see <sys/ctf.h>) */
+ int dtd_ref; /* recfount for dyanmic types */
+ union {
+ ctf_list_t dtu_members; /* struct, union, or enum */
+ ctf_arinfo_t dtu_arr; /* array */
+ ctf_encoding_t dtu_enc; /* integer or float */
+ ctf_id_t *dtu_argv; /* function */
+ } dtd_u;
+} ctf_dtdef_t;
+
+typedef struct ctf_bundle {
+ ctf_file_t *ctb_file; /* CTF container handle */
+ ctf_id_t ctb_type; /* CTF type identifier */
+ ctf_dtdef_t *ctb_dtd; /* CTF dynamic type definition (if any) */
+} ctf_bundle_t;
+
+/*
+ * The ctf_file is the structure used to represent a CTF container to library
+ * clients, who see it only as an opaque pointer. Modifications can therefore
+ * be made freely to this structure without regard to client versioning. The
+ * ctf_file_t typedef appears in <sys/ctf_api.h> and declares a forward tag.
+ *
+ * NOTE: ctf_update() requires that everything inside of ctf_file either be an
+ * immediate value, a pointer to dynamically allocated data *outside* of the
+ * ctf_file itself, or a pointer to statically allocated data. If you add a
+ * pointer to ctf_file that points to something within the ctf_file itself,
+ * you must make corresponding changes to ctf_update().
+ */
+struct ctf_file {
+ const ctf_fileops_t *ctf_fileops; /* version-specific file operations */
+ ctf_sect_t ctf_data; /* CTF data from object file */
+ ctf_sect_t ctf_symtab; /* symbol table from object file */
+ ctf_sect_t ctf_strtab; /* string table from object file */
+ ctf_hash_t ctf_structs; /* hash table of struct types */
+ ctf_hash_t ctf_unions; /* hash table of union types */
+ ctf_hash_t ctf_enums; /* hash table of enum types */
+ ctf_hash_t ctf_names; /* hash table of remaining type names */
+ ctf_lookup_t ctf_lookups[5]; /* pointers to hashes for name lookup */
+ ctf_strs_t ctf_str[2]; /* array of string table base and bounds */
+ const uchar_t *ctf_base; /* base of CTF header + uncompressed buffer */
+ const uchar_t *ctf_buf; /* uncompressed CTF data buffer */
+ size_t ctf_size; /* size of CTF header + uncompressed data */
+ uint_t *ctf_sxlate; /* translation table for symtab entries */
+ ulong_t ctf_nsyms; /* number of entries in symtab xlate table */
+ uint_t *ctf_txlate; /* translation table for type IDs */
+ ushort_t *ctf_ptrtab; /* translation table for pointer-to lookups */
+ ulong_t ctf_typemax; /* maximum valid type ID number */
+ const ctf_dmodel_t *ctf_dmodel; /* data model pointer (see above) */
+ struct ctf_file *ctf_parent; /* parent CTF container (if any) */
+ const char *ctf_parlabel; /* label in parent container (if any) */
+ const char *ctf_parname; /* basename of parent (if any) */
+ uint_t ctf_refcnt; /* reference count (for parent links) */
+ uint_t ctf_flags; /* libctf flags (see below) */
+ int ctf_errno; /* error code for most recent error */
+ int ctf_version; /* CTF data version */
+ ctf_dtdef_t **ctf_dthash; /* hash of dynamic type definitions */
+ ulong_t ctf_dthashlen; /* size of dynamic type hash bucket array */
+ ctf_list_t ctf_dtdefs; /* list of dynamic type definitions */
+ size_t ctf_dtstrlen; /* total length of dynamic type strings */
+ ulong_t ctf_dtnextid; /* next dynamic type id to assign */
+ ulong_t ctf_dtoldid; /* oldest id that has been committed */
+ void *ctf_specific; /* data for ctf_get/setspecific */
+};
+
+#define LCTF_INDEX_TO_TYPEPTR(fp, i) \
+ ((ctf_type_t *)((uintptr_t)(fp)->ctf_buf + (fp)->ctf_txlate[(i)]))
+
+#define LCTF_INFO_KIND(fp, info) ((fp)->ctf_fileops->ctfo_get_kind(info))
+#define LCTF_INFO_ROOT(fp, info) ((fp)->ctf_fileops->ctfo_get_root(info))
+#define LCTF_INFO_VLEN(fp, info) ((fp)->ctf_fileops->ctfo_get_vlen(info))
+
+#define LCTF_MMAP 0x0001 /* libctf should munmap buffers on close */
+#define LCTF_CHILD 0x0002 /* CTF container is a child */
+#define LCTF_RDWR 0x0004 /* CTF container is writable */
+#define LCTF_DIRTY 0x0008 /* CTF container has been modified */
+
+#define ECTF_BASE 1000 /* base value for libctf errnos */
+
+enum {
+ ECTF_FMT = ECTF_BASE, /* file is not in CTF or ELF format */
+ ECTF_ELFVERS, /* ELF version is more recent than libctf */
+ ECTF_CTFVERS, /* CTF version is more recent than libctf */
+ ECTF_ENDIAN, /* data is different endian-ness than lib */
+ ECTF_SYMTAB, /* symbol table uses invalid entry size */
+ ECTF_SYMBAD, /* symbol table data buffer invalid */
+ ECTF_STRBAD, /* string table data buffer invalid */
+ ECTF_CORRUPT, /* file data corruption detected */
+ ECTF_NOCTFDATA, /* ELF file does not contain CTF data */
+ ECTF_NOCTFBUF, /* buffer does not contain CTF data */
+ ECTF_NOSYMTAB, /* symbol table data is not available */
+ ECTF_NOPARENT, /* parent CTF container is not available */
+ ECTF_DMODEL, /* data model mismatch */
+ ECTF_MMAP, /* failed to mmap a data section */
+ ECTF_ZMISSING, /* decompression library not installed */
+ ECTF_ZINIT, /* failed to initialize decompression library */
+ ECTF_ZALLOC, /* failed to allocate decompression buffer */
+ ECTF_DECOMPRESS, /* failed to decompress CTF data */
+ ECTF_STRTAB, /* string table for this string is missing */
+ ECTF_BADNAME, /* string offset is corrupt w.r.t. strtab */
+ ECTF_BADID, /* invalid type ID number */
+ ECTF_NOTSOU, /* type is not a struct or union */
+ ECTF_NOTENUM, /* type is not an enum */
+ ECTF_NOTSUE, /* type is not a struct, union, or enum */
+ ECTF_NOTINTFP, /* type is not an integer or float */
+ ECTF_NOTARRAY, /* type is not an array */
+ ECTF_NOTREF, /* type does not reference another type */
+ ECTF_NAMELEN, /* buffer is too small to hold type name */
+ ECTF_NOTYPE, /* no type found corresponding to name */
+ ECTF_SYNTAX, /* syntax error in type name */
+ ECTF_NOTFUNC, /* symtab entry does not refer to a function */
+ ECTF_NOFUNCDAT, /* no func info available for function */
+ ECTF_NOTDATA, /* symtab entry does not refer to a data obj */
+ ECTF_NOTYPEDAT, /* no type info available for object */
+ ECTF_NOLABEL, /* no label found corresponding to name */
+ ECTF_NOLABELDATA, /* file does not contain any labels */
+ ECTF_NOTSUP, /* feature not supported */
+ ECTF_NOENUMNAM, /* enum element name not found */
+ ECTF_NOMEMBNAM, /* member name not found */
+ ECTF_RDONLY, /* CTF container is read-only */
+ ECTF_DTFULL, /* CTF type is full (no more members allowed) */
+ ECTF_FULL, /* CTF container is full */
+ ECTF_DUPMEMBER, /* duplicate member name definition */
+ ECTF_CONFLICT, /* conflicting type definition present */
+ ECTF_REFERENCED, /* type has outstanding references */
+ ECTF_NOTDYN /* type is not a dynamic type */
+};
+
+extern ssize_t ctf_get_ctt_size(const ctf_file_t *, const ctf_type_t *,
+ ssize_t *, ssize_t *);
+
+extern const ctf_type_t *ctf_lookup_by_id(ctf_file_t **, ctf_id_t);
+
+extern int ctf_hash_create(ctf_hash_t *, ulong_t);
+extern int ctf_hash_insert(ctf_hash_t *, ctf_file_t *, ushort_t, uint_t);
+extern int ctf_hash_define(ctf_hash_t *, ctf_file_t *, ushort_t, uint_t);
+extern ctf_helem_t *ctf_hash_lookup(ctf_hash_t *, ctf_file_t *,
+ const char *, size_t);
+extern uint_t ctf_hash_size(const ctf_hash_t *);
+extern void ctf_hash_destroy(ctf_hash_t *);
+
+#define ctf_list_prev(elem) ((void *)(((ctf_list_t *)(elem))->l_prev))
+#define ctf_list_next(elem) ((void *)(((ctf_list_t *)(elem))->l_next))
+
+extern void ctf_list_append(ctf_list_t *, void *);
+extern void ctf_list_prepend(ctf_list_t *, void *);
+extern void ctf_list_delete(ctf_list_t *, void *);
+
+extern void ctf_dtd_insert(ctf_file_t *, ctf_dtdef_t *);
+extern void ctf_dtd_delete(ctf_file_t *, ctf_dtdef_t *);
+extern ctf_dtdef_t *ctf_dtd_lookup(ctf_file_t *, ctf_id_t);
+
+extern void ctf_decl_init(ctf_decl_t *, char *, size_t);
+extern void ctf_decl_fini(ctf_decl_t *);
+extern void ctf_decl_push(ctf_decl_t *, ctf_file_t *, ctf_id_t);
+extern void ctf_decl_sprintf(ctf_decl_t *, const char *, ...);
+
+extern const char *ctf_strraw(ctf_file_t *, uint_t);
+extern const char *ctf_strptr(ctf_file_t *, uint_t);
+
+extern ctf_file_t *ctf_set_open_errno(int *, int);
+extern long ctf_set_errno(ctf_file_t *, int);
+
+extern const void *ctf_sect_mmap(ctf_sect_t *, int);
+extern void ctf_sect_munmap(const ctf_sect_t *);
+
+extern void *ctf_data_alloc(size_t);
+extern void ctf_data_free(void *, size_t);
+extern void ctf_data_protect(void *, size_t);
+
+extern void *ctf_alloc(size_t);
+extern void ctf_free(void *, size_t);
+
+extern char *ctf_strdup(const char *);
+extern const char *ctf_strerror(int);
+extern void ctf_dprintf(const char *, ...);
+
+extern void *ctf_zopen(int *);
+
+extern const char _CTF_SECTION[]; /* name of CTF ELF section */
+extern const char _CTF_NULLSTR[]; /* empty string */
+
+extern int _libctf_version; /* library client version */
+extern int _libctf_debug; /* debugging messages enabled */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CTF_IMPL_H */
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_labels.c b/cddl/contrib/opensolaris/common/ctf/ctf_labels.c
new file mode 100644
index 000000000000..ddcb1d330202
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_labels.c
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ *
+ * 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 2002-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ctf_impl.h>
+
+static int
+extract_label_info(ctf_file_t *fp, const ctf_lblent_t **ctl, uint_t *num_labels)
+{
+ const ctf_header_t *h;
+
+ /*
+ * Labels are only supported in V2 or later
+ */
+ if (fp->ctf_version < CTF_VERSION_2)
+ return (ctf_set_errno(fp, ECTF_NOTSUP));
+
+ h = (const ctf_header_t *)fp->ctf_data.cts_data;
+
+ /* LINTED - pointer alignment */
+ *ctl = (const ctf_lblent_t *)(fp->ctf_buf + h->cth_lbloff);
+ *num_labels = (h->cth_objtoff - h->cth_lbloff) / sizeof (ctf_lblent_t);
+
+ return (0);
+}
+
+/*
+ * Returns the topmost label, or NULL if any errors are encountered
+ */
+const char *
+ctf_label_topmost(ctf_file_t *fp)
+{
+ const ctf_lblent_t *ctlp;
+ const char *s;
+ uint_t num_labels;
+
+ if (extract_label_info(fp, &ctlp, &num_labels) == CTF_ERR)
+ return (NULL); /* errno is set */
+
+ if (num_labels == 0) {
+ (void) ctf_set_errno(fp, ECTF_NOLABELDATA);
+ return (NULL);
+ }
+
+ if ((s = ctf_strraw(fp, (ctlp + num_labels - 1)->ctl_label)) == NULL)
+ (void) ctf_set_errno(fp, ECTF_CORRUPT);
+
+ return (s);
+}
+
+/*
+ * Iterate over all labels. We pass the label string and the lblinfo_t struct
+ * to the specified callback function.
+ */
+int
+ctf_label_iter(ctf_file_t *fp, ctf_label_f *func, void *arg)
+{
+ const ctf_lblent_t *ctlp;
+ uint_t i, num_labels;
+ ctf_lblinfo_t linfo;
+ const char *lname;
+ int rc;
+
+ if (extract_label_info(fp, &ctlp, &num_labels) == CTF_ERR)
+ return (CTF_ERR); /* errno is set */
+
+ if (num_labels == 0)
+ return (ctf_set_errno(fp, ECTF_NOLABELDATA));
+
+ for (i = 0; i < num_labels; i++, ctlp++) {
+ if ((lname = ctf_strraw(fp, ctlp->ctl_label)) == NULL) {
+ ctf_dprintf("failed to decode label %u with "
+ "typeidx %u\n", ctlp->ctl_label, ctlp->ctl_typeidx);
+ return (ctf_set_errno(fp, ECTF_CORRUPT));
+ }
+
+ linfo.ctb_typeidx = ctlp->ctl_typeidx;
+ if ((rc = func(lname, &linfo, arg)) != 0)
+ return (rc);
+ }
+
+ return (0);
+}
+
+typedef struct linfo_cb_arg {
+ const char *lca_name; /* Label we want to retrieve info for */
+ ctf_lblinfo_t *lca_info; /* Where to store the info about the label */
+} linfo_cb_arg_t;
+
+static int
+label_info_cb(const char *lname, const ctf_lblinfo_t *linfo, void *arg)
+{
+ /*
+ * If lname matches the label we are looking for, copy the
+ * lblinfo_t struct for the caller.
+ */
+ if (strcmp(lname, ((linfo_cb_arg_t *)arg)->lca_name) == 0) {
+ /*
+ * Allow caller not to allocate storage to test if label exists
+ */
+ if (((linfo_cb_arg_t *)arg)->lca_info != NULL)
+ bcopy(linfo, ((linfo_cb_arg_t *)arg)->lca_info,
+ sizeof (ctf_lblinfo_t));
+ return (1); /* Indicate we found a match */
+ }
+
+ return (0);
+}
+
+/*
+ * Retrieve information about the label with name "lname"
+ */
+int
+ctf_label_info(ctf_file_t *fp, const char *lname, ctf_lblinfo_t *linfo)
+{
+ linfo_cb_arg_t cb_arg;
+ int rc;
+
+ cb_arg.lca_name = lname;
+ cb_arg.lca_info = linfo;
+
+ if ((rc = ctf_label_iter(fp, label_info_cb, &cb_arg)) == CTF_ERR)
+ return (rc);
+
+ if (rc != 1)
+ return (ctf_set_errno(fp, ECTF_NOLABEL));
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c b/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c
new file mode 100644
index 000000000000..aa58663309b6
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c
@@ -0,0 +1,315 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sysmacros.h>
+#include <ctf_impl.h>
+
+/*
+ * Compare the given input string and length against a table of known C storage
+ * qualifier keywords. We just ignore these in ctf_lookup_by_name, below. To
+ * do this quickly, we use a pre-computed Perfect Hash Function similar to the
+ * technique originally described in the classic paper:
+ *
+ * R.J. Cichelli, "Minimal Perfect Hash Functions Made Simple",
+ * Communications of the ACM, Volume 23, Issue 1, January 1980, pp. 17-19.
+ *
+ * For an input string S of length N, we use hash H = S[N - 1] + N - 105, which
+ * for the current set of qualifiers yields a unique H in the range [0 .. 20].
+ * The hash can be modified when the keyword set changes as necessary. We also
+ * store the length of each keyword and check it prior to the final strcmp().
+ */
+static int
+isqualifier(const char *s, size_t len)
+{
+ static const struct qual {
+ const char *q_name;
+ size_t q_len;
+ } qhash[] = {
+ { "static", 6 }, { "", 0 }, { "", 0 }, { "", 0 },
+ { "volatile", 8 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 },
+ { "", 0 }, { "auto", 4 }, { "extern", 6 }, { "", 0 }, { "", 0 },
+ { "", 0 }, { "", 0 }, { "const", 5 }, { "register", 8 },
+ { "", 0 }, { "restrict", 8 }, { "_Restrict", 9 }
+ };
+
+ int h = s[len - 1] + (int)len - 105;
+ const struct qual *qp;
+
+ if (h < 0 || h >= sizeof (qhash) / sizeof (qhash[0]))
+ return (0);
+ qp = &qhash[h];
+ return (len == qp->q_len && strncmp(qp->q_name, s, qp->q_len) == 0);
+}
+
+/*
+ * Attempt to convert the given C type name into the corresponding CTF type ID.
+ * It is not possible to do complete and proper conversion of type names
+ * without implementing a more full-fledged parser, which is necessary to
+ * handle things like types that are function pointers to functions that
+ * have arguments that are function pointers, and fun stuff like that.
+ * Instead, this function implements a very simple conversion algorithm that
+ * finds the things that we actually care about: structs, unions, enums,
+ * integers, floats, typedefs, and pointers to any of these named types.
+ */
+ctf_id_t
+ctf_lookup_by_name(ctf_file_t *fp, const char *name)
+{
+ static const char delimiters[] = " \t\n\r\v\f*";
+
+ const ctf_lookup_t *lp;
+ const ctf_helem_t *hp;
+ const char *p, *q, *end;
+ ctf_id_t type = 0;
+ ctf_id_t ntype, ptype;
+
+ if (name == NULL)
+ return (ctf_set_errno(fp, EINVAL));
+
+ for (p = name, end = name + strlen(name); *p != '\0'; p = q) {
+ while (isspace(*p))
+ p++; /* skip leading ws */
+
+ if (p == end)
+ break;
+
+ if ((q = strpbrk(p + 1, delimiters)) == NULL)
+ q = end; /* compare until end */
+
+ if (*p == '*') {
+ /*
+ * Find a pointer to type by looking in fp->ctf_ptrtab.
+ * If we can't find a pointer to the given type, see if
+ * we can compute a pointer to the type resulting from
+ * resolving the type down to its base type and use
+ * that instead. This helps with cases where the CTF
+ * data includes "struct foo *" but not "foo_t *" and
+ * the user tries to access "foo_t *" in the debugger.
+ */
+ ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)];
+ if (ntype == 0) {
+ ntype = ctf_type_resolve(fp, type);
+ if (ntype == CTF_ERR || (ntype = fp->ctf_ptrtab[
+ CTF_TYPE_TO_INDEX(ntype)]) == 0) {
+ (void) ctf_set_errno(fp, ECTF_NOTYPE);
+ goto err;
+ }
+ }
+
+ type = CTF_INDEX_TO_TYPE(ntype,
+ (fp->ctf_flags & LCTF_CHILD));
+
+ q = p + 1;
+ continue;
+ }
+
+ if (isqualifier(p, (size_t)(q - p)))
+ continue; /* skip qualifier keyword */
+
+ for (lp = fp->ctf_lookups; lp->ctl_prefix != NULL; lp++) {
+ if (lp->ctl_prefix[0] == '\0' ||
+ strncmp(p, lp->ctl_prefix, (size_t)(q - p)) == 0) {
+ for (p += lp->ctl_len; isspace(*p); p++)
+ continue; /* skip prefix and next ws */
+
+ if ((q = strchr(p, '*')) == NULL)
+ q = end; /* compare until end */
+
+ while (isspace(q[-1]))
+ q--; /* exclude trailing ws */
+
+ if ((hp = ctf_hash_lookup(lp->ctl_hash, fp, p,
+ (size_t)(q - p))) == NULL) {
+ (void) ctf_set_errno(fp, ECTF_NOTYPE);
+ goto err;
+ }
+
+ type = hp->h_type;
+ break;
+ }
+ }
+
+ if (lp->ctl_prefix == NULL) {
+ (void) ctf_set_errno(fp, ECTF_NOTYPE);
+ goto err;
+ }
+ }
+
+ if (*p != '\0' || type == 0)
+ return (ctf_set_errno(fp, ECTF_SYNTAX));
+
+ return (type);
+
+err:
+ if (fp->ctf_parent != NULL &&
+ (ptype = ctf_lookup_by_name(fp->ctf_parent, name)) != CTF_ERR)
+ return (ptype);
+
+ return (CTF_ERR);
+}
+
+/*
+ * Given a symbol table index, return the type of the data object described
+ * by the corresponding entry in the symbol table.
+ */
+ctf_id_t
+ctf_lookup_by_symbol(ctf_file_t *fp, ulong_t symidx)
+{
+ const ctf_sect_t *sp = &fp->ctf_symtab;
+ ctf_id_t type;
+
+ if (sp->cts_data == NULL)
+ return (ctf_set_errno(fp, ECTF_NOSYMTAB));
+
+ if (symidx >= fp->ctf_nsyms)
+ return (ctf_set_errno(fp, EINVAL));
+
+ if (sp->cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)sp->cts_data + symidx;
+ if (ELF32_ST_TYPE(symp->st_info) != STT_OBJECT)
+ return (ctf_set_errno(fp, ECTF_NOTDATA));
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)sp->cts_data + symidx;
+ if (ELF64_ST_TYPE(symp->st_info) != STT_OBJECT)
+ return (ctf_set_errno(fp, ECTF_NOTDATA));
+ }
+
+ if (fp->ctf_sxlate[symidx] == -1u)
+ return (ctf_set_errno(fp, ECTF_NOTYPEDAT));
+
+ type = *(ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]);
+ if (type == 0)
+ return (ctf_set_errno(fp, ECTF_NOTYPEDAT));
+
+ return (type);
+}
+
+/*
+ * Return the pointer to the internal CTF type data corresponding to the
+ * given type ID. If the ID is invalid, the function returns NULL.
+ * This function is not exported outside of the library.
+ */
+const ctf_type_t *
+ctf_lookup_by_id(ctf_file_t **fpp, ctf_id_t type)
+{
+ ctf_file_t *fp = *fpp; /* caller passes in starting CTF container */
+
+ if ((fp->ctf_flags & LCTF_CHILD) && CTF_TYPE_ISPARENT(type) &&
+ (fp = fp->ctf_parent) == NULL) {
+ (void) ctf_set_errno(*fpp, ECTF_NOPARENT);
+ return (NULL);
+ }
+
+ type = CTF_TYPE_TO_INDEX(type);
+ if (type > 0 && type <= fp->ctf_typemax) {
+ *fpp = fp; /* function returns ending CTF container */
+ return (LCTF_INDEX_TO_TYPEPTR(fp, type));
+ }
+
+ (void) ctf_set_errno(fp, ECTF_BADID);
+ return (NULL);
+}
+
+/*
+ * Given a symbol table index, return the info for the function described
+ * by the corresponding entry in the symbol table.
+ */
+int
+ctf_func_info(ctf_file_t *fp, ulong_t symidx, ctf_funcinfo_t *fip)
+{
+ const ctf_sect_t *sp = &fp->ctf_symtab;
+ const ushort_t *dp;
+ ushort_t info, kind, n;
+
+ if (sp->cts_data == NULL)
+ return (ctf_set_errno(fp, ECTF_NOSYMTAB));
+
+ if (symidx >= fp->ctf_nsyms)
+ return (ctf_set_errno(fp, EINVAL));
+
+ if (sp->cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)sp->cts_data + symidx;
+ if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC)
+ return (ctf_set_errno(fp, ECTF_NOTFUNC));
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)sp->cts_data + symidx;
+ if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC)
+ return (ctf_set_errno(fp, ECTF_NOTFUNC));
+ }
+
+ if (fp->ctf_sxlate[symidx] == -1u)
+ return (ctf_set_errno(fp, ECTF_NOFUNCDAT));
+
+ dp = (ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]);
+
+ info = *dp++;
+ kind = LCTF_INFO_KIND(fp, info);
+ n = LCTF_INFO_VLEN(fp, info);
+
+ if (kind == CTF_K_UNKNOWN && n == 0)
+ return (ctf_set_errno(fp, ECTF_NOFUNCDAT));
+
+ if (kind != CTF_K_FUNCTION)
+ return (ctf_set_errno(fp, ECTF_CORRUPT));
+
+ fip->ctc_return = *dp++;
+ fip->ctc_argc = n;
+ fip->ctc_flags = 0;
+
+ if (n != 0 && dp[n - 1] == 0) {
+ fip->ctc_flags |= CTF_FUNC_VARARG;
+ fip->ctc_argc--;
+ }
+
+ return (0);
+}
+
+/*
+ * Given a symbol table index, return the arguments for the function described
+ * by the corresponding entry in the symbol table.
+ */
+int
+ctf_func_args(ctf_file_t *fp, ulong_t symidx, uint_t argc, ctf_id_t *argv)
+{
+ const ushort_t *dp;
+ ctf_funcinfo_t f;
+
+ if (ctf_func_info(fp, symidx, &f) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ /*
+ * The argument data is two ushort_t's past the translation table
+ * offset: one for the function info, and one for the return type.
+ */
+ dp = (ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]) + 2;
+
+ for (argc = MIN(argc, f.ctc_argc); argc != 0; argc--)
+ *argv++ = *dp++;
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_open.c b/cddl/contrib/opensolaris/common/ctf/ctf_open.c
new file mode 100644
index 000000000000..001cf5c59104
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_open.c
@@ -0,0 +1,1045 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <ctf_impl.h>
+#include <sys/mman.h>
+#include <sys/zmod.h>
+
+static const ctf_dmodel_t _libctf_models[] = {
+ { "ILP32", CTF_MODEL_ILP32, 4, 1, 2, 4, 4 },
+ { "LP64", CTF_MODEL_LP64, 8, 1, 2, 4, 8 },
+ { NULL, 0, 0, 0, 0, 0, 0 }
+};
+
+const char _CTF_SECTION[] = ".SUNW_ctf";
+const char _CTF_NULLSTR[] = "";
+
+int _libctf_version = CTF_VERSION; /* library client version */
+int _libctf_debug = 0; /* debugging messages enabled */
+
+static ushort_t
+get_kind_v1(ushort_t info)
+{
+ return (CTF_INFO_KIND_V1(info));
+}
+
+static ushort_t
+get_kind_v2(ushort_t info)
+{
+ return (CTF_INFO_KIND(info));
+}
+
+static ushort_t
+get_root_v1(ushort_t info)
+{
+ return (CTF_INFO_ISROOT_V1(info));
+}
+
+static ushort_t
+get_root_v2(ushort_t info)
+{
+ return (CTF_INFO_ISROOT(info));
+}
+
+static ushort_t
+get_vlen_v1(ushort_t info)
+{
+ return (CTF_INFO_VLEN_V1(info));
+}
+
+static ushort_t
+get_vlen_v2(ushort_t info)
+{
+ return (CTF_INFO_VLEN(info));
+}
+
+static const ctf_fileops_t ctf_fileops[] = {
+ { NULL, NULL },
+ { get_kind_v1, get_root_v1, get_vlen_v1 },
+ { get_kind_v2, get_root_v2, get_vlen_v2 },
+};
+
+/*
+ * Convert a 32-bit ELF symbol into GElf (Elf64) and return a pointer to it.
+ */
+static Elf64_Sym *
+sym_to_gelf(const Elf32_Sym *src, Elf64_Sym *dst)
+{
+ dst->st_name = src->st_name;
+ dst->st_value = src->st_value;
+ dst->st_size = src->st_size;
+ dst->st_info = src->st_info;
+ dst->st_other = src->st_other;
+ dst->st_shndx = src->st_shndx;
+
+ return (dst);
+}
+
+/*
+ * Initialize the symtab translation table by filling each entry with the
+ * offset of the CTF type or function data corresponding to each STT_FUNC or
+ * STT_OBJECT entry in the symbol table.
+ */
+static int
+init_symtab(ctf_file_t *fp, const ctf_header_t *hp,
+ const ctf_sect_t *sp, const ctf_sect_t *strp)
+{
+ const uchar_t *symp = sp->cts_data;
+ uint_t *xp = fp->ctf_sxlate;
+ uint_t *xend = xp + fp->ctf_nsyms;
+
+ uint_t objtoff = hp->cth_objtoff;
+ uint_t funcoff = hp->cth_funcoff;
+
+ ushort_t info, vlen;
+ Elf64_Sym sym, *gsp;
+ const char *name;
+
+ /*
+ * The CTF data object and function type sections are ordered to match
+ * the relative order of the respective symbol types in the symtab.
+ * If no type information is available for a symbol table entry, a
+ * pad is inserted in the CTF section. As a further optimization,
+ * anonymous or undefined symbols are omitted from the CTF data.
+ */
+ for (; xp < xend; xp++, symp += sp->cts_entsize) {
+ if (sp->cts_entsize == sizeof (Elf32_Sym))
+ gsp = sym_to_gelf((Elf32_Sym *)(uintptr_t)symp, &sym);
+ else
+ gsp = (Elf64_Sym *)(uintptr_t)symp;
+
+ if (gsp->st_name < strp->cts_size)
+ name = (const char *)strp->cts_data + gsp->st_name;
+ else
+ name = _CTF_NULLSTR;
+
+ if (gsp->st_name == 0 || gsp->st_shndx == SHN_UNDEF ||
+ strcmp(name, "_START_") == 0 ||
+ strcmp(name, "_END_") == 0) {
+ *xp = -1u;
+ continue;
+ }
+
+ switch (ELF64_ST_TYPE(gsp->st_info)) {
+ case STT_OBJECT:
+ if (objtoff >= hp->cth_funcoff ||
+ (gsp->st_shndx == SHN_ABS && gsp->st_value == 0)) {
+ *xp = -1u;
+ break;
+ }
+
+ *xp = objtoff;
+ objtoff += sizeof (ushort_t);
+ break;
+
+ case STT_FUNC:
+ if (funcoff >= hp->cth_typeoff) {
+ *xp = -1u;
+ break;
+ }
+
+ *xp = funcoff;
+
+ info = *(ushort_t *)((uintptr_t)fp->ctf_buf + funcoff);
+ vlen = LCTF_INFO_VLEN(fp, info);
+
+ /*
+ * If we encounter a zero pad at the end, just skip it.
+ * Otherwise skip over the function and its return type
+ * (+2) and the argument list (vlen).
+ */
+ if (LCTF_INFO_KIND(fp, info) == CTF_K_UNKNOWN &&
+ vlen == 0)
+ funcoff += sizeof (ushort_t); /* skip pad */
+ else
+ funcoff += sizeof (ushort_t) * (vlen + 2);
+ break;
+
+ default:
+ *xp = -1u;
+ break;
+ }
+ }
+
+ ctf_dprintf("loaded %lu symtab entries\n", fp->ctf_nsyms);
+ return (0);
+}
+
+/*
+ * Initialize the type ID translation table with the byte offset of each type,
+ * and initialize the hash tables of each named type.
+ */
+static int
+init_types(ctf_file_t *fp, const ctf_header_t *cth)
+{
+ /* LINTED - pointer alignment */
+ const ctf_type_t *tbuf = (ctf_type_t *)(fp->ctf_buf + cth->cth_typeoff);
+ /* LINTED - pointer alignment */
+ const ctf_type_t *tend = (ctf_type_t *)(fp->ctf_buf + cth->cth_stroff);
+
+ ulong_t pop[CTF_K_MAX + 1] = { 0 };
+ const ctf_type_t *tp;
+ ctf_hash_t *hp;
+ ushort_t id, dst;
+ uint_t *xp;
+
+ /*
+ * We initially determine whether the container is a child or a parent
+ * based on the value of cth_parname. To support containers that pre-
+ * date cth_parname, we also scan the types themselves for references
+ * to values in the range reserved for child types in our first pass.
+ */
+ int child = cth->cth_parname != 0;
+ int nlstructs = 0, nlunions = 0;
+ int err;
+
+ /*
+ * We make two passes through the entire type section. In this first
+ * pass, we count the number of each type and the total number of types.
+ */
+ for (tp = tbuf; tp < tend; fp->ctf_typemax++) {
+ ushort_t kind = LCTF_INFO_KIND(fp, tp->ctt_info);
+ ulong_t vlen = LCTF_INFO_VLEN(fp, tp->ctt_info);
+ ssize_t size, increment;
+
+ size_t vbytes;
+ uint_t n;
+
+ (void) ctf_get_ctt_size(fp, tp, &size, &increment);
+
+ switch (kind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ vbytes = sizeof (uint_t);
+ break;
+ case CTF_K_ARRAY:
+ vbytes = sizeof (ctf_array_t);
+ break;
+ case CTF_K_FUNCTION:
+ vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
+ break;
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ if (fp->ctf_version == CTF_VERSION_1 ||
+ size < CTF_LSTRUCT_THRESH) {
+ ctf_member_t *mp = (ctf_member_t *)
+ ((uintptr_t)tp + increment);
+
+ vbytes = sizeof (ctf_member_t) * vlen;
+ for (n = vlen; n != 0; n--, mp++)
+ child |= CTF_TYPE_ISCHILD(mp->ctm_type);
+ } else {
+ ctf_lmember_t *lmp = (ctf_lmember_t *)
+ ((uintptr_t)tp + increment);
+
+ vbytes = sizeof (ctf_lmember_t) * vlen;
+ for (n = vlen; n != 0; n--, lmp++)
+ child |=
+ CTF_TYPE_ISCHILD(lmp->ctlm_type);
+ }
+ break;
+ case CTF_K_ENUM:
+ vbytes = sizeof (ctf_enum_t) * vlen;
+ break;
+ case CTF_K_FORWARD:
+ /*
+ * For forward declarations, ctt_type is the CTF_K_*
+ * kind for the tag, so bump that population count too.
+ * If ctt_type is unknown, treat the tag as a struct.
+ */
+ if (tp->ctt_type == CTF_K_UNKNOWN ||
+ tp->ctt_type >= CTF_K_MAX)
+ pop[CTF_K_STRUCT]++;
+ else
+ pop[tp->ctt_type]++;
+ /*FALLTHRU*/
+ case CTF_K_UNKNOWN:
+ vbytes = 0;
+ break;
+ case CTF_K_POINTER:
+ case CTF_K_TYPEDEF:
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ child |= CTF_TYPE_ISCHILD(tp->ctt_type);
+ vbytes = 0;
+ break;
+ default:
+ ctf_dprintf("detected invalid CTF kind -- %u\n", kind);
+ return (ECTF_CORRUPT);
+ }
+ tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
+ pop[kind]++;
+ }
+
+ /*
+ * If we detected a reference to a child type ID, then we know this
+ * container is a child and may have a parent's types imported later.
+ */
+ if (child) {
+ ctf_dprintf("CTF container %p is a child\n", (void *)fp);
+ fp->ctf_flags |= LCTF_CHILD;
+ } else
+ ctf_dprintf("CTF container %p is a parent\n", (void *)fp);
+
+ /*
+ * Now that we've counted up the number of each type, we can allocate
+ * the hash tables, type translation table, and pointer table.
+ */
+ if ((err = ctf_hash_create(&fp->ctf_structs, pop[CTF_K_STRUCT])) != 0)
+ return (err);
+
+ if ((err = ctf_hash_create(&fp->ctf_unions, pop[CTF_K_UNION])) != 0)
+ return (err);
+
+ if ((err = ctf_hash_create(&fp->ctf_enums, pop[CTF_K_ENUM])) != 0)
+ return (err);
+
+ if ((err = ctf_hash_create(&fp->ctf_names,
+ pop[CTF_K_INTEGER] + pop[CTF_K_FLOAT] + pop[CTF_K_FUNCTION] +
+ pop[CTF_K_TYPEDEF] + pop[CTF_K_POINTER] + pop[CTF_K_VOLATILE] +
+ pop[CTF_K_CONST] + pop[CTF_K_RESTRICT])) != 0)
+ return (err);
+
+ fp->ctf_txlate = ctf_alloc(sizeof (uint_t) * (fp->ctf_typemax + 1));
+ fp->ctf_ptrtab = ctf_alloc(sizeof (ushort_t) * (fp->ctf_typemax + 1));
+
+ if (fp->ctf_txlate == NULL || fp->ctf_ptrtab == NULL)
+ return (EAGAIN); /* memory allocation failed */
+
+ xp = fp->ctf_txlate;
+ *xp++ = 0; /* type id 0 is used as a sentinel value */
+
+ bzero(fp->ctf_txlate, sizeof (uint_t) * (fp->ctf_typemax + 1));
+ bzero(fp->ctf_ptrtab, sizeof (ushort_t) * (fp->ctf_typemax + 1));
+
+ /*
+ * In the second pass through the types, we fill in each entry of the
+ * type and pointer tables and add names to the appropriate hashes.
+ */
+ for (id = 1, tp = tbuf; tp < tend; xp++, id++) {
+ ushort_t kind = LCTF_INFO_KIND(fp, tp->ctt_info);
+ ulong_t vlen = LCTF_INFO_VLEN(fp, tp->ctt_info);
+ ssize_t size, increment;
+
+ const char *name;
+ size_t vbytes;
+ ctf_helem_t *hep;
+ ctf_encoding_t cte;
+
+ (void) ctf_get_ctt_size(fp, tp, &size, &increment);
+ name = ctf_strptr(fp, tp->ctt_name);
+
+ switch (kind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ /*
+ * Only insert a new integer base type definition if
+ * this type name has not been defined yet. We re-use
+ * the names with different encodings for bit-fields.
+ */
+ if ((hep = ctf_hash_lookup(&fp->ctf_names, fp,
+ name, strlen(name))) == NULL) {
+ err = ctf_hash_insert(&fp->ctf_names, fp,
+ CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);
+ if (err != 0 && err != ECTF_STRTAB)
+ return (err);
+ } else if (ctf_type_encoding(fp, hep->h_type,
+ &cte) == 0 && cte.cte_bits == 0) {
+ /*
+ * Work-around SOS8 stabs bug: replace existing
+ * intrinsic w/ same name if it was zero bits.
+ */
+ hep->h_type = CTF_INDEX_TO_TYPE(id, child);
+ }
+ vbytes = sizeof (uint_t);
+ break;
+
+ case CTF_K_ARRAY:
+ vbytes = sizeof (ctf_array_t);
+ break;
+
+ case CTF_K_FUNCTION:
+ err = ctf_hash_insert(&fp->ctf_names, fp,
+ CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);
+ if (err != 0 && err != ECTF_STRTAB)
+ return (err);
+ vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
+ break;
+
+ case CTF_K_STRUCT:
+ err = ctf_hash_define(&fp->ctf_structs, fp,
+ CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);
+
+ if (err != 0 && err != ECTF_STRTAB)
+ return (err);
+
+ if (fp->ctf_version == CTF_VERSION_1 ||
+ size < CTF_LSTRUCT_THRESH)
+ vbytes = sizeof (ctf_member_t) * vlen;
+ else {
+ vbytes = sizeof (ctf_lmember_t) * vlen;
+ nlstructs++;
+ }
+ break;
+
+ case CTF_K_UNION:
+ err = ctf_hash_define(&fp->ctf_unions, fp,
+ CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);
+
+ if (err != 0 && err != ECTF_STRTAB)
+ return (err);
+
+ if (fp->ctf_version == CTF_VERSION_1 ||
+ size < CTF_LSTRUCT_THRESH)
+ vbytes = sizeof (ctf_member_t) * vlen;
+ else {
+ vbytes = sizeof (ctf_lmember_t) * vlen;
+ nlunions++;
+ }
+ break;
+
+ case CTF_K_ENUM:
+ err = ctf_hash_define(&fp->ctf_enums, fp,
+ CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);
+
+ if (err != 0 && err != ECTF_STRTAB)
+ return (err);
+
+ vbytes = sizeof (ctf_enum_t) * vlen;
+ break;
+
+ case CTF_K_TYPEDEF:
+ err = ctf_hash_insert(&fp->ctf_names, fp,
+ CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);
+ if (err != 0 && err != ECTF_STRTAB)
+ return (err);
+ vbytes = 0;
+ break;
+
+ case CTF_K_FORWARD:
+ /*
+ * Only insert forward tags into the given hash if the
+ * type or tag name is not already present.
+ */
+ switch (tp->ctt_type) {
+ case CTF_K_STRUCT:
+ hp = &fp->ctf_structs;
+ break;
+ case CTF_K_UNION:
+ hp = &fp->ctf_unions;
+ break;
+ case CTF_K_ENUM:
+ hp = &fp->ctf_enums;
+ break;
+ default:
+ hp = &fp->ctf_structs;
+ }
+
+ if (ctf_hash_lookup(hp, fp,
+ name, strlen(name)) == NULL) {
+ err = ctf_hash_insert(hp, fp,
+ CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);
+ if (err != 0 && err != ECTF_STRTAB)
+ return (err);
+ }
+ vbytes = 0;
+ break;
+
+ case CTF_K_POINTER:
+ /*
+ * If the type referenced by the pointer is in this CTF
+ * container, then store the index of the pointer type
+ * in fp->ctf_ptrtab[ index of referenced type ].
+ */
+ if (CTF_TYPE_ISCHILD(tp->ctt_type) == child &&
+ CTF_TYPE_TO_INDEX(tp->ctt_type) <= fp->ctf_typemax)
+ fp->ctf_ptrtab[
+ CTF_TYPE_TO_INDEX(tp->ctt_type)] = id;
+ /*FALLTHRU*/
+
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ err = ctf_hash_insert(&fp->ctf_names, fp,
+ CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);
+ if (err != 0 && err != ECTF_STRTAB)
+ return (err);
+ /*FALLTHRU*/
+
+ default:
+ vbytes = 0;
+ break;
+ }
+
+ *xp = (uint_t)((uintptr_t)tp - (uintptr_t)fp->ctf_buf);
+ tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
+ }
+
+ ctf_dprintf("%lu total types processed\n", fp->ctf_typemax);
+ ctf_dprintf("%u enum names hashed\n", ctf_hash_size(&fp->ctf_enums));
+ ctf_dprintf("%u struct names hashed (%d long)\n",
+ ctf_hash_size(&fp->ctf_structs), nlstructs);
+ ctf_dprintf("%u union names hashed (%d long)\n",
+ ctf_hash_size(&fp->ctf_unions), nlunions);
+ ctf_dprintf("%u base type names hashed\n",
+ ctf_hash_size(&fp->ctf_names));
+
+ /*
+ * Make an additional pass through the pointer table to find pointers
+ * that point to anonymous typedef nodes. If we find one, modify the
+ * pointer table so that the pointer is also known to point to the
+ * node that is referenced by the anonymous typedef node.
+ */
+ for (id = 1; id <= fp->ctf_typemax; id++) {
+ if ((dst = fp->ctf_ptrtab[id]) != 0) {
+ tp = LCTF_INDEX_TO_TYPEPTR(fp, id);
+
+ if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_TYPEDEF &&
+ strcmp(ctf_strptr(fp, tp->ctt_name), "") == 0 &&
+ CTF_TYPE_ISCHILD(tp->ctt_type) == child &&
+ CTF_TYPE_TO_INDEX(tp->ctt_type) <= fp->ctf_typemax)
+ fp->ctf_ptrtab[
+ CTF_TYPE_TO_INDEX(tp->ctt_type)] = dst;
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Decode the specified CTF buffer and optional symbol table and create a new
+ * CTF container representing the symbolic debugging information. This code
+ * can be used directly by the debugger, or it can be used as the engine for
+ * ctf_fdopen() or ctf_open(), below.
+ */
+ctf_file_t *
+ctf_bufopen(const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
+ const ctf_sect_t *strsect, int *errp)
+{
+ const ctf_preamble_t *pp;
+ ctf_header_t hp;
+ ctf_file_t *fp;
+ void *buf, *base;
+ size_t size, hdrsz;
+ int err;
+
+ if (ctfsect == NULL || ((symsect == NULL) != (strsect == NULL)))
+ return (ctf_set_open_errno(errp, EINVAL));
+
+ if (symsect != NULL && symsect->cts_entsize != sizeof (Elf32_Sym) &&
+ symsect->cts_entsize != sizeof (Elf64_Sym))
+ return (ctf_set_open_errno(errp, ECTF_SYMTAB));
+
+ if (symsect != NULL && symsect->cts_data == NULL)
+ return (ctf_set_open_errno(errp, ECTF_SYMBAD));
+
+ if (strsect != NULL && strsect->cts_data == NULL)
+ return (ctf_set_open_errno(errp, ECTF_STRBAD));
+
+ if (ctfsect->cts_size < sizeof (ctf_preamble_t))
+ return (ctf_set_open_errno(errp, ECTF_NOCTFBUF));
+
+ pp = (const ctf_preamble_t *)ctfsect->cts_data;
+
+ ctf_dprintf("ctf_bufopen: magic=0x%x version=%u\n",
+ pp->ctp_magic, pp->ctp_version);
+
+ /*
+ * Validate each part of the CTF header (either V1 or V2).
+ * First, we validate the preamble (common to all versions). At that
+ * point, we know specific header version, and can validate the
+ * version-specific parts including section offsets and alignments.
+ */
+ if (pp->ctp_magic != CTF_MAGIC)
+ return (ctf_set_open_errno(errp, ECTF_NOCTFBUF));
+
+ if (pp->ctp_version == CTF_VERSION_2) {
+ if (ctfsect->cts_size < sizeof (ctf_header_t))
+ return (ctf_set_open_errno(errp, ECTF_NOCTFBUF));
+
+ bcopy(ctfsect->cts_data, &hp, sizeof (hp));
+ hdrsz = sizeof (ctf_header_t);
+
+ } else if (pp->ctp_version == CTF_VERSION_1) {
+ const ctf_header_v1_t *h1p =
+ (const ctf_header_v1_t *)ctfsect->cts_data;
+
+ if (ctfsect->cts_size < sizeof (ctf_header_v1_t))
+ return (ctf_set_open_errno(errp, ECTF_NOCTFBUF));
+
+ bzero(&hp, sizeof (hp));
+ hp.cth_preamble = h1p->cth_preamble;
+ hp.cth_objtoff = h1p->cth_objtoff;
+ hp.cth_funcoff = h1p->cth_funcoff;
+ hp.cth_typeoff = h1p->cth_typeoff;
+ hp.cth_stroff = h1p->cth_stroff;
+ hp.cth_strlen = h1p->cth_strlen;
+
+ hdrsz = sizeof (ctf_header_v1_t);
+ } else
+ return (ctf_set_open_errno(errp, ECTF_CTFVERS));
+
+ size = hp.cth_stroff + hp.cth_strlen;
+
+ ctf_dprintf("ctf_bufopen: uncompressed size=%lu\n", (ulong_t)size);
+
+ if (hp.cth_lbloff > size || hp.cth_objtoff > size ||
+ hp.cth_funcoff > size || hp.cth_typeoff > size ||
+ hp.cth_stroff > size)
+ return (ctf_set_open_errno(errp, ECTF_CORRUPT));
+
+ if (hp.cth_lbloff > hp.cth_objtoff ||
+ hp.cth_objtoff > hp.cth_funcoff ||
+ hp.cth_funcoff > hp.cth_typeoff ||
+ hp.cth_typeoff > hp.cth_stroff)
+ return (ctf_set_open_errno(errp, ECTF_CORRUPT));
+
+ if ((hp.cth_lbloff & 3) || (hp.cth_objtoff & 1) ||
+ (hp.cth_funcoff & 1) || (hp.cth_typeoff & 3))
+ return (ctf_set_open_errno(errp, ECTF_CORRUPT));
+
+ /*
+ * Once everything is determined to be valid, attempt to decompress
+ * the CTF data buffer if it is compressed. Otherwise we just put
+ * the data section's buffer pointer into ctf_buf, below.
+ */
+ if (hp.cth_flags & CTF_F_COMPRESS) {
+ size_t srclen, dstlen;
+ const void *src;
+ int rc = Z_OK;
+
+ if (ctf_zopen(errp) == NULL)
+ return (NULL); /* errp is set for us */
+
+ if ((base = ctf_data_alloc(size + hdrsz)) == MAP_FAILED)
+ return (ctf_set_open_errno(errp, ECTF_ZALLOC));
+
+ bcopy(ctfsect->cts_data, base, hdrsz);
+ ((ctf_preamble_t *)base)->ctp_flags &= ~CTF_F_COMPRESS;
+ buf = (uchar_t *)base + hdrsz;
+
+ src = (uchar_t *)ctfsect->cts_data + hdrsz;
+ srclen = ctfsect->cts_size - hdrsz;
+ dstlen = size;
+
+ if ((rc = z_uncompress(buf, &dstlen, src, srclen)) != Z_OK) {
+ ctf_dprintf("zlib inflate err: %s\n", z_strerror(rc));
+ ctf_data_free(base, size + hdrsz);
+ return (ctf_set_open_errno(errp, ECTF_DECOMPRESS));
+ }
+
+ if (dstlen != size) {
+ ctf_dprintf("zlib inflate short -- got %lu of %lu "
+ "bytes\n", (ulong_t)dstlen, (ulong_t)size);
+ ctf_data_free(base, size + hdrsz);
+ return (ctf_set_open_errno(errp, ECTF_CORRUPT));
+ }
+
+ ctf_data_protect(base, size + hdrsz);
+
+ } else {
+ base = (void *)ctfsect->cts_data;
+ buf = (uchar_t *)base + hdrsz;
+ }
+
+ /*
+ * Once we have uncompressed and validated the CTF data buffer, we can
+ * proceed with allocating a ctf_file_t and initializing it.
+ */
+ if ((fp = ctf_alloc(sizeof (ctf_file_t))) == NULL)
+ return (ctf_set_open_errno(errp, EAGAIN));
+
+ bzero(fp, sizeof (ctf_file_t));
+ fp->ctf_version = hp.cth_version;
+ fp->ctf_fileops = &ctf_fileops[hp.cth_version];
+ bcopy(ctfsect, &fp->ctf_data, sizeof (ctf_sect_t));
+
+ if (symsect != NULL) {
+ bcopy(symsect, &fp->ctf_symtab, sizeof (ctf_sect_t));
+ bcopy(strsect, &fp->ctf_strtab, sizeof (ctf_sect_t));
+ }
+
+ if (fp->ctf_data.cts_name != NULL)
+ fp->ctf_data.cts_name = ctf_strdup(fp->ctf_data.cts_name);
+ if (fp->ctf_symtab.cts_name != NULL)
+ fp->ctf_symtab.cts_name = ctf_strdup(fp->ctf_symtab.cts_name);
+ if (fp->ctf_strtab.cts_name != NULL)
+ fp->ctf_strtab.cts_name = ctf_strdup(fp->ctf_strtab.cts_name);
+
+ if (fp->ctf_data.cts_name == NULL)
+ fp->ctf_data.cts_name = _CTF_NULLSTR;
+ if (fp->ctf_symtab.cts_name == NULL)
+ fp->ctf_symtab.cts_name = _CTF_NULLSTR;
+ if (fp->ctf_strtab.cts_name == NULL)
+ fp->ctf_strtab.cts_name = _CTF_NULLSTR;
+
+ fp->ctf_str[CTF_STRTAB_0].cts_strs = (const char *)buf + hp.cth_stroff;
+ fp->ctf_str[CTF_STRTAB_0].cts_len = hp.cth_strlen;
+
+ if (strsect != NULL) {
+ fp->ctf_str[CTF_STRTAB_1].cts_strs = strsect->cts_data;
+ fp->ctf_str[CTF_STRTAB_1].cts_len = strsect->cts_size;
+ }
+
+ fp->ctf_base = base;
+ fp->ctf_buf = buf;
+ fp->ctf_size = size + hdrsz;
+
+ /*
+ * If we have a parent container name and label, store the relocated
+ * string pointers in the CTF container for easy access later.
+ */
+ if (hp.cth_parlabel != 0)
+ fp->ctf_parlabel = ctf_strptr(fp, hp.cth_parlabel);
+ if (hp.cth_parname != 0)
+ fp->ctf_parname = ctf_strptr(fp, hp.cth_parname);
+
+ ctf_dprintf("ctf_bufopen: parent name %s (label %s)\n",
+ fp->ctf_parname ? fp->ctf_parname : "<NULL>",
+ fp->ctf_parlabel ? fp->ctf_parlabel : "<NULL>");
+
+ /*
+ * If we have a symbol table section, allocate and initialize
+ * the symtab translation table, pointed to by ctf_sxlate.
+ */
+ if (symsect != NULL) {
+ fp->ctf_nsyms = symsect->cts_size / symsect->cts_entsize;
+ fp->ctf_sxlate = ctf_alloc(fp->ctf_nsyms * sizeof (uint_t));
+
+ if (fp->ctf_sxlate == NULL) {
+ (void) ctf_set_open_errno(errp, EAGAIN);
+ goto bad;
+ }
+
+ if ((err = init_symtab(fp, &hp, symsect, strsect)) != 0) {
+ (void) ctf_set_open_errno(errp, err);
+ goto bad;
+ }
+ }
+
+ if ((err = init_types(fp, &hp)) != 0) {
+ (void) ctf_set_open_errno(errp, err);
+ goto bad;
+ }
+
+ /*
+ * Initialize the ctf_lookup_by_name top-level dictionary. We keep an
+ * array of type name prefixes and the corresponding ctf_hash to use.
+ * NOTE: This code must be kept in sync with the code in ctf_update().
+ */
+ fp->ctf_lookups[0].ctl_prefix = "struct";
+ fp->ctf_lookups[0].ctl_len = strlen(fp->ctf_lookups[0].ctl_prefix);
+ fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs;
+ fp->ctf_lookups[1].ctl_prefix = "union";
+ fp->ctf_lookups[1].ctl_len = strlen(fp->ctf_lookups[1].ctl_prefix);
+ fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions;
+ fp->ctf_lookups[2].ctl_prefix = "enum";
+ fp->ctf_lookups[2].ctl_len = strlen(fp->ctf_lookups[2].ctl_prefix);
+ fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums;
+ fp->ctf_lookups[3].ctl_prefix = _CTF_NULLSTR;
+ fp->ctf_lookups[3].ctl_len = strlen(fp->ctf_lookups[3].ctl_prefix);
+ fp->ctf_lookups[3].ctl_hash = &fp->ctf_names;
+ fp->ctf_lookups[4].ctl_prefix = NULL;
+ fp->ctf_lookups[4].ctl_len = 0;
+ fp->ctf_lookups[4].ctl_hash = NULL;
+
+ if (symsect != NULL) {
+ if (symsect->cts_entsize == sizeof (Elf64_Sym))
+ (void) ctf_setmodel(fp, CTF_MODEL_LP64);
+ else
+ (void) ctf_setmodel(fp, CTF_MODEL_ILP32);
+ } else
+ (void) ctf_setmodel(fp, CTF_MODEL_NATIVE);
+
+ fp->ctf_refcnt = 1;
+ return (fp);
+
+bad:
+ ctf_close(fp);
+ return (NULL);
+}
+
+/*
+ * Dupliate a ctf_file_t and its underlying section information into a new
+ * container. This works by copying the three ctf_sect_t's of the original
+ * container if they exist and passing those into ctf_bufopen. To copy those, we
+ * mmap anonymous memory with ctf_data_alloc and bcopy the data across. It's not
+ * the cheapest thing, but it's what we've got.
+ */
+ctf_file_t *
+ctf_dup(ctf_file_t *ofp)
+{
+ ctf_file_t *fp;
+ ctf_sect_t ctfsect, symsect, strsect;
+ ctf_sect_t *ctp, *symp, *strp;
+ void *cbuf, *symbuf, *strbuf;
+ int err;
+
+ cbuf = symbuf = strbuf = NULL;
+ /*
+ * The ctfsect isn't allowed to not exist, but the symbol and string
+ * section might not. We only need to copy the data of the section, not
+ * the name, as ctf_bufopen will take care of that.
+ */
+ bcopy(&ofp->ctf_data, &ctfsect, sizeof (ctf_sect_t));
+ cbuf = ctf_data_alloc(ctfsect.cts_size);
+ if (cbuf == NULL) {
+ (void) ctf_set_errno(ofp, ECTF_MMAP);
+ return (NULL);
+ }
+
+ bcopy(ctfsect.cts_data, cbuf, ctfsect.cts_size);
+ ctf_data_protect(cbuf, ctfsect.cts_size);
+ ctfsect.cts_data = cbuf;
+ ctfsect.cts_offset = 0;
+ ctp = &ctfsect;
+
+ if (ofp->ctf_symtab.cts_data != NULL) {
+ bcopy(&ofp->ctf_symtab, &symsect, sizeof (ctf_sect_t));
+ symbuf = ctf_data_alloc(symsect.cts_size);
+ if (symbuf == NULL) {
+ (void) ctf_set_errno(ofp, ECTF_MMAP);
+ goto err;
+ }
+ bcopy(symsect.cts_data, symbuf, symsect.cts_size);
+ ctf_data_protect(symbuf, symsect.cts_size);
+ symsect.cts_data = symbuf;
+ symsect.cts_offset = 0;
+ symp = &symsect;
+ } else {
+ symp = NULL;
+ }
+
+ if (ofp->ctf_strtab.cts_data != NULL) {
+ bcopy(&ofp->ctf_strtab, &strsect, sizeof (ctf_sect_t));
+ strbuf = ctf_data_alloc(strsect.cts_size);
+ if (strbuf == NULL) {
+ (void) ctf_set_errno(ofp, ECTF_MMAP);
+ goto err;
+ }
+ bcopy(strsect.cts_data, strbuf, strsect.cts_size);
+ ctf_data_protect(strbuf, strsect.cts_size);
+ strsect.cts_data = strbuf;
+ strsect.cts_offset = 0;
+ strp = &strsect;
+ } else {
+ strp = NULL;
+ }
+
+ fp = ctf_bufopen(ctp, symp, strp, &err);
+ if (fp == NULL) {
+ (void) ctf_set_errno(ofp, err);
+ goto err;
+ }
+
+ fp->ctf_flags |= LCTF_MMAP;
+
+ return (fp);
+
+err:
+ ctf_data_free(cbuf, ctfsect.cts_size);
+ if (symbuf != NULL)
+ ctf_data_free(symbuf, symsect.cts_size);
+ if (strbuf != NULL)
+ ctf_data_free(strbuf, strsect.cts_size);
+ return (NULL);
+}
+
+/*
+ * Close the specified CTF container and free associated data structures. Note
+ * that ctf_close() is a reference counted operation: if the specified file is
+ * the parent of other active containers, its reference count will be greater
+ * than one and it will be freed later when no active children exist.
+ */
+void
+ctf_close(ctf_file_t *fp)
+{
+ ctf_dtdef_t *dtd, *ntd;
+
+ if (fp == NULL)
+ return; /* allow ctf_close(NULL) to simplify caller code */
+
+ ctf_dprintf("ctf_close(%p) refcnt=%u\n", (void *)fp, fp->ctf_refcnt);
+
+ if (fp->ctf_refcnt > 1) {
+ fp->ctf_refcnt--;
+ return;
+ }
+
+ if (fp->ctf_parent != NULL)
+ ctf_close(fp->ctf_parent);
+
+ /*
+ * Note, to work properly with reference counting on the dynamic
+ * section, we must delete the list in reverse.
+ */
+ for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
+ ntd = ctf_list_prev(dtd);
+ ctf_dtd_delete(fp, dtd);
+ }
+
+ ctf_free(fp->ctf_dthash, fp->ctf_dthashlen * sizeof (ctf_dtdef_t *));
+
+ if (fp->ctf_flags & LCTF_MMAP) {
+ if (fp->ctf_data.cts_data != NULL)
+ ctf_sect_munmap(&fp->ctf_data);
+ if (fp->ctf_symtab.cts_data != NULL)
+ ctf_sect_munmap(&fp->ctf_symtab);
+ if (fp->ctf_strtab.cts_data != NULL)
+ ctf_sect_munmap(&fp->ctf_strtab);
+ }
+
+ if (fp->ctf_data.cts_name != _CTF_NULLSTR &&
+ fp->ctf_data.cts_name != NULL) {
+ ctf_free((char *)fp->ctf_data.cts_name,
+ strlen(fp->ctf_data.cts_name) + 1);
+ }
+
+ if (fp->ctf_symtab.cts_name != _CTF_NULLSTR &&
+ fp->ctf_symtab.cts_name != NULL) {
+ ctf_free((char *)fp->ctf_symtab.cts_name,
+ strlen(fp->ctf_symtab.cts_name) + 1);
+ }
+
+ if (fp->ctf_strtab.cts_name != _CTF_NULLSTR &&
+ fp->ctf_strtab.cts_name != NULL) {
+ ctf_free((char *)fp->ctf_strtab.cts_name,
+ strlen(fp->ctf_strtab.cts_name) + 1);
+ }
+
+ if (fp->ctf_base != fp->ctf_data.cts_data && fp->ctf_base != NULL)
+ ctf_data_free((void *)fp->ctf_base, fp->ctf_size);
+
+ if (fp->ctf_sxlate != NULL)
+ ctf_free(fp->ctf_sxlate, sizeof (uint_t) * fp->ctf_nsyms);
+
+ if (fp->ctf_txlate != NULL) {
+ ctf_free(fp->ctf_txlate,
+ sizeof (uint_t) * (fp->ctf_typemax + 1));
+ }
+
+ if (fp->ctf_ptrtab != NULL) {
+ ctf_free(fp->ctf_ptrtab,
+ sizeof (ushort_t) * (fp->ctf_typemax + 1));
+ }
+
+ ctf_hash_destroy(&fp->ctf_structs);
+ ctf_hash_destroy(&fp->ctf_unions);
+ ctf_hash_destroy(&fp->ctf_enums);
+ ctf_hash_destroy(&fp->ctf_names);
+
+ ctf_free(fp, sizeof (ctf_file_t));
+}
+
+/*
+ * Return the CTF handle for the parent CTF container, if one exists.
+ * Otherwise return NULL to indicate this container has no imported parent.
+ */
+ctf_file_t *
+ctf_parent_file(ctf_file_t *fp)
+{
+ return (fp->ctf_parent);
+}
+
+/*
+ * Return the name of the parent CTF container, if one exists. Otherwise
+ * return NULL to indicate this container is a root container.
+ */
+const char *
+ctf_parent_name(ctf_file_t *fp)
+{
+ return (fp->ctf_parname);
+}
+
+/*
+ * Import the types from the specified parent container by storing a pointer
+ * to it in ctf_parent and incrementing its reference count. Only one parent
+ * is allowed: if a parent already exists, it is replaced by the new parent.
+ */
+int
+ctf_import(ctf_file_t *fp, ctf_file_t *pfp)
+{
+ if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
+ return (ctf_set_errno(fp, EINVAL));
+
+ if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
+ return (ctf_set_errno(fp, ECTF_DMODEL));
+
+ if (fp->ctf_parent != NULL)
+ ctf_close(fp->ctf_parent);
+
+ if (pfp != NULL) {
+ fp->ctf_flags |= LCTF_CHILD;
+ pfp->ctf_refcnt++;
+ }
+
+ fp->ctf_parent = pfp;
+ return (0);
+}
+
+/*
+ * Set the data model constant for the CTF container.
+ */
+int
+ctf_setmodel(ctf_file_t *fp, int model)
+{
+ const ctf_dmodel_t *dp;
+
+ for (dp = _libctf_models; dp->ctd_name != NULL; dp++) {
+ if (dp->ctd_code == model) {
+ fp->ctf_dmodel = dp;
+ return (0);
+ }
+ }
+
+ return (ctf_set_errno(fp, EINVAL));
+}
+
+/*
+ * Return the data model constant for the CTF container.
+ */
+int
+ctf_getmodel(ctf_file_t *fp)
+{
+ return (fp->ctf_dmodel->ctd_code);
+}
+
+void
+ctf_setspecific(ctf_file_t *fp, void *data)
+{
+ fp->ctf_specific = data;
+}
+
+void *
+ctf_getspecific(ctf_file_t *fp)
+{
+ return (fp->ctf_specific);
+}
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_types.c b/cddl/contrib/opensolaris/common/ctf/ctf_types.c
new file mode 100644
index 000000000000..21b061cd9356
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_types.c
@@ -0,0 +1,887 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <ctf_impl.h>
+
+ssize_t
+ctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep,
+ ssize_t *incrementp)
+{
+ ssize_t size, increment;
+
+ if (fp->ctf_version > CTF_VERSION_1 &&
+ tp->ctt_size == CTF_LSIZE_SENT) {
+ size = CTF_TYPE_LSIZE(tp);
+ increment = sizeof (ctf_type_t);
+ } else {
+ size = tp->ctt_size;
+ increment = sizeof (ctf_stype_t);
+ }
+
+ if (sizep)
+ *sizep = size;
+ if (incrementp)
+ *incrementp = increment;
+
+ return (size);
+}
+
+/*
+ * Iterate over the members of a STRUCT or UNION. We pass the name, member
+ * type, and offset of each member to the specified callback function.
+ */
+int
+ctf_member_iter(ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+ ssize_t size, increment;
+ uint_t kind, n;
+ int rc;
+
+ if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ (void) ctf_get_ctt_size(fp, tp, &size, &increment);
+ kind = LCTF_INFO_KIND(fp, tp->ctt_info);
+
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+ return (ctf_set_errno(ofp, ECTF_NOTSOU));
+
+ if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
+ const ctf_member_t *mp = (const ctf_member_t *)
+ ((uintptr_t)tp + increment);
+
+ for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
+ const char *name = ctf_strptr(fp, mp->ctm_name);
+ if ((rc = func(name, mp->ctm_type, mp->ctm_offset,
+ arg)) != 0)
+ return (rc);
+ }
+
+ } else {
+ const ctf_lmember_t *lmp = (const ctf_lmember_t *)
+ ((uintptr_t)tp + increment);
+
+ for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
+ const char *name = ctf_strptr(fp, lmp->ctlm_name);
+ if ((rc = func(name, lmp->ctlm_type,
+ (ulong_t)CTF_LMEM_OFFSET(lmp), arg)) != 0)
+ return (rc);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Iterate over the members of an ENUM. We pass the string name and associated
+ * integer value of each enum element to the specified callback function.
+ */
+int
+ctf_enum_iter(ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+ const ctf_enum_t *ep;
+ ssize_t increment;
+ uint_t n;
+ int rc;
+
+ if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM)
+ return (ctf_set_errno(ofp, ECTF_NOTENUM));
+
+ (void) ctf_get_ctt_size(fp, tp, NULL, &increment);
+
+ ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
+
+ for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
+ const char *name = ctf_strptr(fp, ep->cte_name);
+ if ((rc = func(name, ep->cte_value, arg)) != 0)
+ return (rc);
+ }
+
+ return (0);
+}
+
+/*
+ * Iterate over every root (user-visible) type in the given CTF container.
+ * We pass the type ID of each type to the specified callback function.
+ */
+int
+ctf_type_iter(ctf_file_t *fp, ctf_type_f *func, void *arg)
+{
+ ctf_id_t id, max = fp->ctf_typemax;
+ int rc, child = (fp->ctf_flags & LCTF_CHILD);
+
+ for (id = 1; id <= max; id++) {
+ const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR(fp, id);
+ if (CTF_INFO_ISROOT(tp->ctt_info) &&
+ (rc = func(CTF_INDEX_TO_TYPE(id, child), arg)) != 0)
+ return (rc);
+ }
+
+ return (0);
+}
+
+/*
+ * Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
+ * RESTRICT nodes until we reach a "base" type node. This is useful when
+ * we want to follow a type ID to a node that has members or a size. To guard
+ * against infinite loops, we implement simplified cycle detection and check
+ * each link against itself, the previous node, and the topmost node.
+ */
+ctf_id_t
+ctf_type_resolve(ctf_file_t *fp, ctf_id_t type)
+{
+ ctf_id_t prev = type, otype = type;
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+
+ while ((tp = ctf_lookup_by_id(&fp, type)) != NULL) {
+ switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
+ case CTF_K_TYPEDEF:
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ if (tp->ctt_type == type || tp->ctt_type == otype ||
+ tp->ctt_type == prev) {
+ ctf_dprintf("type %ld cycle detected\n", otype);
+ return (ctf_set_errno(ofp, ECTF_CORRUPT));
+ }
+ prev = type;
+ type = tp->ctt_type;
+ break;
+ default:
+ return (type);
+ }
+ }
+
+ return (CTF_ERR); /* errno is set for us */
+}
+
+/*
+ * Lookup the given type ID and print a string name for it into buf. Return
+ * the actual number of bytes (not including \0) needed to format the name.
+ */
+static ssize_t
+ctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
+ const char *qname)
+{
+ ctf_decl_t cd;
+ ctf_decl_node_t *cdp;
+ ctf_decl_prec_t prec, lp, rp;
+ int ptr, arr;
+ uint_t k;
+
+ if (fp == NULL && type == CTF_ERR)
+ return (-1); /* simplify caller code by permitting CTF_ERR */
+
+ ctf_decl_init(&cd, buf, len);
+ ctf_decl_push(&cd, fp, type);
+
+ if (cd.cd_err != 0) {
+ ctf_decl_fini(&cd);
+ return (ctf_set_errno(fp, cd.cd_err));
+ }
+
+ /*
+ * If the type graph's order conflicts with lexical precedence order
+ * for pointers or arrays, then we need to surround the declarations at
+ * the corresponding lexical precedence with parentheses. This can
+ * result in either a parenthesized pointer (*) as in int (*)() or
+ * int (*)[], or in a parenthesized pointer and array as in int (*[])().
+ */
+ ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER;
+ arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY;
+
+ rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1;
+ lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1;
+
+ k = CTF_K_POINTER; /* avoid leading whitespace (see below) */
+
+ for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) {
+ for (cdp = ctf_list_next(&cd.cd_nodes[prec]);
+ cdp != NULL; cdp = ctf_list_next(cdp)) {
+
+ ctf_file_t *rfp = fp;
+ const ctf_type_t *tp =
+ ctf_lookup_by_id(&rfp, cdp->cd_type);
+ const char *name = ctf_strptr(rfp, tp->ctt_name);
+
+ if (k != CTF_K_POINTER && k != CTF_K_ARRAY)
+ ctf_decl_sprintf(&cd, " ");
+
+ if (lp == prec) {
+ ctf_decl_sprintf(&cd, "(");
+ lp = -1;
+ }
+
+ switch (cdp->cd_kind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ case CTF_K_TYPEDEF:
+ if (qname != NULL)
+ ctf_decl_sprintf(&cd, "%s`", qname);
+ ctf_decl_sprintf(&cd, "%s", name);
+ break;
+ case CTF_K_POINTER:
+ ctf_decl_sprintf(&cd, "*");
+ break;
+ case CTF_K_ARRAY:
+ ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n);
+ break;
+ case CTF_K_FUNCTION:
+ ctf_decl_sprintf(&cd, "()");
+ break;
+ case CTF_K_STRUCT:
+ case CTF_K_FORWARD:
+ ctf_decl_sprintf(&cd, "struct ");
+ if (qname != NULL)
+ ctf_decl_sprintf(&cd, "%s`", qname);
+ ctf_decl_sprintf(&cd, "%s", name);
+ break;
+ case CTF_K_UNION:
+ ctf_decl_sprintf(&cd, "union ");
+ if (qname != NULL)
+ ctf_decl_sprintf(&cd, "%s`", qname);
+ ctf_decl_sprintf(&cd, "%s", name);
+ break;
+ case CTF_K_ENUM:
+ ctf_decl_sprintf(&cd, "enum ");
+ if (qname != NULL)
+ ctf_decl_sprintf(&cd, "%s`", qname);
+ ctf_decl_sprintf(&cd, "%s", name);
+ break;
+ case CTF_K_VOLATILE:
+ ctf_decl_sprintf(&cd, "volatile");
+ break;
+ case CTF_K_CONST:
+ ctf_decl_sprintf(&cd, "const");
+ break;
+ case CTF_K_RESTRICT:
+ ctf_decl_sprintf(&cd, "restrict");
+ break;
+ }
+
+ k = cdp->cd_kind;
+ }
+
+ if (rp == prec)
+ ctf_decl_sprintf(&cd, ")");
+ }
+
+ if (cd.cd_len >= len)
+ (void) ctf_set_errno(fp, ECTF_NAMELEN);
+
+ ctf_decl_fini(&cd);
+ return (cd.cd_len);
+}
+
+ssize_t
+ctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
+{
+ return (ctf_type_qlname(fp, type, buf, len, NULL));
+}
+
+/*
+ * Lookup the given type ID and print a string name for it into buf. If buf
+ * is too small, return NULL: the ECTF_NAMELEN error is set on 'fp' for us.
+ */
+char *
+ctf_type_name(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
+{
+ ssize_t rv = ctf_type_qlname(fp, type, buf, len, NULL);
+ return (rv >= 0 && rv < len ? buf : NULL);
+}
+
+char *
+ctf_type_qname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
+ const char *qname)
+{
+ ssize_t rv = ctf_type_qlname(fp, type, buf, len, qname);
+ return (rv >= 0 && rv < len ? buf : NULL);
+}
+
+
+/*
+ * Resolve the type down to a base type node, and then return the size
+ * of the type storage in bytes.
+ */
+ssize_t
+ctf_type_size(ctf_file_t *fp, ctf_id_t type)
+{
+ const ctf_type_t *tp;
+ ssize_t size;
+ ctf_arinfo_t ar;
+
+ if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
+ return (-1); /* errno is set for us */
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (-1); /* errno is set for us */
+
+ switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
+ case CTF_K_POINTER:
+ return (fp->ctf_dmodel->ctd_pointer);
+
+ case CTF_K_FUNCTION:
+ return (0); /* function size is only known by symtab */
+
+ case CTF_K_ENUM:
+ return (fp->ctf_dmodel->ctd_int);
+
+ case CTF_K_ARRAY:
+ /*
+ * Array size is not directly returned by stabs data. Instead,
+ * it defines the element type and requires the user to perform
+ * the multiplication. If ctf_get_ctt_size() returns zero, the
+ * current version of ctfconvert does not compute member sizes
+ * and we compute the size here on its behalf.
+ */
+ if ((size = ctf_get_ctt_size(fp, tp, NULL, NULL)) > 0)
+ return (size);
+
+ if (ctf_array_info(fp, type, &ar) == CTF_ERR ||
+ (size = ctf_type_size(fp, ar.ctr_contents)) == CTF_ERR)
+ return (-1); /* errno is set for us */
+
+ return (size * ar.ctr_nelems);
+
+ default:
+ return (ctf_get_ctt_size(fp, tp, NULL, NULL));
+ }
+}
+
+/*
+ * Resolve the type down to a base type node, and then return the alignment
+ * needed for the type storage in bytes.
+ */
+ssize_t
+ctf_type_align(ctf_file_t *fp, ctf_id_t type)
+{
+ const ctf_type_t *tp;
+ ctf_arinfo_t r;
+
+ if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
+ return (-1); /* errno is set for us */
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (-1); /* errno is set for us */
+
+ switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
+ case CTF_K_POINTER:
+ case CTF_K_FUNCTION:
+ return (fp->ctf_dmodel->ctd_pointer);
+
+ case CTF_K_ARRAY:
+ if (ctf_array_info(fp, type, &r) == CTF_ERR)
+ return (-1); /* errno is set for us */
+ return (ctf_type_align(fp, r.ctr_contents));
+
+ case CTF_K_STRUCT:
+ case CTF_K_UNION: {
+ uint_t n = LCTF_INFO_VLEN(fp, tp->ctt_info);
+ ssize_t size, increment;
+ size_t align = 0;
+ const void *vmp;
+
+ (void) ctf_get_ctt_size(fp, tp, &size, &increment);
+ vmp = (uchar_t *)tp + increment;
+
+ if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_STRUCT)
+ n = MIN(n, 1); /* only use first member for structs */
+
+ if (fp->ctf_version == CTF_VERSION_1 ||
+ size < CTF_LSTRUCT_THRESH) {
+ const ctf_member_t *mp = vmp;
+ for (; n != 0; n--, mp++) {
+ ssize_t am = ctf_type_align(fp, mp->ctm_type);
+ align = MAX(align, am);
+ }
+ } else {
+ const ctf_lmember_t *lmp = vmp;
+ for (; n != 0; n--, lmp++) {
+ ssize_t am = ctf_type_align(fp, lmp->ctlm_type);
+ align = MAX(align, am);
+ }
+ }
+
+ return (align);
+ }
+
+ case CTF_K_ENUM:
+ return (fp->ctf_dmodel->ctd_int);
+
+ default:
+ return (ctf_get_ctt_size(fp, tp, NULL, NULL));
+ }
+}
+
+/*
+ * Return the kind (CTF_K_* constant) for the specified type ID.
+ */
+int
+ctf_type_kind(ctf_file_t *fp, ctf_id_t type)
+{
+ const ctf_type_t *tp;
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ return (LCTF_INFO_KIND(fp, tp->ctt_info));
+}
+
+/*
+ * If the type is one that directly references another type (such as POINTER),
+ * then return the ID of the type to which it refers.
+ */
+ctf_id_t
+ctf_type_reference(ctf_file_t *fp, ctf_id_t type)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
+ case CTF_K_POINTER:
+ case CTF_K_TYPEDEF:
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ return (tp->ctt_type);
+ default:
+ return (ctf_set_errno(ofp, ECTF_NOTREF));
+ }
+}
+
+/*
+ * Find a pointer to type by looking in fp->ctf_ptrtab. If we can't find a
+ * pointer to the given type, see if we can compute a pointer to the type
+ * resulting from resolving the type down to its base type and use that
+ * instead. This helps with cases where the CTF data includes "struct foo *"
+ * but not "foo_t *" and the user accesses "foo_t *" in the debugger.
+ */
+ctf_id_t
+ctf_type_pointer(ctf_file_t *fp, ctf_id_t type)
+{
+ ctf_file_t *ofp = fp;
+ ctf_id_t ntype;
+
+ if (ctf_lookup_by_id(&fp, type) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0)
+ return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD)));
+
+ if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
+ return (ctf_set_errno(ofp, ECTF_NOTYPE));
+
+ if (ctf_lookup_by_id(&fp, type) == NULL)
+ return (ctf_set_errno(ofp, ECTF_NOTYPE));
+
+ if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0)
+ return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD)));
+
+ return (ctf_set_errno(ofp, ECTF_NOTYPE));
+}
+
+/*
+ * Return the encoding for the specified INTEGER or FLOAT.
+ */
+int
+ctf_type_encoding(ctf_file_t *fp, ctf_id_t type, ctf_encoding_t *ep)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+ ssize_t increment;
+ uint_t data;
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ (void) ctf_get_ctt_size(fp, tp, NULL, &increment);
+
+ switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
+ case CTF_K_INTEGER:
+ data = *(const uint_t *)((uintptr_t)tp + increment);
+ ep->cte_format = CTF_INT_ENCODING(data);
+ ep->cte_offset = CTF_INT_OFFSET(data);
+ ep->cte_bits = CTF_INT_BITS(data);
+ break;
+ case CTF_K_FLOAT:
+ data = *(const uint_t *)((uintptr_t)tp + increment);
+ ep->cte_format = CTF_FP_ENCODING(data);
+ ep->cte_offset = CTF_FP_OFFSET(data);
+ ep->cte_bits = CTF_FP_BITS(data);
+ break;
+ default:
+ return (ctf_set_errno(ofp, ECTF_NOTINTFP));
+ }
+
+ return (0);
+}
+
+int
+ctf_type_cmp(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype)
+{
+ int rval;
+
+ if (ltype < rtype)
+ rval = -1;
+ else if (ltype > rtype)
+ rval = 1;
+ else
+ rval = 0;
+
+ if (lfp == rfp)
+ return (rval);
+
+ if (CTF_TYPE_ISPARENT(ltype) && lfp->ctf_parent != NULL)
+ lfp = lfp->ctf_parent;
+
+ if (CTF_TYPE_ISPARENT(rtype) && rfp->ctf_parent != NULL)
+ rfp = rfp->ctf_parent;
+
+ if (lfp < rfp)
+ return (-1);
+
+ if (lfp > rfp)
+ return (1);
+
+ return (rval);
+}
+
+/*
+ * Return a boolean value indicating if two types are compatible integers or
+ * floating-pointer values. This function returns true if the two types are
+ * the same, or if they have the same ASCII name and encoding properties.
+ * This function could be extended to test for compatibility for other kinds.
+ */
+int
+ctf_type_compat(ctf_file_t *lfp, ctf_id_t ltype,
+ ctf_file_t *rfp, ctf_id_t rtype)
+{
+ const ctf_type_t *ltp, *rtp;
+ ctf_encoding_t le, re;
+ ctf_arinfo_t la, ra;
+ uint_t lkind, rkind;
+
+ if (ctf_type_cmp(lfp, ltype, rfp, rtype) == 0)
+ return (1);
+
+ ltype = ctf_type_resolve(lfp, ltype);
+ lkind = ctf_type_kind(lfp, ltype);
+
+ rtype = ctf_type_resolve(rfp, rtype);
+ rkind = ctf_type_kind(rfp, rtype);
+
+ if (lkind != rkind ||
+ (ltp = ctf_lookup_by_id(&lfp, ltype)) == NULL ||
+ (rtp = ctf_lookup_by_id(&rfp, rtype)) == NULL ||
+ strcmp(ctf_strptr(lfp, ltp->ctt_name),
+ ctf_strptr(rfp, rtp->ctt_name)) != 0)
+ return (0);
+
+ switch (lkind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ return (ctf_type_encoding(lfp, ltype, &le) == 0 &&
+ ctf_type_encoding(rfp, rtype, &re) == 0 &&
+ bcmp(&le, &re, sizeof (ctf_encoding_t)) == 0);
+ case CTF_K_POINTER:
+ return (ctf_type_compat(lfp, ctf_type_reference(lfp, ltype),
+ rfp, ctf_type_reference(rfp, rtype)));
+ case CTF_K_ARRAY:
+ return (ctf_array_info(lfp, ltype, &la) == 0 &&
+ ctf_array_info(rfp, rtype, &ra) == 0 &&
+ la.ctr_nelems == ra.ctr_nelems && ctf_type_compat(
+ lfp, la.ctr_contents, rfp, ra.ctr_contents) &&
+ ctf_type_compat(lfp, la.ctr_index, rfp, ra.ctr_index));
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ return (ctf_type_size(lfp, ltype) == ctf_type_size(rfp, rtype));
+ case CTF_K_ENUM:
+ case CTF_K_FORWARD:
+ return (1); /* no other checks required for these type kinds */
+ default:
+ return (0); /* should not get here since we did a resolve */
+ }
+}
+
+static int
+_ctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name, ulong_t off,
+ ctf_membinfo_t *mip)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+ ssize_t size, increment;
+ uint_t kind, n;
+
+ if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ (void) ctf_get_ctt_size(fp, tp, &size, &increment);
+ kind = LCTF_INFO_KIND(fp, tp->ctt_info);
+
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+ return (ctf_set_errno(ofp, ECTF_NOTSOU));
+
+ if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
+ const ctf_member_t *mp = (const ctf_member_t *)
+ ((uintptr_t)tp + increment);
+
+ for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
+ if (mp->ctm_name == 0 &&
+ _ctf_member_info(fp, mp->ctm_type, name,
+ mp->ctm_offset + off, mip) == 0)
+ return (0);
+ if (strcmp(ctf_strptr(fp, mp->ctm_name), name) == 0) {
+ mip->ctm_type = mp->ctm_type;
+ mip->ctm_offset = mp->ctm_offset + off;
+ return (0);
+ }
+ }
+ } else {
+ const ctf_lmember_t *lmp = (const ctf_lmember_t *)
+ ((uintptr_t)tp + increment);
+
+ for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
+ if (lmp->ctlm_name == 0 &&
+ _ctf_member_info(fp, lmp->ctlm_name, name,
+ (ulong_t)CTF_LMEM_OFFSET(lmp) + off, mip) == 0)
+ return (0);
+ if (strcmp(ctf_strptr(fp, lmp->ctlm_name), name) == 0) {
+ mip->ctm_type = lmp->ctlm_type;
+ mip->ctm_offset =
+ (ulong_t)CTF_LMEM_OFFSET(lmp) + off;
+ return (0);
+ }
+ }
+ }
+
+ return (ctf_set_errno(ofp, ECTF_NOMEMBNAM));
+}
+
+/*
+ * Return the type and offset for a given member of a STRUCT or UNION.
+ */
+int
+ctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name,
+ ctf_membinfo_t *mip)
+{
+
+ return (_ctf_member_info(fp, type, name, 0, mip));
+}
+
+/*
+ * Return the array type, index, and size information for the specified ARRAY.
+ */
+int
+ctf_array_info(ctf_file_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+ const ctf_array_t *ap;
+ ssize_t increment;
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ARRAY)
+ return (ctf_set_errno(ofp, ECTF_NOTARRAY));
+
+ (void) ctf_get_ctt_size(fp, tp, NULL, &increment);
+
+ ap = (const ctf_array_t *)((uintptr_t)tp + increment);
+ arp->ctr_contents = ap->cta_contents;
+ arp->ctr_index = ap->cta_index;
+ arp->ctr_nelems = ap->cta_nelems;
+
+ return (0);
+}
+
+/*
+ * Convert the specified value to the corresponding enum member name, if a
+ * matching name can be found. Otherwise NULL is returned.
+ */
+const char *
+ctf_enum_name(ctf_file_t *fp, ctf_id_t type, int value)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+ const ctf_enum_t *ep;
+ ssize_t increment;
+ uint_t n;
+
+ if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
+ return (NULL); /* errno is set for us */
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (NULL); /* errno is set for us */
+
+ if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) {
+ (void) ctf_set_errno(ofp, ECTF_NOTENUM);
+ return (NULL);
+ }
+
+ (void) ctf_get_ctt_size(fp, tp, NULL, &increment);
+
+ ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
+
+ for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
+ if (ep->cte_value == value)
+ return (ctf_strptr(fp, ep->cte_name));
+ }
+
+ (void) ctf_set_errno(ofp, ECTF_NOENUMNAM);
+ return (NULL);
+}
+
+/*
+ * Convert the specified enum tag name to the corresponding value, if a
+ * matching name can be found. Otherwise CTF_ERR is returned.
+ */
+int
+ctf_enum_value(ctf_file_t *fp, ctf_id_t type, const char *name, int *valp)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+ const ctf_enum_t *ep;
+ ssize_t size, increment;
+ uint_t n;
+
+ if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) {
+ (void) ctf_set_errno(ofp, ECTF_NOTENUM);
+ return (CTF_ERR);
+ }
+
+ (void) ctf_get_ctt_size(fp, tp, &size, &increment);
+
+ ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
+
+ for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
+ if (strcmp(ctf_strptr(fp, ep->cte_name), name) == 0) {
+ if (valp != NULL)
+ *valp = ep->cte_value;
+ return (0);
+ }
+ }
+
+ (void) ctf_set_errno(ofp, ECTF_NOENUMNAM);
+ return (CTF_ERR);
+}
+
+/*
+ * Recursively visit the members of any type. This function is used as the
+ * engine for ctf_type_visit, below. We resolve the input type, recursively
+ * invoke ourself for each type member if the type is a struct or union, and
+ * then invoke the callback function on the current type. If any callback
+ * returns non-zero, we abort and percolate the error code back up to the top.
+ */
+static int
+ctf_type_rvisit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg,
+ const char *name, ulong_t offset, int depth)
+{
+ ctf_id_t otype = type;
+ const ctf_type_t *tp;
+ ssize_t size, increment;
+ uint_t kind, n;
+ int rc;
+
+ if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ if ((rc = func(name, otype, offset, depth, arg)) != 0)
+ return (rc);
+
+ kind = LCTF_INFO_KIND(fp, tp->ctt_info);
+
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+ return (0);
+
+ (void) ctf_get_ctt_size(fp, tp, &size, &increment);
+
+ if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
+ const ctf_member_t *mp = (const ctf_member_t *)
+ ((uintptr_t)tp + increment);
+
+ for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
+ if ((rc = ctf_type_rvisit(fp, mp->ctm_type,
+ func, arg, ctf_strptr(fp, mp->ctm_name),
+ offset + mp->ctm_offset, depth + 1)) != 0)
+ return (rc);
+ }
+
+ } else {
+ const ctf_lmember_t *lmp = (const ctf_lmember_t *)
+ ((uintptr_t)tp + increment);
+
+ for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
+ if ((rc = ctf_type_rvisit(fp, lmp->ctlm_type,
+ func, arg, ctf_strptr(fp, lmp->ctlm_name),
+ offset + (ulong_t)CTF_LMEM_OFFSET(lmp),
+ depth + 1)) != 0)
+ return (rc);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Recursively visit the members of any type. We pass the name, member
+ * type, and offset of each member to the specified callback function.
+ */
+int
+ctf_type_visit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg)
+{
+ return (ctf_type_rvisit(fp, type, func, arg, "", 0, 0));
+}
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_util.c b/cddl/contrib/opensolaris/common/ctf/ctf_util.c
new file mode 100644
index 000000000000..740d403e8c52
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_util.c
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ctf_impl.h>
+
+/*
+ * Simple doubly-linked list append routine. This implementation assumes that
+ * each list element contains an embedded ctf_list_t as the first member.
+ * An additional ctf_list_t is used to store the head (l_next) and tail
+ * (l_prev) pointers. The current head and tail list elements have their
+ * previous and next pointers set to NULL, respectively.
+ */
+void
+ctf_list_append(ctf_list_t *lp, void *new)
+{
+ ctf_list_t *p = lp->l_prev; /* p = tail list element */
+ ctf_list_t *q = new; /* q = new list element */
+
+ lp->l_prev = q;
+ q->l_prev = p;
+ q->l_next = NULL;
+
+ if (p != NULL)
+ p->l_next = q;
+ else
+ lp->l_next = q;
+}
+
+/*
+ * Prepend the specified existing element to the given ctf_list_t. The
+ * existing pointer should be pointing at a struct with embedded ctf_list_t.
+ */
+void
+ctf_list_prepend(ctf_list_t *lp, void *new)
+{
+ ctf_list_t *p = new; /* p = new list element */
+ ctf_list_t *q = lp->l_next; /* q = head list element */
+
+ lp->l_next = p;
+ p->l_prev = NULL;
+ p->l_next = q;
+
+ if (q != NULL)
+ q->l_prev = p;
+ else
+ lp->l_prev = p;
+}
+
+/*
+ * Delete the specified existing element from the given ctf_list_t. The
+ * existing pointer should be pointing at a struct with embedded ctf_list_t.
+ */
+void
+ctf_list_delete(ctf_list_t *lp, void *existing)
+{
+ ctf_list_t *p = existing;
+
+ if (p->l_prev != NULL)
+ p->l_prev->l_next = p->l_next;
+ else
+ lp->l_next = p->l_next;
+
+ if (p->l_next != NULL)
+ p->l_next->l_prev = p->l_prev;
+ else
+ lp->l_prev = p->l_prev;
+}
+
+/*
+ * Convert an encoded CTF string name into a pointer to a C string by looking
+ * up the appropriate string table buffer and then adding the offset.
+ */
+const char *
+ctf_strraw(ctf_file_t *fp, uint_t name)
+{
+ ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID(name)];
+
+ if (ctsp->cts_strs != NULL && CTF_NAME_OFFSET(name) < ctsp->cts_len)
+ return (ctsp->cts_strs + CTF_NAME_OFFSET(name));
+
+ /* string table not loaded or corrupt offset */
+ return (NULL);
+}
+
+const char *
+ctf_strptr(ctf_file_t *fp, uint_t name)
+{
+ const char *s = ctf_strraw(fp, name);
+ return (s != NULL ? s : "(?)");
+}
+
+/*
+ * Same strdup(3C), but use ctf_alloc() to do the memory allocation.
+ */
+char *
+ctf_strdup(const char *s1)
+{
+ char *s2 = ctf_alloc(strlen(s1) + 1);
+
+ if (s2 != NULL)
+ (void) strcpy(s2, s1);
+
+ return (s2);
+}
+
+/*
+ * Store the specified error code into errp if it is non-NULL, and then
+ * return NULL for the benefit of the caller.
+ */
+ctf_file_t *
+ctf_set_open_errno(int *errp, int error)
+{
+ if (errp != NULL)
+ *errp = error;
+ return (NULL);
+}
+
+/*
+ * Store the specified error code into the CTF container, and then return
+ * CTF_ERR for the benefit of the caller.
+ */
+long
+ctf_set_errno(ctf_file_t *fp, int err)
+{
+ fp->ctf_errno = err;
+ return (CTF_ERR);
+}
diff --git a/cddl/contrib/opensolaris/common/util/strtolctype.h b/cddl/contrib/opensolaris/common/util/strtolctype.h
new file mode 100644
index 000000000000..91609cede4e1
--- /dev/null
+++ b/cddl/contrib/opensolaris/common/util/strtolctype.h
@@ -0,0 +1,79 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+#ifndef _COMMON_UTIL_CTYPE_H
+#define _COMMON_UTIL_CTYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This header file contains a collection of macros that the strtou?ll?
+ * functions in common/util use to test characters. What we need is a kernel
+ * version of ctype.h.
+ *
+ * NOTE: These macros are used within several DTrace probe context functions.
+ * They must not be altered to make function calls or perform actions not
+ * safe in probe context.
+ */
+
+#if defined(illumos) && (defined(_KERNEL) || defined(_BOOT))
+
+#define isalnum(ch) (isalpha(ch) || isdigit(ch))
+#define isalpha(ch) (isupper(ch) || islower(ch))
+#define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
+#define islower(ch) ((ch) >= 'a' && (ch) <= 'z')
+#define isspace(ch) (((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
+ ((ch) == '\t') || ((ch) == '\f'))
+#define isupper(ch) ((ch) >= 'A' && (ch) <= 'Z')
+#define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
+ ((ch) >= 'A' && (ch) <= 'F'))
+
+#endif /* _KERNEL || _BOOT */
+
+#define DIGIT(x) \
+ (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
+
+#define MBASE ('z' - 'a' + 1 + 10)
+
+/*
+ * The following macro is a version of isalnum() that limits alphabetic
+ * characters to the ranges a-z and A-Z; locale dependent characters will not
+ * return 1. The members of a-z and A-Z are assumed to be in ascending order
+ * and contiguous.
+ */
+#define lisalnum(x) \
+ (isdigit(x) || ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _COMMON_UTIL_CTYPE_H */
diff --git a/cddl/contrib/opensolaris/head/atomic.h b/cddl/contrib/opensolaris/head/atomic.h
new file mode 100644
index 000000000000..00c947604eb8
--- /dev/null
+++ b/cddl/contrib/opensolaris/head/atomic.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ATOMIC_H
+#define _ATOMIC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/atomic.h>
+
+#endif /* _ATOMIC_H */
diff --git a/cddl/contrib/opensolaris/head/libintl.h b/cddl/contrib/opensolaris/head/libintl.h
new file mode 100644
index 000000000000..262fa89a1722
--- /dev/null
+++ b/cddl/contrib/opensolaris/head/libintl.h
@@ -0,0 +1,97 @@
+/*
+ * 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 2014 Garrett D'Amore <garrett@damore.org>
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _LIBINTL_H
+#define _LIBINTL_H
+
+#include <sys/isa_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * wchar_t is a built-in type in standard C++ and as such is not
+ * defined here when using standard C++. However, the GNU compiler
+ * fixincludes utility nonetheless creates its own version of this
+ * header for use by gcc and g++. In that version it adds a redundant
+ * guard for __cplusplus. To avoid the creation of a gcc/g++ specific
+ * header we need to include the following magic comment:
+ *
+ * we must use the C++ compiler's type
+ *
+ * The above comment should not be removed or changed until GNU
+ * gcc/fixinc/inclhack.def is updated to bypass this header.
+ */
+#if !defined(__cplusplus) || (__cplusplus < 199711L && !defined(__GNUG__))
+#ifndef _WCHAR_T
+#define _WCHAR_T
+#if defined(_LP64)
+typedef int wchar_t;
+#else
+typedef long wchar_t;
+#endif
+#endif /* !_WCHAR_T */
+#endif /* !defined(__cplusplus) ... */
+
+#define TEXTDOMAINMAX 256
+
+#define __GNU_GETTEXT_SUPPORTED_REVISION(m) \
+ ((((m) == 0) || ((m) == 1)) ? 1 : -1)
+
+extern char *dcgettext(const char *, const char *, const int);
+extern char *dgettext(const char *, const char *);
+extern char *gettext(const char *);
+extern char *textdomain(const char *);
+extern char *bindtextdomain(const char *, const char *);
+
+/*
+ * LI18NUX 2000 Globalization Specification Version 1.0
+ * with Amendment 2
+ */
+extern char *dcngettext(const char *, const char *,
+ const char *, unsigned long int, int);
+extern char *dngettext(const char *, const char *,
+ const char *, unsigned long int);
+extern char *ngettext(const char *, const char *, unsigned long int);
+extern char *bind_textdomain_codeset(const char *, const char *);
+
+/* Word handling functions --- requires dynamic linking */
+/* Warning: these are experimental and subject to change. */
+extern int wdinit(void);
+extern int wdchkind(wchar_t);
+extern int wdbindf(wchar_t, wchar_t, int);
+extern wchar_t *wddelim(wchar_t, wchar_t, int);
+extern wchar_t mcfiller(void);
+extern int mcwrap(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBINTL_H */
diff --git a/cddl/contrib/opensolaris/head/nlist.h b/cddl/contrib/opensolaris/head/nlist.h
new file mode 100644
index 000000000000..de6be5e18444
--- /dev/null
+++ b/cddl/contrib/opensolaris/head/nlist.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ *
+ * 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 2014 Garrett D'Amore <garrett@damore.org>
+ */
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+#ifndef _NLIST_H
+#define _NLIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nlist {
+ char *n_name; /* symbol name */
+ long n_value; /* value of symbol */
+ short n_scnum; /* section number */
+ unsigned short n_type; /* type and derived type */
+ char n_sclass; /* storage class */
+ char n_numaux; /* number of aux. entries */
+};
+
+extern int nlist(const char *, struct nlist *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NLIST_H */
diff --git a/cddl/contrib/opensolaris/head/note.h b/cddl/contrib/opensolaris/head/note.h
new file mode 100644
index 000000000000..6c73867a0275
--- /dev/null
+++ b/cddl/contrib/opensolaris/head/note.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1994 by Sun Microsystems, Inc.
+ */
+
+/*
+ * note.h: interface for annotating source with info for tools
+ *
+ * NOTE is the default interface, but if the identifier NOTE is in use for
+ * some other purpose, you may prepare a similar header file using your own
+ * identifier, mapping that identifier to _NOTE. Also, exported header
+ * files should *not* use NOTE, since the name may already be in use in
+ * a program's namespace. Rather, exported header files should include
+ * sys/note.h directly and use _NOTE. For consistency, all kernel source
+ * should use _NOTE.
+ */
+
+#ifndef _NOTE_H
+#define _NOTE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/note.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NOTE _NOTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NOTE_H */
diff --git a/cddl/contrib/opensolaris/head/stdio_ext.h b/cddl/contrib/opensolaris/head/stdio_ext.h
new file mode 100644
index 000000000000..839e05f7eebd
--- /dev/null
+++ b/cddl/contrib/opensolaris/head/stdio_ext.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _STDIO_EXT_H
+#define _STDIO_EXT_H
+
+#define enable_extended_FILE_stdio(x,y) (0)
+
+#endif
diff --git a/cddl/contrib/opensolaris/head/storclass.h b/cddl/contrib/opensolaris/head/storclass.h
new file mode 100644
index 000000000000..3cbfb8e48fbf
--- /dev/null
+++ b/cddl/contrib/opensolaris/head/storclass.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+#ifndef _STORCLASS_H
+#define _STORCLASS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * STORAGE CLASSES
+ */
+
+#define C_EFCN -1 /* physical end of function */
+#define C_NULL 0
+#define C_AUTO 1 /* automatic variable */
+#define C_EXT 2 /* external symbol */
+#define C_STAT 3 /* static */
+#define C_REG 4 /* register variable */
+#define C_EXTDEF 5 /* external definition */
+#define C_LABEL 6 /* label */
+#define C_ULABEL 7 /* undefined label */
+#define C_MOS 8 /* member of structure */
+#define C_ARG 9 /* function argument */
+#define C_STRTAG 10 /* structure tag */
+#define C_MOU 11 /* member of union */
+#define C_UNTAG 12 /* union tag */
+#define C_TPDEF 13 /* type definition */
+#define C_USTATIC 14 /* undefined static */
+#define C_ENTAG 15 /* enumeration tag */
+#define C_MOE 16 /* member of enumeration */
+#define C_REGPARM 17 /* register parameter */
+#define C_FIELD 18 /* bit field */
+#define C_BLOCK 100 /* ".bb" or ".eb" */
+#define C_FCN 101 /* ".bf" or ".ef" */
+#define C_EOS 102 /* end of structure */
+#define C_FILE 103 /* file name */
+
+/*
+ * The following storage class is a "dummy" used only by STS
+ * for line number entries reformatted as symbol table entries
+ */
+
+#define C_LINE 104
+#define C_ALIAS 105 /* duplicate tag */
+#define C_HIDDEN 106 /* special storage class for external */
+ /* symbols in dmert public libraries */
+#define C_SHADOW 107 /* shadow symbol */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STORCLASS_H */
diff --git a/cddl/contrib/opensolaris/head/syms.h b/cddl/contrib/opensolaris/head/syms.h
new file mode 100644
index 000000000000..d18dda2ff4a5
--- /dev/null
+++ b/cddl/contrib/opensolaris/head/syms.h
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+#ifndef _SYMS_H
+#define _SYMS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 2.8 */
+
+/* Storage Classes are defined in storclass.h */
+#include <storclass.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Number of characters in a symbol name */
+#define SYMNMLEN 8
+/* Number of characters in a file name */
+#define FILNMLEN 14
+/* Number of array dimensions in auxiliary entry */
+#define DIMNUM 4
+
+struct syment
+{
+ union
+ {
+ char _n_name[SYMNMLEN]; /* old COFF version */
+ struct
+ {
+ long _n_zeroes; /* new == 0 */
+ long _n_offset; /* offset into string table */
+ } _n_n;
+ char *_n_nptr[2]; /* allows for overlaying */
+ } _n;
+ unsigned long n_value; /* value of symbol */
+ short n_scnum; /* section number */
+ unsigned short n_type; /* type and derived type */
+ char n_sclass; /* storage class */
+ char n_numaux; /* number of aux. entries */
+};
+
+#define n_name _n._n_name
+#define n_nptr _n._n_nptr[1]
+#define n_zeroes _n._n_n._n_zeroes
+#define n_offset _n._n_n._n_offset
+
+/*
+ * Relocatable symbols have a section number of the
+ * section in which they are defined. Otherwise, section
+ * numbers have the following meanings:
+ */
+ /* undefined symbol */
+#define N_UNDEF 0
+ /* value of symbol is absolute */
+#define N_ABS -1
+ /* special debugging symbol -- value of symbol is meaningless */
+#define N_DEBUG -2
+ /* indicates symbol needs transfer vector (preload) */
+#define N_TV (unsigned short)-3
+
+ /* indicates symbol needs transfer vector (postload) */
+
+#define P_TV (unsigned short)-4
+
+/*
+ * The fundamental type of a symbol packed into the low
+ * 4 bits of the word.
+ */
+
+#define _EF ".ef"
+
+#define T_NULL 0
+#define T_ARG 1 /* function argument (only used by compiler) */
+#define T_CHAR 2 /* character */
+#define T_SHORT 3 /* short integer */
+#define T_INT 4 /* integer */
+#define T_LONG 5 /* long integer */
+#define T_FLOAT 6 /* floating point */
+#define T_DOUBLE 7 /* double word */
+#define T_STRUCT 8 /* structure */
+#define T_UNION 9 /* union */
+#define T_ENUM 10 /* enumeration */
+#define T_MOE 11 /* member of enumeration */
+#define T_UCHAR 12 /* unsigned character */
+#define T_USHORT 13 /* unsigned short */
+#define T_UINT 14 /* unsigned integer */
+#define T_ULONG 15 /* unsigned long */
+
+/*
+ * derived types are:
+ */
+
+#define DT_NON 0 /* no derived type */
+#define DT_PTR 1 /* pointer */
+#define DT_FCN 2 /* function */
+#define DT_ARY 3 /* array */
+
+/*
+ * type packing constants
+ */
+
+#define N_BTMASK 017
+#define N_TMASK 060
+#define N_TMASK1 0300
+#define N_TMASK2 0360
+#define N_BTSHFT 4
+#define N_TSHIFT 2
+
+/*
+ * MACROS
+ */
+
+ /* Basic Type of x */
+
+#define BTYPE(x) ((x) & N_BTMASK)
+
+ /* Is x a pointer ? */
+
+#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
+
+ /* Is x a function ? */
+
+#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
+
+ /* Is x an array ? */
+
+#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
+
+ /* Is x a structure, union, or enumeration TAG? */
+
+#define ISTAG(x) ((x) == C_STRTAG || (x) == C_UNTAG || (x) == C_ENTAG)
+
+#define INCREF(x) ((((x)&~N_BTMASK)<<N_TSHIFT)|(DT_PTR<<N_BTSHFT)|(x&N_BTMASK))
+
+#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
+
+/*
+ * AUXILIARY ENTRY FORMAT
+ */
+
+union auxent
+{
+ struct
+ {
+ long x_tagndx; /* str, un, or enum tag indx */
+ union
+ {
+ struct
+ {
+ unsigned short x_lnno; /* declaration line */
+ /* number */
+ unsigned short x_size; /* str, union, array */
+ /* size */
+ } x_lnsz;
+ long x_fsize; /* size of function */
+ } x_misc;
+ union
+ {
+ struct /* if ISFCN, tag, or .bb */
+ {
+ long x_lnnoptr; /* ptr to fcn line # */
+ long x_endndx; /* entry ndx past */
+ /* block end */
+ } x_fcn;
+ struct /* if ISARY, up to 4 dimen. */
+ {
+ unsigned short x_dimen[DIMNUM];
+ } x_ary;
+ } x_fcnary;
+ unsigned short x_tvndx; /* tv index */
+ } x_sym;
+ struct
+ {
+ char x_fname[FILNMLEN];
+ } x_file;
+ struct
+ {
+ long x_scnlen; /* section length */
+ unsigned short x_nreloc; /* number of reloc entries */
+ unsigned short x_nlinno; /* number of line numbers */
+ } x_scn;
+
+ struct
+ {
+ long x_tvfill; /* tv fill value */
+ unsigned short x_tvlen; /* length of .tv */
+ unsigned short x_tvran[2]; /* tv range */
+ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
+};
+
+#define SYMENT struct syment
+#define SYMESZ 18 /* sizeof(SYMENT) */
+
+#define AUXENT union auxent
+#define AUXESZ 18 /* sizeof(AUXENT) */
+
+/* Defines for "special" symbols */
+
+#define _ETEXT "etext"
+#define _EDATA "edata"
+#define _END "end"
+#define _START "_start"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYMS_H */
diff --git a/cddl/contrib/opensolaris/head/synch.h b/cddl/contrib/opensolaris/head/synch.h
new file mode 100644
index 000000000000..c0f68f12f008
--- /dev/null
+++ b/cddl/contrib/opensolaris/head/synch.h
@@ -0,0 +1,218 @@
+/*
+ * 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 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _SYNCH_H
+#define _SYNCH_H
+
+/*
+ * synch.h:
+ * definitions needed to use the thread synchronization interface
+ */
+
+#ifndef _ASM
+#include <sys/machlock.h>
+#include <sys/time_impl.h>
+#include <sys/synch.h>
+#endif /* _ASM */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ASM
+
+/*
+ * Semaphores
+ */
+typedef struct _sema {
+ /* this structure must be the same as sem_t in <semaphore.h> */
+ uint32_t count; /* semaphore count */
+ uint16_t type;
+ uint16_t magic;
+ upad64_t pad1[3]; /* reserved for a mutex_t */
+ upad64_t pad2[2]; /* reserved for a cond_t */
+} sema_t;
+
+/*
+ * POSIX.1c Note:
+ * POSIX.1c requires that <pthread.h> define the structures pthread_mutex_t
+ * and pthread_cond_t. These structures are identical to mutex_t (lwp_mutex_t)
+ * and cond_t (lwp_cond_t) which are defined in <synch.h>. A nested included
+ * of <synch.h> (to allow a "#typedef mutex_t pthread_mutex_t") would pull in
+ * non-posix symbols/constants violating the namespace restrictions. Hence,
+ * pthread_mutex_t/pthread_cond_t have been redefined in <pthread.h> (actually
+ * in <sys/types.h>). Any modifications done to mutex_t/lwp_mutex_t or
+ * cond_t/lwp_cond_t should also be done to pthread_mutex_t/pthread_cond_t.
+ */
+typedef lwp_mutex_t mutex_t;
+typedef lwp_cond_t cond_t;
+
+/*
+ * Readers/writer locks
+ *
+ * NOTE: The layout of this structure should be kept in sync with the layout
+ * of the correponding structure of pthread_rwlock_t in sys/types.h.
+ * Also, there is an identical structure for lwp_rwlock_t in <sys/synch.h>.
+ * Because we have to deal with C++, we cannot redefine this one as that one.
+ */
+typedef struct _rwlock {
+ int32_t readers; /* rwstate word */
+ uint16_t type;
+ uint16_t magic;
+ mutex_t mutex; /* used with process-shared rwlocks */
+ cond_t readercv; /* used only to indicate ownership */
+ cond_t writercv; /* used only to indicate ownership */
+} rwlock_t;
+
+int _lwp_mutex_lock(lwp_mutex_t *);
+int _lwp_mutex_unlock(lwp_mutex_t *);
+int _lwp_mutex_trylock(lwp_mutex_t *);
+int _lwp_cond_wait(lwp_cond_t *, lwp_mutex_t *);
+int _lwp_cond_timedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
+int _lwp_cond_reltimedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
+int _lwp_cond_signal(lwp_cond_t *);
+int _lwp_cond_broadcast(lwp_cond_t *);
+int _lwp_sema_init(lwp_sema_t *, int);
+int _lwp_sema_wait(lwp_sema_t *);
+int _lwp_sema_trywait(lwp_sema_t *);
+int _lwp_sema_post(lwp_sema_t *);
+int cond_init(cond_t *, int, void *);
+int cond_destroy(cond_t *);
+int cond_wait(cond_t *, mutex_t *);
+int cond_timedwait(cond_t *, mutex_t *, const timespec_t *);
+int cond_reltimedwait(cond_t *, mutex_t *, const timespec_t *);
+int cond_signal(cond_t *);
+int cond_broadcast(cond_t *);
+int mutex_init(mutex_t *, int, void *);
+int mutex_destroy(mutex_t *);
+int mutex_consistent(mutex_t *);
+int mutex_lock(mutex_t *);
+int mutex_trylock(mutex_t *);
+int mutex_unlock(mutex_t *);
+int rwlock_init(rwlock_t *, int, void *);
+int rwlock_destroy(rwlock_t *);
+int rw_rdlock(rwlock_t *);
+int rw_wrlock(rwlock_t *);
+int rw_unlock(rwlock_t *);
+int rw_tryrdlock(rwlock_t *);
+int rw_trywrlock(rwlock_t *);
+int sema_init(sema_t *, unsigned int, int, void *);
+int sema_destroy(sema_t *);
+int sema_wait(sema_t *);
+int sema_timedwait(sema_t *, const timespec_t *);
+int sema_reltimedwait(sema_t *, const timespec_t *);
+int sema_post(sema_t *);
+int sema_trywait(sema_t *);
+
+#endif /* _ASM */
+
+/* "Magic numbers" tagging synchronization object types */
+#define MUTEX_MAGIC _MUTEX_MAGIC
+#define SEMA_MAGIC _SEMA_MAGIC
+#define COND_MAGIC _COND_MAGIC
+#define RWL_MAGIC _RWL_MAGIC
+
+/*
+ * POSIX.1c Note:
+ * DEFAULTMUTEX is defined same as PTHREAD_MUTEX_INITIALIZER in <pthread.h>.
+ * DEFAULTCV is defined same as PTHREAD_COND_INITIALIZER in <pthread.h>.
+ * DEFAULTRWLOCK is defined same as PTHREAD_RWLOCK_INITIALIZER in <pthread.h>.
+ * Any changes to these macros should be reflected in <pthread.h>
+ */
+#define DEFAULTMUTEX \
+ {{0, 0, 0, {USYNC_THREAD}, MUTEX_MAGIC}, \
+ {{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
+#define SHAREDMUTEX \
+ {{0, 0, 0, {USYNC_PROCESS}, MUTEX_MAGIC}, \
+ {{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
+#define RECURSIVEMUTEX \
+ {{0, 0, 0, {USYNC_THREAD|LOCK_RECURSIVE}, MUTEX_MAGIC}, \
+ {{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
+#define ERRORCHECKMUTEX \
+ {{0, 0, 0, {USYNC_THREAD|LOCK_ERRORCHECK}, MUTEX_MAGIC}, \
+ {{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
+#define RECURSIVE_ERRORCHECKMUTEX \
+ {{0, 0, 0, {USYNC_THREAD|LOCK_RECURSIVE|LOCK_ERRORCHECK}, \
+ MUTEX_MAGIC}, {{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
+#define DEFAULTCV \
+ {{{0, 0, 0, 0}, USYNC_THREAD, COND_MAGIC}, 0}
+#define SHAREDCV \
+ {{{0, 0, 0, 0}, USYNC_PROCESS, COND_MAGIC}, 0}
+#define DEFAULTSEMA \
+ {0, USYNC_THREAD, SEMA_MAGIC, {0, 0, 0}, {0, 0}}
+#define SHAREDSEMA \
+ {0, USYNC_PROCESS, SEMA_MAGIC, {0, 0, 0}, {0, 0}}
+#define DEFAULTRWLOCK \
+ {0, USYNC_THREAD, RWL_MAGIC, DEFAULTMUTEX, DEFAULTCV, DEFAULTCV}
+#define SHAREDRWLOCK \
+ {0, USYNC_PROCESS, RWL_MAGIC, SHAREDMUTEX, SHAREDCV, SHAREDCV}
+
+/*
+ * Tests on lock states.
+ */
+#define SEMA_HELD(x) _sema_held(x)
+#define RW_READ_HELD(x) _rw_read_held(x)
+#define RW_WRITE_HELD(x) _rw_write_held(x)
+#define RW_LOCK_HELD(x) (RW_READ_HELD(x) || RW_WRITE_HELD(x))
+#define MUTEX_HELD(x) _mutex_held(x)
+
+/*
+ * The following definitions are for assertions which can be checked
+ * statically by tools like lock_lint. You can also define your own
+ * run-time test for each. If you don't, we define them to 1 so that
+ * such assertions simply pass.
+ */
+#ifndef NO_LOCKS_HELD
+#define NO_LOCKS_HELD 1
+#endif
+#ifndef NO_COMPETING_THREADS
+#define NO_COMPETING_THREADS 1
+#endif
+
+#ifndef _ASM
+
+/*
+ * The *_held() functions apply equally well to Solaris threads
+ * and to Posix threads synchronization objects, but the formal
+ * type declarations are different, so we just declare the argument
+ * to each *_held() function to be a void *, expecting that they will
+ * be called with the proper type of argument in each case.
+ */
+int _sema_held(void *); /* sema_t or sem_t */
+int _rw_read_held(void *); /* rwlock_t or pthread_rwlock_t */
+int _rw_write_held(void *); /* rwlock_t or pthread_rwlock_t */
+int _mutex_held(void *); /* mutex_t or pthread_mutex_t */
+
+/* Pause API */
+void smt_pause(void);
+
+#endif /* _ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYNCH_H */
diff --git a/cddl/contrib/opensolaris/head/thread.h b/cddl/contrib/opensolaris/head/thread.h
new file mode 100644
index 000000000000..be58e1cf4183
--- /dev/null
+++ b/cddl/contrib/opensolaris/head/thread.h
@@ -0,0 +1,104 @@
+/*
+ * 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 2014 Garrett D'Amore <garrett@damore.org>
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _THREAD_H
+#define _THREAD_H
+
+#include <pthread.h>
+#include <pthread_np.h>
+#include <assert.h>
+
+/*
+ * Compatibility thread stuff needed for Solaris -> Linux port
+ */
+
+typedef pthread_t thread_t;
+typedef pthread_mutex_t mutex_t;
+typedef pthread_cond_t cond_t;
+typedef pthread_rwlock_t rwlock_t;
+
+#define USYNC_THREAD 0
+
+#define thr_self() (unsigned long)pthread_self()
+#define thr_equal(a,b) pthread_equal(a,b)
+#define thr_join(t,d,s) pthread_join(t,s)
+#define thr_exit(r) pthread_exit(r)
+#define _mutex_init(l,f,a) pthread_mutex_init(l,NULL)
+#define _mutex_destroy(l) pthread_mutex_destroy(l)
+#define mutex_lock(l) pthread_mutex_lock(l)
+#define mutex_trylock(l) pthread_mutex_trylock(l)
+#define mutex_unlock(l) pthread_mutex_unlock(l)
+#define rwlock_init(l,f,a) pthread_rwlock_init(l,NULL)
+#define rwlock_destroy(l) pthread_rwlock_destroy(l)
+#define rw_rdlock(l) pthread_rwlock_rdlock(l)
+#define rw_wrlock(l) pthread_rwlock_wrlock(l)
+#define rw_tryrdlock(l) pthread_rwlock_tryrdlock(l)
+#define rw_trywrlock(l) pthread_rwlock_trywrlock(l)
+#define rw_unlock(l) pthread_rwlock_unlock(l)
+#define cond_init(l,f,a) pthread_cond_init(l,NULL)
+#define cond_destroy(l) pthread_cond_destroy(l)
+#define cond_wait(l,m) pthread_cond_wait(l,m)
+#define cond_signal(l) pthread_cond_signal(l)
+#define cond_broadcast(l) pthread_cond_broadcast(l)
+
+#define THR_BOUND 0x00000001 /* = PTHREAD_SCOPE_SYSTEM */
+#define THR_NEW_LWP 0x00000002
+#define THR_DETACHED 0x00000040 /* = PTHREAD_CREATE_DETACHED */
+#define THR_SUSPENDED 0x00000080
+#define THR_DAEMON 0x00000100
+
+static __inline int
+thr_create(void *stack_base, size_t stack_size, void *(*start_func) (void*),
+ void *arg, long flags, thread_t *new_thread_ID)
+{
+ pthread_t dummy;
+ int ret;
+
+ assert(stack_base == NULL);
+ assert(stack_size == 0);
+ assert((flags & ~THR_BOUND & ~THR_DETACHED) == 0);
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+
+ if (flags & THR_DETACHED)
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ if (new_thread_ID == NULL)
+ new_thread_ID = &dummy;
+
+ /* This function ignores the THR_BOUND flag, since NPTL doesn't seem to support PTHREAD_SCOPE_PROCESS */
+
+ ret = pthread_create(new_thread_ID, &attr, start_func, arg);
+
+ pthread_attr_destroy(&attr);
+
+ return (ret);
+}
+
+#endif /* _THREAD_H */
diff --git a/cddl/contrib/opensolaris/lib/libcmdutils/common/nicenum.c b/cddl/contrib/opensolaris/lib/libcmdutils/common/nicenum.c
new file mode 100644
index 000000000000..8e3202f79270
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libcmdutils/common/nicenum.c
@@ -0,0 +1,130 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Jason king
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/debug.h>
+#include "libcmdutils.h"
+
+/* The largest suffix that can fit, aka an exabyte (2^60 / 10^18) */
+#define INDEX_MAX (6)
+
+/* Verify INDEX_MAX fits */
+CTASSERT(INDEX_MAX * 10 < sizeof (uint64_t) * 8);
+
+void
+nicenum_scale(uint64_t n, size_t units, char *buf, size_t buflen,
+ uint32_t flags)
+{
+ uint64_t divamt = 1024;
+ uint64_t divisor = 1;
+ int index = 0;
+ int rc = 0;
+ char u;
+
+ if (units == 0)
+ units = 1;
+
+ if (n > 0) {
+ n *= units;
+ if (n < units)
+ goto overflow;
+ }
+
+ if (flags & NN_DIVISOR_1000)
+ divamt = 1000;
+
+ /*
+ * This tries to find the suffix S(n) such that
+ * S(n) <= n < S(n+1), where S(n) = 2^(n*10) | 10^(3*n)
+ * (i.e. 1024/1000, 1,048,576/1,000,000, etc). Stop once S(n)
+ * is the largest prefix supported (i.e. don't bother computing
+ * and checking S(n+1). Since INDEX_MAX should be the largest
+ * suffix that fits (currently an exabyte), S(INDEX_MAX + 1) is
+ * never checked as it would overflow.
+ */
+ while (index < INDEX_MAX) {
+ uint64_t newdiv = divisor * divamt;
+
+ /* CTASSERT() guarantee these never trip */
+ VERIFY3U(newdiv, >=, divamt);
+ VERIFY3U(newdiv, >=, divisor);
+
+ if (n < newdiv)
+ break;
+
+ divisor = newdiv;
+ index++;
+ }
+
+ u = " KMGTPE"[index];
+
+ if (index == 0) {
+ rc = snprintf(buf, buflen, "%llu", n);
+ } else if (n % divisor == 0) {
+ /*
+ * If this is an even multiple of the base, always display
+ * without any decimal precision.
+ */
+ rc = snprintf(buf, buflen, "%llu%c", n / divisor, u);
+ } else {
+ /*
+ * We want to choose a precision that reflects the best choice
+ * for fitting in 5 characters. This can get rather tricky
+ * when we have numbers that are very close to an order of
+ * magnitude. For example, when displaying 10239 (which is
+ * really 9.999K), we want only a single place of precision
+ * for 10.0K. We could develop some complex heuristics for
+ * this, but it's much easier just to try each combination
+ * in turn.
+ */
+ int i;
+ for (i = 2; i >= 0; i--) {
+ if ((rc = snprintf(buf, buflen, "%.*f%c", i,
+ (double)n / divisor, u)) <= 5)
+ break;
+ }
+ }
+
+ if (rc + 1 > buflen || rc < 0)
+ goto overflow;
+
+ return;
+
+overflow:
+ /* prefer a more verbose message if possible */
+ if (buflen > 10)
+ (void) strlcpy(buf, "<overflow>", buflen);
+ else
+ (void) strlcpy(buf, "??", buflen);
+}
+
+void
+nicenum(uint64_t num, char *buf, size_t buflen)
+{
+ nicenum_scale(num, 1, buf, buflen, 0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libcmdutils/libcmdutils.h b/cddl/contrib/opensolaris/lib/libcmdutils/libcmdutils.h
new file mode 100644
index 000000000000..fffdd9de22f1
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libcmdutils/libcmdutils.h
@@ -0,0 +1,235 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013 RackTop Systems.
+ */
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
+/*
+ * Declarations for the functions in libcmdutils.
+ */
+
+#ifndef _LIBCMDUTILS_H
+#define _LIBCMDUTILS_H
+
+#ifdef illumos
+#if !defined(_LP64) && \
+ !((_FILE_OFFSET_BITS == 64) || defined(_LARGEFILE64_SOURCE))
+#error "libcmdutils.h can only be used in a largefile compilation environment"
+#endif
+#endif
+
+/*
+ * This is a private header file. Applications should not directly include
+ * this file.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <libintl.h>
+#include <string.h>
+#include <dirent.h>
+#ifdef illumos
+#include <attr.h>
+#endif
+#include <sys/avl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <libnvpair.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* extended system attribute support */
+#define _NOT_SATTR 0
+#define _RO_SATTR 1
+#define _RW_SATTR 2
+
+#define MAXMAPSIZE (1024*1024*8) /* map at most 8MB */
+#define SMALLFILESIZE (32*1024) /* don't use mmap on little file */
+
+/* Type used for a node containing a device id and inode number */
+
+#if defined(_LP64) || (_FILE_OFFSET_BITS == 64)
+typedef struct tree_node {
+ dev_t node_dev;
+ ino_t node_ino;
+ avl_node_t avl_link;
+} tree_node_t;
+#else
+typedef struct tree_node {
+ dev_t node_dev;
+ ino64_t node_ino;
+ avl_node_t avl_link;
+} tree_node_t;
+#endif
+
+ /* extended system attribute support */
+
+/* Determine if a file is the name of an extended system attribute file */
+extern int sysattr_type(char *);
+
+/* Determine if the underlying file system supports system attributes */
+extern int sysattr_support(char *, int);
+
+/* Copies the content of the source file to the target file */
+#if defined(_LP64) || (_FILE_OFFSET_BITS == 64)
+extern int writefile(int, int, char *, char *, char *, char *,
+ struct stat *, struct stat *);
+#else
+extern int writefile(int, int, char *, char *, char *, char *,
+ struct stat64 *, struct stat64 *);
+#endif
+
+/* Gets file descriptors of the source and target attribute files */
+extern int get_attrdirs(int, int, char *, int *, int *);
+
+/* Move extended attribute and extended system attribute */
+extern int mv_xattrs(char *, char *, char *, int, int);
+
+/* Returns non default extended system attribute list */
+extern nvlist_t *sysattr_list(char *, int, char *);
+
+
+
+ /* avltree */
+
+/*
+ * Used to compare two nodes. We are attempting to match the 1st
+ * argument (node) against the 2nd argument (a node which
+ * is already in the search tree).
+ */
+
+extern int tnode_compare(const void *, const void *);
+
+/*
+ * Used to add a single node (containing the input device id and
+ * inode number) to the specified search tree. The calling
+ * application must set the tree pointer to NULL before calling
+ * add_tnode() for the first time.
+ */
+#if defined(_LP64) || (_FILE_OFFSET_BITS == 64)
+extern int add_tnode(avl_tree_t **, dev_t, ino_t);
+#else
+extern int add_tnode(avl_tree_t **, dev_t, ino64_t);
+#endif
+
+/*
+ * Used to destroy a whole tree (all nodes) without rebalancing.
+ * The calling application is responsible for setting the tree
+ * pointer to NULL upon return.
+ */
+extern void destroy_tree(avl_tree_t *);
+
+
+
+ /* user/group id helpers */
+
+/*
+ * Used to get the next available user id in given range.
+ */
+extern int findnextuid(uid_t, uid_t, uid_t *);
+
+/*
+ * Used to get the next available group id in given range.
+ */
+extern int findnextgid(gid_t, gid_t, gid_t *);
+
+
+
+ /* dynamic string utilities */
+
+typedef struct custr custr_t;
+
+/*
+ * Allocate and free a "custr_t" dynamic string object. Returns 0 on success
+ * and -1 otherwise.
+ */
+extern int custr_alloc(custr_t **);
+extern void custr_free(custr_t *);
+
+/*
+ * Allocate a "custr_t" dynamic string object that operates on a fixed external
+ * buffer.
+ */
+extern int custr_alloc_buf(custr_t **, void *, size_t);
+
+/*
+ * Append a single character, or a NUL-terminated string of characters, to a
+ * dynamic string. Returns 0 on success and -1 otherwise. The dynamic string
+ * will be unmodified if the function returns -1.
+ */
+extern int custr_appendc(custr_t *, char);
+extern int custr_append(custr_t *, const char *);
+
+/*
+ * Append a format string and arguments as though the contents were being parsed
+ * through snprintf. Returns 0 on success and -1 otherwise. The dynamic string
+ * will be unmodified if the function returns -1.
+ */
+extern int custr_append_printf(custr_t *, const char *, ...);
+extern int custr_append_vprintf(custr_t *, const char *, va_list);
+
+/*
+ * Determine the length in bytes, not including the NUL terminator, of the
+ * dynamic string.
+ */
+extern size_t custr_len(custr_t *);
+
+/*
+ * Clear the contents of a dynamic string. Does not free the underlying
+ * memory.
+ */
+extern void custr_reset(custr_t *);
+
+/*
+ * Retrieve a const pointer to a NUL-terminated string version of the contents
+ * of the dynamic string. Storage for this string should not be freed, and
+ * the pointer will be invalidated by any mutations to the dynamic string.
+ */
+extern const char *custr_cstr(custr_t *str);
+
+#define NN_DIVISOR_1000 (1U << 0)
+
+/* Minimum size for the output of nicenum, including NULL */
+#define NN_NUMBUF_SZ (6)
+
+void nicenum(uint64_t, char *, size_t);
+void nicenum_scale(uint64_t, size_t, char *, size_t, uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBCMDUTILS_H */
diff --git a/cddl/contrib/opensolaris/lib/libctf/common/ctf.5 b/cddl/contrib/opensolaris/lib/libctf/common/ctf.5
new file mode 100644
index 000000000000..d9f41de6a9ca
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libctf/common/ctf.5
@@ -0,0 +1,1224 @@
+.\"
+.\" This file and its contents are supplied under the terms of the
+.\" Common Development and Distribution License ("CDDL"), version 1.0.
+.\" You may only use this file in accordance with the terms of version
+.\" 1.0 of the CDDL.
+.\"
+.\" A full copy of the text of the CDDL should have accompanied this
+.\" source. A copy of the CDDL is also available via the Internet at
+.\" http://www.illumos.org/license/CDDL.
+.\"
+.\"
+.\" Copyright (c) 2014 Joyent, Inc.
+.\"
+.Dd Sep 26, 2014
+.Dt CTF 5
+.Os
+.Sh NAME
+.Nm ctf
+.Nd Compact C Type Format
+.Sh SYNOPSIS
+.In sys/ctf.h
+.Sh DESCRIPTION
+.Nm
+is designed to be a compact representation of the C programming
+language's type information focused on serving the needs of dynamic
+tracing, debuggers, and other in-situ and post-mortem introspection
+tools.
+.Nm
+data is generally included in
+.Sy ELF
+objects and is tagged as
+.Sy SHT_PROGBITS
+to ensure that the data is accessible in a running process and in subsequent
+core dumps, if generated.
+.Lp
+The
+.Nm
+data contained in each file has information about the layout and
+sizes of C types, including intrinsic types, enumerations, structures,
+typedefs, and unions, that are used by the corresponding
+.Sy ELF
+object.
+The
+.Nm
+data may also include information about the types of global objects and
+the return type and arguments of functions in the symbol table.
+.Lp
+Because a
+.Nm
+file is often embedded inside a file, rather than being a standalone
+file itself, it may also be referred to as a
+.Nm
+.Sy container .
+.Lp
+On
+.Fx
+systems,
+.Nm
+data is consumed by
+.Xr dtrace 1 .
+Programmatic access to
+.Nm
+data can be obtained through libctf.
+.Lp
+The
+.Nm
+file format is broken down into seven different sections.
+The first section is the
+.Sy preamble
+and
+.Sy header ,
+which describes the version of the
+.Nm
+file, the links it has to other
+.Nm
+files, and the sizes of the other sections.
+The next section is the
+.Sy label
+section,
+which provides a way of identifying similar groups of
+.Nm
+data across multiple files.
+This is followed by the
+.Sy object
+information section, which describes the types of global
+symbols.
+The subsequent section is the
+.Sy function
+information section, which describes the return
+types and arguments of functions.
+The next section is the
+.Sy type
+information section, which describes
+the format and layout of the C types themselves, and finally the last
+section is the
+.Sy string
+section, which contains the names of types, enumerations, members, and
+labels.
+.Lp
+While strictly speaking, only the
+.Sy preamble
+and
+.Sy header
+are required, to be actually useful, both the type and string
+sections are necessary.
+.Lp
+A
+.Nm
+file may contain all of the type information that it requires, or it
+may optionally refer to another
+.Nm
+file which holds the remaining types.
+When a
+.Nm
+file refers to another file, it is called the
+.Sy child
+and the file it refers to is called the
+.Sy parent .
+A given file may only refer to one parent.
+This process is called
+.Em uniquification
+because it ensures each child only has type information that is
+unique to it.
+A common example of this is that most kernel modules in illumos are uniquified
+against the kernel module
+.Sy genunix
+and the type information that comes from the
+.Sy IP
+module.
+This means that a module only has types that are unique to itself and the most
+common types in the kernel are not duplicated.
+.Sh FILE FORMAT
+This documents version
+.Em two
+of the
+.Nm
+file format.
+All applications and tools on
+.Fx
+currently produce and operate on this version.
+.Lp
+The file format can be summarized with the following image, the
+following sections will cover this in more detail.
+.Bd -literal
+
+ +-------------+ 0t0
++--------| Preamble |
+| +-------------+ 0t4
+|+-------| Header |
+|| +-------------+ 0t36 + cth_lbloff
+||+------| Labels |
+||| +-------------+ 0t36 + cth_objtoff
+|||+-----| Objects |
+|||| +-------------+ 0t36 + cth_funcoff
+||||+----| Functions |
+||||| +-------------+ 0t36 + cth_typeoff
+|||||+---| Types |
+|||||| +-------------+ 0t36 + cth_stroff
+||||||+--| Strings |
+||||||| +-------------+ 0t36 + cth_stroff + cth_strlen
+|||||||
+|||||||
+|||||||
+||||||| +-- magic - vers flags
+||||||| | | | |
+||||||| +------+------+------+------+
++---------| 0xcf | 0xf1 | 0x02 | 0x00 |
+ |||||| +------+------+------+------+
+ |||||| 0 1 2 3 4
+ ||||||
+ |||||| + parent label + objects
+ |||||| | + parent name | + functions + strings
+ |||||| | | + label | | + types | + strlen
+ |||||| | | | | | | | |
+ |||||| +------+------+------+------+------+-------+-------+-------+
+ +--------| 0x00 | 0x00 | 0x00 | 0x08 | 0x36 | 0x110 | 0x5f4 | 0x611 |
+ ||||| +------+------+------+------+------+-------+-------+-------+
+ ||||| 0x04 0x08 0x0c 0x10 0x14 0x18 0x1c 0x20 0x24
+ |||||
+ ||||| + Label name
+ ||||| | + Label type
+ ||||| | | + Next label
+ ||||| | | |
+ ||||| +-------+------+-----+
+ +-----------| 0x01 | 0x42 | ... |
+ |||| +-------+------+-----+
+ |||| cth_lbloff +0x4 +0x8 cth_objtoff
+ ||||
+ ||||
+ |||| Symidx 0t15 0t43 0t44
+ |||| +------+------+------+-----+
+ +----------| 0x00 | 0x42 | 0x36 | ... |
+ ||| +------+------+------+-----+
+ ||| cth_objtoff +0x2 +0x4 +0x6 cth_funcoff
+ |||
+ ||| + CTF_TYPE_INFO + CTF_TYPE_INFO
+ ||| | + Return type |
+ ||| | | + arg0 |
+ ||| +--------+------+------+-----+
+ +---------| 0x2c10 | 0x08 | 0x0c | ... |
+ || +--------+------+------+-----+
+ || cth_funcff +0x2 +0x4 +0x6 cth_typeoff
+ ||
+ || + ctf_stype_t for type 1
+ || | integer + integer encoding
+ || | | + ctf_stype_t for type 2
+ || | | |
+ || +--------------------+-----------+-----+
+ +--------| 0x19 * 0xc01 * 0x0 | 0x1000000 | ... |
+ | +--------------------+-----------+-----+
+ | cth_typeoff +0x08 +0x0c cth_stroff
+ |
+ | +--- str 0
+ | | +--- str 1 + str 2
+ | | | |
+ | v v v
+ | +----+---+---+---+----+---+---+---+---+---+----+
+ +---| \\0 | i | n | t | \\0 | f | o | o | _ | t | \\0 |
+ +----+---+---+---+----+---+---+---+---+---+----+
+ 0 1 2 3 4 5 6 7 8 9 10 11
+.Ed
+.Lp
+Every
+.Nm
+file begins with a
+.Sy preamble ,
+followed by a
+.Sy header .
+The
+.Sy preamble
+is defined as follows:
+.Bd -literal
+typedef struct ctf_preamble {
+ uint16_t ctp_magic; /* magic number (CTF_MAGIC) */
+ uint8_t ctp_version; /* data format version number (CTF_VERSION) */
+ uint8_t ctp_flags; /* flags (see below) */
+} ctf_preamble_t;
+.Ed
+.Pp
+The
+.Sy preamble
+is four bytes long and must be four byte aligned.
+This
+.Sy preamble
+defines the version of the
+.Nm
+file which defines the format of the rest of the header.
+While the header may change in subsequent versions, the preamble will not change
+across versions, though the interpretation of its flags may change from
+version to version.
+The
+.Em ctp_magic
+member defines the magic number for the
+.Nm
+file format.
+This must always be
+.Li 0xcff1 .
+If another value is encountered, then the file should not be treated as
+a
+.Nm
+file.
+The
+.Em ctp_version
+member defines the version of the
+.Nm
+file.
+The current version is
+.Li 2 .
+It is possible to encounter an unsupported version.
+In that case, software should not try to parse the format, as it may have
+changed.
+Finally, the
+.Em ctp_flags
+member describes aspects of the file which modify its interpretation.
+The following flags are currently defined:
+.Bd -literal
+#define CTF_F_COMPRESS 0x01
+.Ed
+.Pp
+The flag
+.Sy CTF_F_COMPRESS
+indicates that the body of the
+.Nm
+file, all the data following the
+.Sy header ,
+has been compressed through the
+.Sy zlib
+library and its
+.Sy deflate
+algorithm.
+If this flag is not present, then the body has not been compressed and no
+special action is needed to interpret it.
+All offsets into the data as described by
+.Sy header ,
+always refer to the
+.Sy uncompressed
+data.
+.Lp
+In version two of the
+.Nm
+file format, the
+.Sy header
+denotes whether or not this
+.Nm
+file is the child of another
+.Nm
+file and also indicates the size of the remaining sections.
+The structure for the
+.Sy header
+logically contains a copy of the
+.Sy preamble
+and the two have a combined size of 36 bytes.
+.Bd -literal
+typedef struct ctf_header {
+ ctf_preamble_t cth_preamble;
+ uint32_t cth_parlabel; /* ref to name of parent lbl uniq'd against */
+ uint32_t cth_parname; /* ref to basename of parent */
+ uint32_t cth_lbloff; /* offset of label section */
+ uint32_t cth_objtoff; /* offset of object section */
+ uint32_t cth_funcoff; /* offset of function section */
+ uint32_t cth_typeoff; /* offset of type section */
+ uint32_t cth_stroff; /* offset of string section */
+ uint32_t cth_strlen; /* length of string section in bytes */
+} ctf_header_t;
+.Ed
+.Pp
+After the
+.Sy preamble ,
+the next two members
+.Em cth_parlablel
+and
+.Em cth_parname ,
+are used to identify the parent.
+The value of both members are offsets into the
+.Sy string
+section which point to the start of a null-terminated string.
+For more information on the encoding of strings, see the subsection on
+.Sx String Identifiers .
+If the value of either is zero, then there is no entry for that
+member.
+If the member
+.Em cth_parlabel
+is set, then the
+.Em ctf_parname
+member must be set, otherwise it will not be possible to find the
+parent.
+If
+.Em ctf_parname
+is set, it is not necessary to define
+.Em cth_parlabel ,
+as the parent may not have a label.
+For more information on labels and their interpretation, see
+.Sx The Label Section .
+.Lp
+The remaining members (excepting
+.Em cth_strlen )
+describe the beginning of the corresponding sections.
+These offsets are relative to the end of the
+.Sy header .
+Therefore, something with an offset of 0 is at an offset of thirty-six
+bytes relative to the start of the
+.Nm
+file.
+The difference between members indicates the size of the section itself.
+Different offsets have different alignment requirements.
+The start of the
+.Em cth_objotoff
+and
+.Em cth_funcoff
+must be two byte aligned, while the sections
+.Em cth_lbloff
+and
+.Em cth_typeoff
+must be four-byte aligned.
+The section
+.Em cth_stroff
+has no alignment requirements.
+To calculate the size of a given section, excepting the
+.Sy string
+section, one should subtract the offset of the section from the following one.
+For example, the size of the
+.Sy types
+section can be calculated by subtracting
+.Em cth_stroff
+from
+.Em cth_typeoff .
+.Lp
+Finally, the member
+.Em cth_strlen
+describes the length of the string section itself.
+From it, you can also calculate the size of the entire
+.Nm
+file by adding together the size of the
+.Sy ctf_header_t ,
+the offset of the string section in
+.Em cth_stroff ,
+and the size of the string section in
+.Em cth_srlen .
+.Ss Type Identifiers
+Through the
+.Nm ctf
+data, types are referred to by identifiers.
+A given
+.Nm
+file supports up to 32767 (0x7fff) types.
+The first valid type identifier is 0x1.
+When a given
+.Nm
+file is a child, indicated by a non-zero entry for the
+.Sy header Ns 's
+.Em cth_parname ,
+then the first valid type identifier is 0x8000 and the last is 0xffff.
+In this case, type identifiers 0x1 through 0x7fff are references to the
+parent.
+.Lp
+The type identifier zero is a sentinel value used to indicate that there
+is no type information available or it is an unknown type.
+.Lp
+Throughout the file format, the identifier is stored in different sized
+values; however, the minimum size to represent a given identifier is a
+.Sy uint16_t .
+Other consumers of
+.Nm
+information may use larger or opaque identifiers.
+.Ss String Identifiers
+String identifiers are always encoded as four byte unsigned integers
+which are an offset into a string table.
+The
+.Nm
+format supports two different string tables which have an identifier of
+zero or one.
+This identifier is stored in the high-order bit of the unsigned four byte
+offset.
+Therefore, the maximum supported offset into one of these tables is 0x7ffffffff.
+.Lp
+Table identifier zero, always refers to the
+.Sy string
+section in the CTF file itself.
+String table identifier one refers to an external string table which is the ELF
+string table for the ELF symbol table associated with the
+.Nm
+container.
+.Ss Type Encoding
+Every
+.Nm
+type begins with metadata encoded into a
+.Sy uint16_t .
+This encoded information tells us three different pieces of information:
+.Bl -bullet -offset indent -compact
+.It
+The kind of the type
+.It
+Whether this type is a root type or not
+.It
+The length of the variable data
+.El
+.Lp
+The 16 bits that make up the encoding are broken down such that you have
+five bits for the kind, one bit for indicating whether or not it is a
+root type, and 10 bits for the variable length.
+This is laid out as follows:
+.Bd -literal -offset indent
++--------------------+
+| kind | root | vlen |
++--------------------+
+15 11 10 9 0
+.Ed
+.Lp
+The current version of the file format defines 14 different kinds.
+The interpretation of these different kinds will be discussed in the section
+.Sx The Type Section .
+If a kind is encountered that is not listed below, then it is not a valid
+.Nm
+file.
+The kinds are defined as follows:
+.Bd -literal -offset indent
+#define CTF_K_UNKNOWN 0
+#define CTF_K_INTEGER 1
+#define CTF_K_FLOAT 2
+#define CTF_K_POINTER 3
+#define CTF_K_ARRAY 4
+#define CTF_K_FUNCTION 5
+#define CTF_K_STRUCT 6
+#define CTF_K_UNION 7
+#define CTF_K_ENUM 8
+#define CTF_K_FORWARD 9
+#define CTF_K_TYPEDEF 10
+#define CTF_K_VOLATILE 11
+#define CTF_K_CONST 12
+#define CTF_K_RESTRICT 13
+.Ed
+.Lp
+Programs directly reference many types; however, other types are referenced
+indirectly because they are part of some other structure.
+These types that are referenced directly and used are called
+.Sy root
+types.
+Other types may be used indirectly, for example, a program may reference
+a structure directly, but not one of its members which has a type.
+That type is not considered a
+.Sy root
+type.
+If a type is a
+.Sy root
+type, then it will have bit 10 set.
+.Lp
+The variable length section is specific to each kind and is discussed in the
+section
+.Sx The Type Section .
+.Lp
+The following macros are useful for constructing and deconstructing the encoded
+type information:
+.Bd -literal -offset indent
+
+#define CTF_MAX_VLEN 0x3ff
+#define CTF_INFO_KIND(info) (((info) & 0xf800) >> 11)
+#define CTF_INFO_ISROOT(info) (((info) & 0x0400) >> 10)
+#define CTF_INFO_VLEN(info) (((info) & CTF_MAX_VLEN))
+
+#define CTF_TYPE_INFO(kind, isroot, vlen) \\
+ (((kind) << 11) | (((isroot) ? 1 : 0) << 10) | ((vlen) & CTF_MAX_VLEN))
+.Ed
+.Ss The Label Section
+When consuming
+.Nm
+data, it is often useful to know whether two different
+.Nm
+containers come from the same source base and version.
+For example, when building illumos, there are many kernel modules that are built
+against a single collection of source code.
+A label is encoded into the
+.Nm
+files that corresponds with the particular build.
+This ensures that if files on the system were to become mixed up from multiple
+releases, that they are not used together by tools, particularly when a child
+needs to refer to a type in the parent.
+Because they are linked using the type identifiers, if the wrong parent is used
+then the wrong type will be encountered.
+.Lp
+Each label is encoded in the file format using the following eight byte
+structure:
+.Bd -literal
+typedef struct ctf_lblent {
+ uint32_t ctl_label; /* ref to name of label */
+ uint32_t ctl_typeidx; /* last type associated with this label */
+} ctf_lblent_t;
+.Ed
+.Lp
+Each label has two different components, a name and a type identifier.
+The name is encoded in the
+.Em ctl_label
+member which is in the format defined in the section
+.Sx String Identifiers .
+Generally, the names of all labels are found in the internal string
+section.
+.Lp
+The type identifier encoded in the member
+.Em ctl_typeidx
+refers to the last type identifier that a label refers to in the current
+file.
+Labels only refer to types in the current file, if the
+.Nm
+file is a child, then it will have the same label as its parent;
+however, its label will only refer to its types, not its parent's.
+.Lp
+It is also possible, though rather uncommon, for a
+.Nm
+file to have multiple labels.
+Labels are placed one after another, every eight bytes.
+When multiple labels are present, types may only belong to a single label.
+.Ss The Object Section
+The object section provides a mapping from ELF symbols of type
+.Sy STT_OBJECT
+in the symbol table to a type identifier.
+Every entry in this section is a
+.Sy uint16_t
+which contains a type identifier as described in the section
+.Sx Type Identifiers .
+If there is no information for an object, then the type identifier 0x0
+is stored for that entry.
+.Lp
+To walk the object section, you need to have a corresponding
+.Sy symbol table
+in the ELF object that contains the
+.Nm
+data.
+Not every object is included in this section.
+Specifically, when walking the symbol table, an entry is skipped if it matches
+any of the following conditions:
+.Lp
+.Bl -bullet -offset indent -compact
+.It
+The symbol type is not
+.Sy STT_OBJECT
+.It
+The symbol's section index is
+.Sy SHN_UNDEF
+.It
+The symbol's name offset is zero
+.It
+The symbol's section index is
+.Sy SHN_ABS
+and the value of the symbol is zero.
+.It
+The symbol's name is
+.Li _START_
+or
+.Li _END_ .
+These are skipped because they are used for scoping local symbols in
+ELF.
+.El
+.Lp
+The following sample code shows an example of iterating the object
+section and skipping the correct symbols:
+.Bd -literal
+#include <gelf.h>
+#include <stdio.h>
+
+/*
+ * Given the start of the object section in the CTF file, the number of symbols,
+ * and the ELF Data sections for the symbol table and the string table, this
+ * prints the type identifiers that correspond to objects. Note, a more robust
+ * implementation should ensure that they don't walk beyond the end of the CTF
+ * object section.
+ */
+static int
+walk_symbols(uint16_t *objtoff, Elf_Data *symdata, Elf_Data *strdata,
+ long nsyms)
+{
+ long i;
+ uintptr_t strbase = strdata->d_buf;
+
+ for (i = 1; i < nsyms; i++, objftoff++) {
+ const char *name;
+ GElf_Sym sym;
+
+ if (gelf_getsym(symdata, i, &sym) == NULL)
+ return (1);
+
+ if (GELF_ST_TYPE(sym.st_info) != STT_OBJECT)
+ continue;
+ if (sym.st_shndx == SHN_UNDEF || sym.st_name == 0)
+ continue;
+ if (sym.st_shndx == SHN_ABS && sym.st_value == 0)
+ continue;
+ name = (const char *)(strbase + sym.st_name);
+ if (strcmp(name, "_START_") == 0 || strcmp(name, "_END_") == 0)
+ continue;
+
+ (void) printf("Symbol %d has type %d\n", i, *objtoff);
+ }
+
+ return (0);
+}
+.Ed
+.Ss The Function Section
+The function section of the
+.Nm
+file encodes the types of both the function's arguments and the function's
+return value.
+Similar to
+.Sx The Object Section ,
+the function section encodes information for all symbols of type
+.Sy STT_FUNCTION ,
+excepting those that fit specific criteria.
+Unlike with objects, because functions have a variable number of arguments, they
+start with a type encoding as defined in
+.Sx Type Encoding ,
+which is the size of a
+.Sy uint16_t .
+For functions which have no type information available, they are encoded as
+.Li CTF_TYPE_INFO(CTF_K_UNKNOWN, 0, 0) .
+Functions with arguments are encoded differently.
+Here, the variable length is turned into the number of arguments in the
+function.
+If a function is a
+.Sy varargs
+type function, then the number of arguments is increased by one.
+Functions with type information are encoded as:
+.Li CTF_TYPE_INFO(CTF_K_FUNCTION, 0, nargs) .
+.Lp
+For functions that have no type information, nothing else is encoded, and the
+next function is encoded.
+For functions with type information, the next
+.Sy uint16_t
+is encoded with the type identifier of the return type of the function.
+It is followed by each of the type identifiers of the arguments, if any exist,
+in the order that they appear in the function.
+Therefore, argument 0 is the first type identifier and so on.
+When a function has a final varargs argument, that is encoded with the type
+identifier of zero.
+.Lp
+Like
+.Sx The Object Section ,
+the function section is encoded in the order of the symbol table.
+It has similar, but slightly different considerations from objects.
+While iterating the symbol table, if any of the following conditions are true,
+then the entry is skipped and no corresponding entry is written:
+.Lp
+.Bl -bullet -offset indent -compact
+.It
+The symbol type is not
+.Sy STT_FUNCTION
+.It
+The symbol's section index is
+.Sy SHN_UNDEF
+.It
+The symbol's name offset is zero
+.It
+The symbol's name is
+.Li _START_
+or
+.Li _END_ .
+These are skipped because they are used for scoping local symbols in
+ELF.
+.El
+.Ss The Type Section
+The type section is the heart of the
+.Nm
+data.
+It encodes all of the information about the types themselves.
+The base of the type information comes in two forms, a short form and a long
+form, each of which may be followed by a variable number of arguments.
+The following definitions describe the short and long forms:
+.Bd -literal
+#define CTF_MAX_SIZE 0xfffe /* max size of a type in bytes */
+#define CTF_LSIZE_SENT 0xffff /* sentinel for ctt_size */
+#define CTF_MAX_LSIZE UINT64_MAX
+
+typedef struct ctf_stype {
+ uint32_t ctt_name; /* reference to name in string table */
+ uint16_t ctt_info; /* encoded kind, variant length */
+ union {
+ uint16_t _size; /* size of entire type in bytes */
+ uint16_t _type; /* reference to another type */
+ } _u;
+} ctf_stype_t;
+
+typedef struct ctf_type {
+ uint32_t ctt_name; /* reference to name in string table */
+ uint16_t ctt_info; /* encoded kind, variant length */
+ union {
+ uint16_t _size; /* always CTF_LSIZE_SENT */
+ uint16_t _type; /* do not use */
+ } _u;
+ uint32_t ctt_lsizehi; /* high 32 bits of type size in bytes */
+ uint32_t ctt_lsizelo; /* low 32 bits of type size in bytes */
+} ctf_type_t;
+
+#define ctt_size _u._size /* for fundamental types that have a size */
+#define ctt_type _u._type /* for types that reference another type */
+.Ed
+.Pp
+Type sizes are stored in
+.Sy bytes .
+The basic small form uses a
+.Sy uint16_t
+to store the number of bytes.
+If the number of bytes in a structure would exceed 0xfffe, then the alternate
+form, the
+.Sy ctf_type_t ,
+is used instead.
+To indicate that the larger form is being used, the member
+.Em ctt_size
+is set to value of
+.Sy CTF_LSIZE_SENT
+(0xffff).
+In general, when going through the type section, consumers use the
+.Sy ctf_type_t
+structure, but pay attention to the value of the member
+.Em ctt_size
+to determine whether they should increment their scan by the size of the
+.Sy ctf_stype_t
+or
+.Sy ctf_type_t .
+Not all kinds of types use
+.Sy ctt_size .
+Those which do not, will always use the
+.Sy ctf_stype_t
+structure.
+The individual sections for each kind have more information.
+.Lp
+Types are written out in order.
+Therefore the first entry encountered has a type id of 0x1, or 0x8000 if a
+child.
+The member
+.Em ctt_name
+is encoded as described in the section
+.Sx String Identifiers .
+The string that it points to is the name of the type.
+If the identifier points to an empty string (one that consists solely of a null
+terminator) then the type does not have a name, this is common with anonymous
+structures and unions that only have a typedef to name them, as well as
+pointers and qualifiers.
+.Lp
+The next member, the
+.Em ctt_info ,
+is encoded as described in the section
+.Sx Type Encoding .
+The type's kind tells us how to interpret the remaining data in the
+.Sy ctf_type_t
+and any variable length data that may exist.
+The rest of this section will be broken down into the interpretation of the
+various kinds.
+.Ss Encoding of Integers
+Integers, which are of type
+.Sy CTF_K_INTEGER ,
+have no variable length arguments.
+Instead, they are followed by a
+.Sy uint32_t
+which describes their encoding.
+All integers must be encoded with a variable length of zero.
+The
+.Em ctt_size
+member describes the length of the integer in bytes.
+In general, integer sizes will be rounded up to the closest power of two.
+.Lp
+The integer encoding contains three different pieces of information:
+.Bl -bullet -offset indent -compact
+.It
+The encoding of the integer
+.It
+The offset in
+.Sy bits
+of the type
+.It
+The size in
+.Sy bits
+of the type
+.El
+.Pp
+This encoding can be expressed through the following macros:
+.Bd -literal -offset indent
+#define CTF_INT_ENCODING(data) (((data) & 0xff000000) >> 24)
+#define CTF_INT_OFFSET(data) (((data) & 0x00ff0000) >> 16)
+#define CTF_INT_BITS(data) (((data) & 0x0000ffff))
+
+#define CTF_INT_DATA(encoding, offset, bits) \\
+ (((encoding) << 24) | ((offset) << 16) | (bits))
+.Ed
+.Pp
+The following flags are defined for the encoding at this time:
+.Bd -literal -offset indent
+#define CTF_INT_SIGNED 0x01
+#define CTF_INT_CHAR 0x02
+#define CTF_INT_BOOL 0x04
+#define CTF_INT_VARARGS 0x08
+.Ed
+.Lp
+By default, an integer is considered to be unsigned, unless it has the
+.Sy CTF_INT_SIGNED
+flag set.
+If the flag
+.Sy CTF_INT_CHAR
+is set, that indicates that the integer is of a type that stores character
+data, for example the intrinsic C type
+.Sy char
+would have the
+.Sy CTF_INT_CHAR
+flag set.
+If the flag
+.Sy CTF_INT_BOOL
+is set, that indicates that the integer represents a boolean type.
+For example, the intrinsic C type
+.Sy _Bool
+would have the
+.Sy CTF_INT_BOOL
+flag set.
+Finally, the flag
+.Sy CTF_INT_VARARGS
+indicates that the integer is used as part of a variable number of arguments.
+This encoding is rather uncommon.
+.Ss Encoding of Floats
+Floats, which are of type
+.Sy CTF_K_FLOAT ,
+are similar to their integer counterparts.
+They have no variable length arguments and are followed by a four byte encoding
+which describes the kind of float that exists.
+The
+.Em ctt_size
+member is the size, in bytes, of the float.
+The float encoding has three different pieces of information inside of it:
+.Lp
+.Bl -bullet -offset indent -compact
+.It
+The specific kind of float that exists
+.It
+The offset in
+.Sy bits
+of the float
+.It
+The size in
+.Sy bits
+of the float
+.El
+.Lp
+This encoding can be expressed through the following macros:
+.Bd -literal -offset indent
+#define CTF_FP_ENCODING(data) (((data) & 0xff000000) >> 24)
+#define CTF_FP_OFFSET(data) (((data) & 0x00ff0000) >> 16)
+#define CTF_FP_BITS(data) (((data) & 0x0000ffff))
+
+#define CTF_FP_DATA(encoding, offset, bits) \\
+ (((encoding) << 24) | ((offset) << 16) | (bits))
+.Ed
+.Lp
+Where as the encoding for integers is a series of flags, the encoding for
+floats maps to a specific kind of float.
+It is not a flag-based value.
+The kinds of floats correspond to both their size, and the encoding.
+This covers all of the basic C intrinsic floating point types.
+The following are the different kinds of floats represented in the encoding:
+.Bd -literal -offset indent
+#define CTF_FP_SINGLE 1 /* IEEE 32-bit float encoding */
+#define CTF_FP_DOUBLE 2 /* IEEE 64-bit float encoding */
+#define CTF_FP_CPLX 3 /* Complex encoding */
+#define CTF_FP_DCPLX 4 /* Double complex encoding */
+#define CTF_FP_LDCPLX 5 /* Long double complex encoding */
+#define CTF_FP_LDOUBLE 6 /* Long double encoding */
+#define CTF_FP_INTRVL 7 /* Interval (2x32-bit) encoding */
+#define CTF_FP_DINTRVL 8 /* Double interval (2x64-bit) encoding */
+#define CTF_FP_LDINTRVL 9 /* Long double interval (2x128-bit) encoding */
+#define CTF_FP_IMAGRY 10 /* Imaginary (32-bit) encoding */
+#define CTF_FP_DIMAGRY 11 /* Long imaginary (64-bit) encoding */
+#define CTF_FP_LDIMAGRY 12 /* Long double imaginary (128-bit) encoding */
+.Ed
+.Ss Encoding of Arrays
+Arrays, which are of type
+.Sy CTF_K_ARRAY ,
+have no variable length arguments.
+They are followed by a structure which describes the number of elements in the
+array, the type identifier of the elements in the array, and the type identifier
+of the index of the array.
+With arrays, the
+.Em ctt_size
+member is set to zero.
+The structure that follows an array is defined as:
+.Bd -literal
+typedef struct ctf_array {
+ uint16_t cta_contents; /* reference to type of array contents */
+ uint16_t cta_index; /* reference to type of array index */
+ uint32_t cta_nelems; /* number of elements */
+} ctf_array_t;
+.Ed
+.Lp
+The
+.Em cta_contents
+and
+.Em cta_index
+members of the
+.Sy ctf_array_t
+are type identifiers which are encoded as per the section
+.Sx Type Identifiers .
+The member
+.Em cta_nelems
+is a simple four byte unsigned count of the number of elements.
+This count may be zero when encountering C99's flexible array members.
+.Ss Encoding of Functions
+Function types, which are of type
+.Sy CTF_K_FUNCTION ,
+use the variable length list to be the number of arguments in the function.
+When the function has a final member which is a varargs, then the argument count
+is incremented by one to account for the variable argument.
+Here, the
+.Em ctt_type
+member is encoded with the type identifier of the return type of the function.
+Note that the
+.Em ctt_size
+member is not used here.
+.Lp
+The variable argument list contains the type identifiers for the arguments of
+the function, if any.
+Each one is represented by a
+.Sy uint16_t
+and encoded according to the
+.Sx Type Identifiers
+section.
+If the function's last argument is of type varargs, then it is also written out,
+but the type identifier is zero.
+This is included in the count of the function's arguments.
+An extra type identifier may follow the argument and return type identifiers
+in order to maintain four-byte alignment for the following type definition.
+Such a type identifier is not included in the argument count and has a value
+of zero.
+.Ss Encoding of Structures and Unions
+Structures and Unions, which are encoded with
+.Sy CTF_K_STRUCT
+and
+.Sy CTF_K_UNION
+respectively, are very similar constructs in C.
+The main difference between them is the fact that members of a structure
+follow one another, where as in a union, all members share the same memory.
+They are also very similar in terms of their encoding in
+.Nm .
+The variable length argument for structures and unions represents the number of
+members that they have.
+The value of the member
+.Em ctt_size
+is the size of the structure and union.
+There are two different structures which are used to encode members in the
+variable list.
+When the size of a structure or union is greater than or equal to the large
+member threshold, 8192, then a different structure is used to encode the member,
+all members are encoded using the same structure.
+The structure for members is as follows:
+.Bd -literal
+typedef struct ctf_member {
+ uint32_t ctm_name; /* reference to name in string table */
+ uint16_t ctm_type; /* reference to type of member */
+ uint16_t ctm_offset; /* offset of this member in bits */
+} ctf_member_t;
+
+typedef struct ctf_lmember {
+ uint32_t ctlm_name; /* reference to name in string table */
+ uint16_t ctlm_type; /* reference to type of member */
+ uint16_t ctlm_pad; /* padding */
+ uint32_t ctlm_offsethi; /* high 32 bits of member offset in bits */
+ uint32_t ctlm_offsetlo; /* low 32 bits of member offset in bits */
+} ctf_lmember_t;
+.Ed
+.Lp
+Both the
+.Em ctm_name
+and
+.Em ctlm_name
+refer to the name of the member.
+The name is encoded as an offset into the string table as described by the
+section
+.Sx String Identifiers .
+The members
+.Sy ctm_type
+and
+.Sy ctlm_type
+both refer to the type of the member.
+They are encoded as per the section
+.Sx Type Identifiers .
+.Lp
+The last piece of information that is present is the offset which describes the
+offset in memory at which the member begins.
+For unions, this value will always be zero because each member of a union has
+an offset of zero.
+For structures, this is the offset in
+.Sy bits
+at which the member begins.
+Note that a compiler may lay out a type with padding.
+This means that the difference in offset between two consecutive members may be
+larger than the size of the member.
+When the size of the overall structure is strictly less than 8192 bytes, the
+normal structure,
+.Sy ctf_member_t ,
+is used and the offset in bits is stored in the member
+.Em ctm_offset .
+However, when the size of the structure is greater than or equal to 8192 bytes,
+then the number of bits is split into two 32-bit quantities.
+One member,
+.Em ctlm_offsethi ,
+represents the upper 32 bits of the offset, while the other member,
+.Em ctlm_offsetlo ,
+represents the lower 32 bits of the offset.
+These can be joined together to get a 64-bit sized offset in bits by shifting
+the member
+.Em ctlm_offsethi
+to the left by thirty two and then doing a binary or of
+.Em ctlm_offsetlo .
+.Ss Encoding of Enumerations
+Enumerations, noted by the type
+.Sy CTF_K_ENUM ,
+are similar to structures.
+Enumerations use the variable list to note the number of values that the
+enumeration contains, which we'll term enumerators.
+In C, an enumeration is always equivalent to the intrinsic type
+.Sy int ,
+thus the value of the member
+.Em ctt_size
+is always the size of an integer which is determined based on the current model.
+For
+.Fx
+systems, this will always be 4, as an integer is always defined to
+be 4 bytes large in both
+.Sy ILP32
+and
+.Sy LP64 ,
+regardless of the architecture.
+For further details, see
+.Xr arch 7 .
+.Lp
+The enumerators encoded in an enumeration have the following structure in the
+variable list:
+.Bd -literal
+typedef struct ctf_enum {
+ uint32_t cte_name; /* reference to name in string table */
+ int32_t cte_value; /* value associated with this name */
+} ctf_enum_t;
+.Ed
+.Pp
+The member
+.Em cte_name
+refers to the name of the enumerator's value, it is encoded according to the
+rules in the section
+.Sx String Identifiers .
+The member
+.Em cte_value
+contains the integer value of this enumerator.
+.Ss Encoding of Forward References
+Forward references, types of kind
+.Sy CTF_K_FORWARD ,
+in a
+.Nm
+file refer to types which may not have a definition at all, only a name.
+If the
+.Nm
+file is a child, then it may be that the forward is resolved to an
+actual type in the parent, otherwise the definition may be in another
+.Nm
+container or may not be known at all.
+The only member of the
+.Sy ctf_type_t
+that matters for a forward declaration is the
+.Em ctt_name
+which points to the name of the forward reference in the string table as
+described earlier.
+There is no other information recorded for forward references.
+.Ss Encoding of Pointers, Typedefs, Volatile, Const, and Restrict
+Pointers, typedefs, volatile, const, and restrict are all similar in
+.Nm .
+They all refer to another type.
+In the case of typedefs, they provide an alternate name, while volatile, const,
+and restrict change how the type is interpreted in the C programming language.
+This covers the
+.Nm
+kinds
+.Sy CTF_K_POINTER ,
+.Sy CTF_K_TYPEDEF ,
+.Sy CTF_K_VOLATILE ,
+.Sy CTF_K_RESTRICT ,
+and
+.Sy CTF_K_CONST .
+.Lp
+These types have no variable list entries and use the member
+.Em ctt_type
+to refer to the base type that they modify.
+.Ss Encoding of Unknown Types
+Types with the kind
+.Sy CTF_K_UNKNOWN
+are used to indicate gaps in the type identifier space.
+These entries consume an identifier, but do not define anything.
+Nothing should refer to these gap identifiers.
+.Ss Dependencies Between Types
+C types can be imagined as a directed, cyclic, graph.
+Structures and unions may refer to each other in a way that creates a cyclic
+dependency.
+In cases such as these, the entire type section must be read in and processed.
+Consumers must not assume that every type can be laid out in dependency order;
+they cannot.
+.Ss The String Section
+The last section of the
+.Nm
+file is the
+.Sy string
+section.
+This section encodes all of the strings that appear throughout the other
+sections.
+It is laid out as a series of characters followed by a null terminator.
+Generally, all names are written out in ASCII, as most C compilers do not allow
+any characters to appear in identifiers outside of a subset of ASCII.
+However, any extended characters sets should be written out as a series of UTF-8
+bytes.
+.Lp
+The first entry in the section, at offset zero, is a single null
+terminator to reference the empty string.
+Following that, each C string should be written out, including the null
+terminator.
+Offsets that refer to something in this section should refer to the first byte
+which begins a string.
+Beyond the first byte in the section being the null terminator, the order of
+strings is unimportant.
+.Ss Data Encoding and ELF Considerations
+.Nm
+data is generally included in ELF objects which specify information to
+identify the architecture and endianness of the file.
+A
+.Nm
+container inside such an object must match the endianness of the ELF object.
+Aside from the question of the endian encoding of data, there should be no other
+differences between architectures.
+While many of the types in this document refer to non-fixed size C integral
+types, they are equivalent in the models
+.Sy ILP32
+and
+.Sy LP64 .
+If any other model is being used with
+.Nm
+data that has different sizes, then it must not use the model's sizes for
+those integral types and instead use the fixed size equivalents based on an
+.Sy ILP32
+environment.
+.Lp
+When placing a
+.Nm
+container inside of an ELF object, there are certain conventions that are
+expected for the purposes of tooling being able to find the
+.Nm
+data.
+In particular, a given ELF object should only contain a single
+.Nm
+section.
+Multiple containers should be merged together into a single one.
+.Lp
+The
+.Nm
+file should be included in its own ELF section.
+The section's name must be
+.Ql .SUNW_ctf .
+The type of the section must be
+.Sy SHT_PROGBITS .
+The section should have a link set to the symbol table and its address
+alignment must be 4.
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr elf 3 ,
+.Xr gelf 3 ,
+.Xr a.out 5 ,
+.Xr elf 5 ,
+.Xr arch 7
diff --git a/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c b/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c
new file mode 100644
index 000000000000..c35b1a526d21
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c
@@ -0,0 +1,528 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/zmod.h>
+#include <ctf_impl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef illumos
+#include <dlfcn.h>
+#else
+#include <zlib.h>
+#endif
+#include <gelf.h>
+
+#ifdef illumos
+#ifdef _LP64
+static const char *_libctf_zlib = "/usr/lib/64/libz.so";
+#else
+static const char *_libctf_zlib = "/usr/lib/libz.so";
+#endif
+#endif
+
+static struct {
+ int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t);
+ const char *(*z_error)(int);
+ void *z_dlp;
+} zlib;
+
+static size_t _PAGESIZE;
+static size_t _PAGEMASK;
+
+#ifdef illumos
+#pragma init(_libctf_init)
+#else
+void _libctf_init(void) __attribute__ ((constructor));
+#endif
+void
+_libctf_init(void)
+{
+#ifdef illumos
+ const char *p = getenv("LIBCTF_DECOMPRESSOR");
+
+ if (p != NULL)
+ _libctf_zlib = p; /* use alternate decompression library */
+#endif
+
+ _libctf_debug = getenv("LIBCTF_DEBUG") != NULL;
+
+ _PAGESIZE = getpagesize();
+ _PAGEMASK = ~(_PAGESIZE - 1);
+}
+
+/*
+ * Attempt to dlopen the decompression library and locate the symbols of
+ * interest that we will need to call. This information in cached so
+ * that multiple calls to ctf_bufopen() do not need to reopen the library.
+ */
+void *
+ctf_zopen(int *errp)
+{
+#ifdef illumos
+ ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);
+
+ if (zlib.z_dlp != NULL)
+ return (zlib.z_dlp); /* library is already loaded */
+
+ if (access(_libctf_zlib, R_OK) == -1)
+ return (ctf_set_open_errno(errp, ECTF_ZMISSING));
+
+ if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL)
+ return (ctf_set_open_errno(errp, ECTF_ZINIT));
+
+ zlib.z_uncompress = (int (*)(uchar_t *, ulong_t *, const uchar_t *, ulong_t)) dlsym(zlib.z_dlp, "uncompress");
+ zlib.z_error = (const char *(*)(int)) dlsym(zlib.z_dlp, "zError");
+
+ if (zlib.z_uncompress == NULL || zlib.z_error == NULL) {
+ (void) dlclose(zlib.z_dlp);
+ bzero(&zlib, sizeof (zlib));
+ return (ctf_set_open_errno(errp, ECTF_ZINIT));
+ }
+#else
+ zlib.z_uncompress = uncompress;
+ zlib.z_error = zError;
+
+ /* Dummy return variable as 'no error' */
+ zlib.z_dlp = (void *) (uintptr_t) 1;
+#endif
+
+ return (zlib.z_dlp);
+}
+
+/*
+ * The ctf_bufopen() routine calls these subroutines, defined by <sys/zmod.h>,
+ * which we then patch through to the functions in the decompression library.
+ */
+int
+z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
+{
+ return (zlib.z_uncompress(dst, (ulong_t *)dstlen, src, srclen));
+}
+
+const char *
+z_strerror(int err)
+{
+ return (zlib.z_error(err));
+}
+
+/*
+ * Convert a 32-bit ELF file header into GElf.
+ */
+static void
+ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst)
+{
+ bcopy(src->e_ident, dst->e_ident, EI_NIDENT);
+ dst->e_type = src->e_type;
+ dst->e_machine = src->e_machine;
+ dst->e_version = src->e_version;
+ dst->e_entry = (Elf64_Addr)src->e_entry;
+ dst->e_phoff = (Elf64_Off)src->e_phoff;
+ dst->e_shoff = (Elf64_Off)src->e_shoff;
+ dst->e_flags = src->e_flags;
+ dst->e_ehsize = src->e_ehsize;
+ dst->e_phentsize = src->e_phentsize;
+ dst->e_phnum = src->e_phnum;
+ dst->e_shentsize = src->e_shentsize;
+ dst->e_shnum = src->e_shnum;
+ dst->e_shstrndx = src->e_shstrndx;
+}
+
+/*
+ * Convert a 32-bit ELF section header into GElf.
+ */
+static void
+shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst)
+{
+ dst->sh_name = src->sh_name;
+ dst->sh_type = src->sh_type;
+ dst->sh_flags = src->sh_flags;
+ dst->sh_addr = src->sh_addr;
+ dst->sh_offset = src->sh_offset;
+ dst->sh_size = src->sh_size;
+ dst->sh_link = src->sh_link;
+ dst->sh_info = src->sh_info;
+ dst->sh_addralign = src->sh_addralign;
+ dst->sh_entsize = src->sh_entsize;
+}
+
+/*
+ * In order to mmap a section from the ELF file, we must round down sh_offset
+ * to the previous page boundary, and mmap the surrounding page. We store
+ * the pointer to the start of the actual section data back into sp->cts_data.
+ */
+const void *
+ctf_sect_mmap(ctf_sect_t *sp, int fd)
+{
+ size_t pageoff = sp->cts_offset & ~_PAGEMASK;
+
+ caddr_t base = mmap64(NULL, sp->cts_size + pageoff, PROT_READ,
+ MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK);
+
+ if (base != MAP_FAILED)
+ sp->cts_data = base + pageoff;
+
+ return (base);
+}
+
+/*
+ * Since sp->cts_data has the adjusted offset, we have to again round down
+ * to get the actual mmap address and round up to get the size.
+ */
+void
+ctf_sect_munmap(const ctf_sect_t *sp)
+{
+ uintptr_t addr = (uintptr_t)sp->cts_data;
+ uintptr_t pageoff = addr & ~_PAGEMASK;
+
+ (void) munmap((void *)(addr - pageoff), sp->cts_size + pageoff);
+}
+
+/*
+ * Open the specified file descriptor and return a pointer to a CTF container.
+ * The file can be either an ELF file or raw CTF file. The caller is
+ * responsible for closing the file descriptor when it is no longer needed.
+ */
+ctf_file_t *
+ctf_fdopen(int fd, int *errp)
+{
+ ctf_sect_t ctfsect, symsect, strsect;
+ ctf_file_t *fp = NULL;
+ size_t shstrndx, shnum;
+
+ struct stat64 st;
+ ssize_t nbytes;
+
+ union {
+ ctf_preamble_t ctf;
+ Elf32_Ehdr e32;
+ GElf_Ehdr e64;
+ } hdr;
+
+ bzero(&ctfsect, sizeof (ctf_sect_t));
+ bzero(&symsect, sizeof (ctf_sect_t));
+ bzero(&strsect, sizeof (ctf_sect_t));
+ bzero(&hdr, sizeof (hdr));
+
+ if (fstat64(fd, &st) == -1)
+ return (ctf_set_open_errno(errp, errno));
+
+ if ((nbytes = pread64(fd, &hdr, sizeof (hdr), 0)) <= 0)
+ return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT));
+
+ /*
+ * If we have read enough bytes to form a CTF header and the magic
+ * string matches, attempt to interpret the file as raw CTF.
+ */
+ if (nbytes >= (ssize_t) sizeof (ctf_preamble_t) &&
+ hdr.ctf.ctp_magic == CTF_MAGIC) {
+ if (hdr.ctf.ctp_version > CTF_VERSION)
+ return (ctf_set_open_errno(errp, ECTF_CTFVERS));
+
+ ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ,
+ MAP_PRIVATE, fd, 0);
+
+ if (ctfsect.cts_data == MAP_FAILED)
+ return (ctf_set_open_errno(errp, errno));
+
+ ctfsect.cts_name = _CTF_SECTION;
+ ctfsect.cts_type = SHT_PROGBITS;
+ ctfsect.cts_flags = SHF_ALLOC;
+ ctfsect.cts_size = (size_t)st.st_size;
+ ctfsect.cts_entsize = 1;
+ ctfsect.cts_offset = 0;
+
+ if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL)
+ ctf_sect_munmap(&ctfsect);
+
+ return (fp);
+ }
+
+ /*
+ * If we have read enough bytes to form an ELF header and the magic
+ * string matches, attempt to interpret the file as an ELF file. We
+ * do our own largefile ELF processing, and convert everything to
+ * GElf structures so that clients can operate on any data model.
+ */
+ if (nbytes >= (ssize_t) sizeof (Elf32_Ehdr) &&
+ bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) {
+#if BYTE_ORDER == _BIG_ENDIAN
+ uchar_t order = ELFDATA2MSB;
+#else
+ uchar_t order = ELFDATA2LSB;
+#endif
+ GElf_Shdr *sp;
+
+ void *strs_map;
+ size_t strs_mapsz, i;
+ char *strs;
+
+ if (hdr.e32.e_ident[EI_DATA] != order)
+ return (ctf_set_open_errno(errp, ECTF_ENDIAN));
+ if (hdr.e32.e_version != EV_CURRENT)
+ return (ctf_set_open_errno(errp, ECTF_ELFVERS));
+
+ if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) {
+ if (nbytes < (ssize_t) sizeof (GElf_Ehdr))
+ return (ctf_set_open_errno(errp, ECTF_FMT));
+ } else {
+ Elf32_Ehdr e32 = hdr.e32;
+ ehdr_to_gelf(&e32, &hdr.e64);
+ }
+
+ shnum = hdr.e64.e_shnum;
+ shstrndx = hdr.e64.e_shstrndx;
+
+ /* Extended ELF sections */
+ if ((shstrndx == SHN_XINDEX) || (shnum == 0)) {
+ if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
+ Elf32_Shdr x32;
+
+ if (pread64(fd, &x32, sizeof (x32),
+ hdr.e64.e_shoff) != sizeof (x32))
+ return (ctf_set_open_errno(errp,
+ errno));
+
+ shnum = x32.sh_size;
+ shstrndx = x32.sh_link;
+ } else {
+ Elf64_Shdr x64;
+
+ if (pread64(fd, &x64, sizeof (x64),
+ hdr.e64.e_shoff) != sizeof (x64))
+ return (ctf_set_open_errno(errp,
+ errno));
+
+ shnum = x64.sh_size;
+ shstrndx = x64.sh_link;
+ }
+ }
+
+ if (shstrndx >= shnum)
+ return (ctf_set_open_errno(errp, ECTF_CORRUPT));
+
+ nbytes = sizeof (GElf_Shdr) * shnum;
+
+ if ((sp = malloc(nbytes)) == NULL)
+ return (ctf_set_open_errno(errp, errno));
+
+ /*
+ * Read in and convert to GElf the array of Shdr structures
+ * from e_shoff so we can locate sections of interest.
+ */
+ if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
+ Elf32_Shdr *sp32;
+
+ nbytes = sizeof (Elf32_Shdr) * shnum;
+
+ if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
+ sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
+ free(sp);
+ free(sp32);
+ return (ctf_set_open_errno(errp, errno));
+ }
+
+ for (i = 0; i < shnum; i++)
+ shdr_to_gelf(&sp32[i], &sp[i]);
+
+ free(sp32);
+
+ } else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) {
+ free(sp);
+ return (ctf_set_open_errno(errp, errno));
+ }
+
+ /*
+ * Now mmap the section header strings section so that we can
+ * perform string comparison on the section names.
+ */
+ strs_mapsz = sp[shstrndx].sh_size +
+ (sp[shstrndx].sh_offset & ~_PAGEMASK);
+
+ strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
+ fd, sp[shstrndx].sh_offset & _PAGEMASK);
+
+ strs = (char *)strs_map +
+ (sp[shstrndx].sh_offset & ~_PAGEMASK);
+
+ if (strs_map == MAP_FAILED) {
+ free(sp);
+ return (ctf_set_open_errno(errp, ECTF_MMAP));
+ }
+
+ /*
+ * Iterate over the section header array looking for the CTF
+ * section and symbol table. The strtab is linked to symtab.
+ */
+ for (i = 0; i < shnum; i++) {
+ const GElf_Shdr *shp = &sp[i];
+ const GElf_Shdr *lhp = &sp[shp->sh_link];
+
+ if (shp->sh_link >= shnum)
+ continue; /* corrupt sh_link field */
+
+ if (shp->sh_name >= sp[shstrndx].sh_size ||
+ lhp->sh_name >= sp[shstrndx].sh_size)
+ continue; /* corrupt sh_name field */
+
+ if (shp->sh_type == SHT_PROGBITS &&
+ strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) {
+ ctfsect.cts_name = strs + shp->sh_name;
+ ctfsect.cts_type = shp->sh_type;
+ ctfsect.cts_flags = shp->sh_flags;
+ ctfsect.cts_size = shp->sh_size;
+ ctfsect.cts_entsize = shp->sh_entsize;
+ ctfsect.cts_offset = (off64_t)shp->sh_offset;
+
+ } else if (shp->sh_type == SHT_SYMTAB) {
+ symsect.cts_name = strs + shp->sh_name;
+ symsect.cts_type = shp->sh_type;
+ symsect.cts_flags = shp->sh_flags;
+ symsect.cts_size = shp->sh_size;
+ symsect.cts_entsize = shp->sh_entsize;
+ symsect.cts_offset = (off64_t)shp->sh_offset;
+
+ strsect.cts_name = strs + lhp->sh_name;
+ strsect.cts_type = lhp->sh_type;
+ strsect.cts_flags = lhp->sh_flags;
+ strsect.cts_size = lhp->sh_size;
+ strsect.cts_entsize = lhp->sh_entsize;
+ strsect.cts_offset = (off64_t)lhp->sh_offset;
+ }
+ }
+
+ free(sp); /* free section header array */
+
+ if (ctfsect.cts_type == SHT_NULL) {
+ (void) munmap(strs_map, strs_mapsz);
+ return (ctf_set_open_errno(errp, ECTF_NOCTFDATA));
+ }
+
+ /*
+ * Now mmap the CTF data, symtab, and strtab sections and
+ * call ctf_bufopen() to do the rest of the work.
+ */
+ if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) {
+ (void) munmap(strs_map, strs_mapsz);
+ return (ctf_set_open_errno(errp, ECTF_MMAP));
+ }
+
+ if (symsect.cts_type != SHT_NULL &&
+ strsect.cts_type != SHT_NULL) {
+ if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED ||
+ ctf_sect_mmap(&strsect, fd) == MAP_FAILED) {
+ (void) ctf_set_open_errno(errp, ECTF_MMAP);
+ goto bad; /* unmap all and abort */
+ }
+ fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp);
+ } else
+ fp = ctf_bufopen(&ctfsect, NULL, NULL, errp);
+bad:
+ if (fp == NULL) {
+ ctf_sect_munmap(&ctfsect);
+ ctf_sect_munmap(&symsect);
+ ctf_sect_munmap(&strsect);
+ } else
+ fp->ctf_flags |= LCTF_MMAP;
+
+ (void) munmap(strs_map, strs_mapsz);
+ return (fp);
+ }
+
+ return (ctf_set_open_errno(errp, ECTF_FMT));
+}
+
+/*
+ * Open the specified file and return a pointer to a CTF container. The file
+ * can be either an ELF file or raw CTF file. This is just a convenient
+ * wrapper around ctf_fdopen() for callers.
+ */
+ctf_file_t *
+ctf_open(const char *filename, int *errp)
+{
+ ctf_file_t *fp;
+ int fd;
+
+ if ((fd = open64(filename, O_RDONLY)) == -1) {
+ if (errp != NULL)
+ *errp = errno;
+ return (NULL);
+ }
+
+ fp = ctf_fdopen(fd, errp);
+ (void) close(fd);
+ return (fp);
+}
+
+/*
+ * Write the uncompressed CTF data stream to the specified file descriptor.
+ * This is useful for saving the results of dynamic CTF containers.
+ */
+int
+ctf_write(ctf_file_t *fp, int fd)
+{
+ const uchar_t *buf = fp->ctf_base;
+ ssize_t resid = fp->ctf_size;
+ ssize_t len;
+
+ while (resid != 0) {
+ if ((len = write(fd, buf, resid)) <= 0)
+ return (ctf_set_errno(fp, errno));
+ resid -= len;
+ buf += len;
+ }
+
+ return (0);
+}
+
+/*
+ * Set the CTF library client version to the specified version. If version is
+ * zero, we just return the default library version number.
+ */
+int
+ctf_version(int version)
+{
+ if (version < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (version > 0) {
+ if (version > CTF_VERSION) {
+ errno = ENOTSUP;
+ return (-1);
+ }
+ ctf_dprintf("ctf_version: client using version %d\n", version);
+ _libctf_version = version;
+ }
+
+ return (_libctf_version);
+}
diff --git a/cddl/contrib/opensolaris/lib/libctf/common/ctf_subr.c b/cddl/contrib/opensolaris/lib/libctf/common/ctf_subr.c
new file mode 100644
index 000000000000..e9f5ad7a1f71
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libctf/common/ctf_subr.c
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ctf_impl.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+
+void *
+ctf_data_alloc(size_t size)
+{
+ return (mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0));
+}
+
+void
+ctf_data_free(void *buf, size_t size)
+{
+ (void) munmap(buf, size);
+}
+
+void
+ctf_data_protect(void *buf, size_t size)
+{
+ (void) mprotect(buf, size, PROT_READ);
+}
+
+void *
+ctf_alloc(size_t size)
+{
+ return (malloc(size));
+}
+
+/*ARGSUSED*/
+void
+ctf_free(void *buf, __unused size_t size)
+{
+ free(buf);
+}
+
+const char *
+ctf_strerror(int err)
+{
+ return ((const char *) strerror(err));
+}
+
+/*PRINTFLIKE1*/
+void
+ctf_dprintf(const char *format, ...)
+{
+ if (_libctf_debug) {
+ va_list alist;
+
+ va_start(alist, format);
+ (void) fputs("libctf DEBUG: ", stderr);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+ }
+}
diff --git a/cddl/contrib/opensolaris/lib/libctf/common/libctf.h b/cddl/contrib/opensolaris/lib/libctf/common/libctf.h
new file mode 100644
index 000000000000..3fd69318ded0
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libctf/common/libctf.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ *
+ * 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 2001-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This header file defines the interfaces available from the CTF debugger
+ * library, libctf. This library provides functions that a debugger can
+ * use to operate on data in the Compact ANSI-C Type Format (CTF). This
+ * is NOT a public interface, although it may eventually become one in
+ * the fullness of time after we gain more experience with the interfaces.
+ *
+ * In the meantime, be aware that any program linked with libctf in this
+ * release of Solaris is almost guaranteed to break in the next release.
+ *
+ * In short, do not user this header file or libctf for any purpose.
+ */
+
+#ifndef _LIBCTF_H
+#define _LIBCTF_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/ctf_api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This flag can be used to enable debug messages.
+ */
+extern int _libctf_debug;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBCTF_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/aarch64/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/aarch64/dt_isadep.c
new file mode 100644
index 000000000000..9f5af8570490
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/aarch64/dt_isadep.c
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2014 Howard Su
+ * Copyright 2015 George V. Neville-Neil
+ * Copyright 2015 Ruslan Bukin <br@bsdpad.com>
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+#if !defined(sun)
+#include <libproc_compat.h>
+#endif
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+
+ ftp->ftps_type = DTFTP_ENTRY;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = 0;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+
+ dt_dprintf("%s: unimplemented\n", __func__);
+
+ return (DT_PROC_ERR);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+
+ if (!ALIGNED_POINTER(off, 4))
+ return (DT_PROC_ALIGN);
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = off;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+ ulong_t i;
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ /*
+ * If we're matching against everything, just iterate through each
+ * instruction in the function, otherwise look for matching offset
+ * names by constructing the string and comparing it against the
+ * pattern.
+ */
+ if (strcmp("*", pattern) == 0) {
+ for (i = 0; i < symp->st_size; i += 4) {
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ } else {
+ char name[sizeof (i) * 2 + 1];
+
+ for (i = 0; i < symp->st_size; i += 4) {
+ (void) sprintf(name, "%lx", i);
+ if (gmatch(name, pattern))
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ }
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (ftp->ftps_noffs);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c
new file mode 100644
index 000000000000..802d9d9752a6
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/arm/dt_isadep.c
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2014 Howard Su
+ * Copyright 2015 George V. Neville-Neil
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+#ifdef __FreeBSD__
+#include <libproc_compat.h>
+#endif
+
+#define OP(x) ((x) >> 30)
+#define OP2(x) (((x) >> 22) & 0x07)
+#define COND(x) (((x) >> 25) & 0x0f)
+#define A(x) (((x) >> 29) & 0x01)
+
+#define OP_BRANCH 0
+
+#define OP2_BPcc 0x1
+#define OP2_Bicc 0x2
+#define OP2_BPr 0x3
+#define OP2_FBPfcc 0x5
+#define OP2_FBfcc 0x6
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+ ftp->ftps_type = DTFTP_ENTRY;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = 0;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+
+ uint32_t *text;
+ int i;
+ int srdepth = 0;
+
+ dt_dprintf("%s: unimplemented\n", __func__);
+ return (DT_PROC_ERR);
+
+ if ((text = malloc(symp->st_size + 4)) == NULL) {
+ dt_dprintf("mr sparkle: malloc() failed\n");
+ return (DT_PROC_ERR);
+ }
+
+ if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
+ dt_dprintf("mr sparkle: Pread() failed\n");
+ free(text);
+ return (DT_PROC_ERR);
+ }
+
+ /*
+ * Leave a dummy instruction in the last slot to simplify edge
+ * conditions.
+ */
+ text[symp->st_size / 4] = 0;
+
+ ftp->ftps_type = DTFTP_RETURN;
+ ftp->ftps_pc = symp->st_value;
+ ftp->ftps_size = symp->st_size;
+ ftp->ftps_noffs = 0;
+
+
+ free(text);
+ if (ftp->ftps_noffs > 0) {
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+ }
+
+
+ return (ftp->ftps_noffs);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+ if (off & 0x3)
+ return (DT_PROC_ALIGN);
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = off;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+ ulong_t i;
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ /*
+ * If we're matching against everything, just iterate through each
+ * instruction in the function, otherwise look for matching offset
+ * names by constructing the string and comparing it against the
+ * pattern.
+ */
+ if (strcmp("*", pattern) == 0) {
+ for (i = 0; i < symp->st_size; i += 4) {
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ } else {
+ char name[sizeof (i) * 2 + 1];
+
+ for (i = 0; i < symp->st_size; i += 4) {
+ (void) sprintf(name, "%lx", i);
+ if (gmatch(name, pattern))
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ }
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (ftp->ftps_noffs);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
new file mode 100644
index 000000000000..cd9294998454
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
@@ -0,0 +1,219 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2013 Voxer Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <sys/dtrace.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libelf.h>
+
+/*
+ * In Solaris 10 GA, the only mechanism for communicating helper information
+ * is through the DTrace helper pseudo-device node in /devices; there is
+ * no /dev link. Because of this, USDT providers and helper actions don't
+ * work inside of non-global zones. This issue was addressed by adding
+ * the /dev and having this initialization code use that /dev link. If the
+ * /dev link doesn't exist it falls back to looking for the /devices node
+ * as this code may be embedded in a binary which runs on Solaris 10 GA.
+ *
+ * Users may set the following environment variable to affect the way
+ * helper initialization takes place:
+ *
+ * DTRACE_DOF_INIT_DEBUG enable debugging output
+ * DTRACE_DOF_INIT_DISABLE disable helper loading
+ * DTRACE_DOF_INIT_DEVNAME set the path to the helper node
+ */
+
+static const char *devnamep = "/dev/dtrace/helper";
+#ifdef illumos
+static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
+#endif
+
+static const char *modname; /* Name of this load object */
+static int gen; /* DOF helper generation */
+extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */
+static boolean_t dof_init_debug = B_FALSE; /* From DTRACE_DOF_INIT_DEBUG */
+
+static void
+dbg_printf(int debug, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (debug && !dof_init_debug)
+ return;
+
+ va_start(ap, fmt);
+
+ if (modname == NULL)
+ (void) fprintf(stderr, "dtrace DOF: ");
+ else
+ (void) fprintf(stderr, "dtrace DOF %s: ", modname);
+
+ (void) vfprintf(stderr, fmt, ap);
+
+ if (fmt[strlen(fmt) - 1] != '\n')
+ (void) fprintf(stderr, ": %s\n", strerror(errno));
+
+ va_end(ap);
+}
+
+#ifdef illumos
+#pragma init(dtrace_dof_init)
+#else
+static void dtrace_dof_init(void) __attribute__ ((constructor));
+#endif
+
+static void
+dtrace_dof_init(void)
+{
+ dof_hdr_t *dof = &__SUNW_dof;
+#ifdef _LP64
+ Elf64_Ehdr *elf;
+#else
+ Elf32_Ehdr *elf;
+#endif
+ dof_helper_t dh;
+ Link_map *lmp = NULL;
+#ifdef illumos
+ Lmid_t lmid;
+#else
+ u_long lmid = 0;
+#endif
+ int fd;
+ const char *p;
+
+ if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
+ return;
+
+ if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL)
+ dof_init_debug = B_TRUE;
+
+ if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) {
+ dbg_printf(1, "couldn't discover module name or address\n");
+ return;
+ }
+
+#ifdef illumos
+ if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
+ dbg_printf(1, "couldn't discover link map ID\n");
+ return;
+ }
+#endif
+
+ if ((modname = strrchr(lmp->l_name, '/')) == NULL)
+ modname = lmp->l_name;
+ else
+ modname++;
+
+ if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
+ dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
+ dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 ||
+ dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) {
+ dbg_printf(0, ".SUNW_dof section corrupt\n");
+ return;
+ }
+
+ elf = (void *)lmp->l_addr;
+
+ dh.dofhp_dof = (uintptr_t)dof;
+ dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0;
+#ifdef __FreeBSD__
+ dh.dofhp_pid = getpid();
+#endif
+
+ if (lmid == 0) {
+ (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
+ "%s", modname);
+ } else {
+ (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
+ "LM%lu`%s", lmid, modname);
+ }
+
+ if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL)
+ devnamep = p;
+
+ if ((fd = open64(devnamep, O_RDWR)) < 0) {
+ dbg_printf(1, "failed to open helper device %s", devnamep);
+#ifdef illumos
+ /*
+ * If the device path wasn't explicitly set, try again with
+ * the old device path.
+ */
+ if (p != NULL)
+ return;
+
+ devnamep = olddevname;
+
+ if ((fd = open64(devnamep, O_RDWR)) < 0) {
+ dbg_printf(1, "failed to open helper device %s", devnamep);
+ return;
+ }
+#else
+ return;
+#endif
+ }
+ if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
+ dbg_printf(1, "DTrace ioctl failed for DOF at %p", dof);
+ else {
+ dbg_printf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
+#ifdef __FreeBSD__
+ gen = dh.dofhp_gen;
+#endif
+ }
+
+ (void) close(fd);
+}
+
+#ifdef illumos
+#pragma fini(dtrace_dof_fini)
+#else
+static void dtrace_dof_fini(void) __attribute__ ((destructor));
+#endif
+
+static void
+dtrace_dof_fini(void)
+{
+ int fd;
+
+ if ((fd = open64(devnamep, O_RDWR)) < 0) {
+ dbg_printf(1, "failed to open helper device %s", devnamep);
+ return;
+ }
+
+ if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, &gen)) == -1)
+ dbg_printf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen);
+ else
+ dbg_printf(1, "DTrace ioctl removed DOF (%d)\n", gen);
+
+ (void) close(fd);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c
new file mode 100644
index 000000000000..5ea55a05faf0
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c
@@ -0,0 +1,2198 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dt_impl.h>
+#include <assert.h>
+#ifdef illumos
+#include <alloca.h>
+#else
+#include <sys/sysctl.h>
+#include <libproc_compat.h>
+#endif
+#include <limits.h>
+
+#define DTRACE_AHASHSIZE 32779 /* big 'ol prime */
+
+/*
+ * Because qsort(3C) does not allow an argument to be passed to a comparison
+ * function, the variables that affect comparison must regrettably be global;
+ * they are protected by a global static lock, dt_qsort_lock.
+ */
+static pthread_mutex_t dt_qsort_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int dt_revsort;
+static int dt_keysort;
+static int dt_keypos;
+
+#define DT_LESSTHAN (dt_revsort == 0 ? -1 : 1)
+#define DT_GREATERTHAN (dt_revsort == 0 ? 1 : -1)
+
+static void
+dt_aggregate_count(int64_t *existing, int64_t *new, size_t size)
+{
+ uint_t i;
+
+ for (i = 0; i < size / sizeof (int64_t); i++)
+ existing[i] = existing[i] + new[i];
+}
+
+static int
+dt_aggregate_countcmp(int64_t *lhs, int64_t *rhs)
+{
+ int64_t lvar = *lhs;
+ int64_t rvar = *rhs;
+
+ if (lvar < rvar)
+ return (DT_LESSTHAN);
+
+ if (lvar > rvar)
+ return (DT_GREATERTHAN);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static void
+dt_aggregate_min(int64_t *existing, int64_t *new, size_t size)
+{
+ if (*new < *existing)
+ *existing = *new;
+}
+
+/*ARGSUSED*/
+static void
+dt_aggregate_max(int64_t *existing, int64_t *new, size_t size)
+{
+ if (*new > *existing)
+ *existing = *new;
+}
+
+static int
+dt_aggregate_averagecmp(int64_t *lhs, int64_t *rhs)
+{
+ int64_t lavg = lhs[0] ? (lhs[1] / lhs[0]) : 0;
+ int64_t ravg = rhs[0] ? (rhs[1] / rhs[0]) : 0;
+
+ if (lavg < ravg)
+ return (DT_LESSTHAN);
+
+ if (lavg > ravg)
+ return (DT_GREATERTHAN);
+
+ return (0);
+}
+
+static int
+dt_aggregate_stddevcmp(int64_t *lhs, int64_t *rhs)
+{
+ uint64_t lsd = dt_stddev((uint64_t *)lhs, 1);
+ uint64_t rsd = dt_stddev((uint64_t *)rhs, 1);
+
+ if (lsd < rsd)
+ return (DT_LESSTHAN);
+
+ if (lsd > rsd)
+ return (DT_GREATERTHAN);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static void
+dt_aggregate_lquantize(int64_t *existing, int64_t *new, size_t size)
+{
+ int64_t arg = *existing++;
+ uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg);
+ int i;
+
+ for (i = 0; i <= levels + 1; i++)
+ existing[i] = existing[i] + new[i + 1];
+}
+
+static long double
+dt_aggregate_lquantizedsum(int64_t *lquanta)
+{
+ int64_t arg = *lquanta++;
+ int32_t base = DTRACE_LQUANTIZE_BASE(arg);
+ uint16_t step = DTRACE_LQUANTIZE_STEP(arg);
+ uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg), i;
+ long double total = (long double)lquanta[0] * (long double)(base - 1);
+
+ for (i = 0; i < levels; base += step, i++)
+ total += (long double)lquanta[i + 1] * (long double)base;
+
+ return (total + (long double)lquanta[levels + 1] *
+ (long double)(base + 1));
+}
+
+static int64_t
+dt_aggregate_lquantizedzero(int64_t *lquanta)
+{
+ int64_t arg = *lquanta++;
+ int32_t base = DTRACE_LQUANTIZE_BASE(arg);
+ uint16_t step = DTRACE_LQUANTIZE_STEP(arg);
+ uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg), i;
+
+ if (base - 1 == 0)
+ return (lquanta[0]);
+
+ for (i = 0; i < levels; base += step, i++) {
+ if (base != 0)
+ continue;
+
+ return (lquanta[i + 1]);
+ }
+
+ if (base + 1 == 0)
+ return (lquanta[levels + 1]);
+
+ return (0);
+}
+
+static int
+dt_aggregate_lquantizedcmp(int64_t *lhs, int64_t *rhs)
+{
+ long double lsum = dt_aggregate_lquantizedsum(lhs);
+ long double rsum = dt_aggregate_lquantizedsum(rhs);
+ int64_t lzero, rzero;
+
+ if (lsum < rsum)
+ return (DT_LESSTHAN);
+
+ if (lsum > rsum)
+ return (DT_GREATERTHAN);
+
+ /*
+ * If they're both equal, then we will compare based on the weights at
+ * zero. If the weights at zero are equal (or if zero is not within
+ * the range of the linear quantization), then this will be judged a
+ * tie and will be resolved based on the key comparison.
+ */
+ lzero = dt_aggregate_lquantizedzero(lhs);
+ rzero = dt_aggregate_lquantizedzero(rhs);
+
+ if (lzero < rzero)
+ return (DT_LESSTHAN);
+
+ if (lzero > rzero)
+ return (DT_GREATERTHAN);
+
+ return (0);
+}
+
+static void
+dt_aggregate_llquantize(int64_t *existing, int64_t *new, size_t size)
+{
+ int i;
+
+ for (i = 1; i < size / sizeof (int64_t); i++)
+ existing[i] = existing[i] + new[i];
+}
+
+static long double
+dt_aggregate_llquantizedsum(int64_t *llquanta)
+{
+ int64_t arg = *llquanta++;
+ uint16_t factor = DTRACE_LLQUANTIZE_FACTOR(arg);
+ uint16_t low = DTRACE_LLQUANTIZE_LOW(arg);
+ uint16_t high = DTRACE_LLQUANTIZE_HIGH(arg);
+ uint16_t nsteps = DTRACE_LLQUANTIZE_NSTEP(arg);
+ int bin = 0, order;
+ int64_t value = 1, next, step;
+ long double total;
+
+ assert(nsteps >= factor);
+ assert(nsteps % factor == 0);
+
+ for (order = 0; order < low; order++)
+ value *= factor;
+
+ total = (long double)llquanta[bin++] * (long double)(value - 1);
+
+ next = value * factor;
+ step = next > nsteps ? next / nsteps : 1;
+
+ while (order <= high) {
+ assert(value < next);
+ total += (long double)llquanta[bin++] * (long double)(value);
+
+ if ((value += step) != next)
+ continue;
+
+ next = value * factor;
+ step = next > nsteps ? next / nsteps : 1;
+ order++;
+ }
+
+ return (total + (long double)llquanta[bin] * (long double)value);
+}
+
+static int
+dt_aggregate_llquantizedcmp(int64_t *lhs, int64_t *rhs)
+{
+ long double lsum = dt_aggregate_llquantizedsum(lhs);
+ long double rsum = dt_aggregate_llquantizedsum(rhs);
+ int64_t lzero, rzero;
+
+ if (lsum < rsum)
+ return (DT_LESSTHAN);
+
+ if (lsum > rsum)
+ return (DT_GREATERTHAN);
+
+ /*
+ * If they're both equal, then we will compare based on the weights at
+ * zero. If the weights at zero are equal, then this will be judged a
+ * tie and will be resolved based on the key comparison.
+ */
+ lzero = lhs[1];
+ rzero = rhs[1];
+
+ if (lzero < rzero)
+ return (DT_LESSTHAN);
+
+ if (lzero > rzero)
+ return (DT_GREATERTHAN);
+
+ return (0);
+}
+
+static int
+dt_aggregate_quantizedcmp(int64_t *lhs, int64_t *rhs)
+{
+ int nbuckets = DTRACE_QUANTIZE_NBUCKETS;
+ long double ltotal = 0, rtotal = 0;
+ int64_t lzero, rzero;
+ uint_t i;
+
+ for (i = 0; i < nbuckets; i++) {
+ int64_t bucketval = DTRACE_QUANTIZE_BUCKETVAL(i);
+
+ if (bucketval == 0) {
+ lzero = lhs[i];
+ rzero = rhs[i];
+ }
+
+ ltotal += (long double)bucketval * (long double)lhs[i];
+ rtotal += (long double)bucketval * (long double)rhs[i];
+ }
+
+ if (ltotal < rtotal)
+ return (DT_LESSTHAN);
+
+ if (ltotal > rtotal)
+ return (DT_GREATERTHAN);
+
+ /*
+ * If they're both equal, then we will compare based on the weights at
+ * zero. If the weights at zero are equal, then this will be judged a
+ * tie and will be resolved based on the key comparison.
+ */
+ if (lzero < rzero)
+ return (DT_LESSTHAN);
+
+ if (lzero > rzero)
+ return (DT_GREATERTHAN);
+
+ return (0);
+}
+
+static void
+dt_aggregate_usym(dtrace_hdl_t *dtp, uint64_t *data)
+{
+ uint64_t pid = data[0];
+ uint64_t *pc = &data[1];
+ struct ps_prochandle *P;
+ GElf_Sym sym;
+
+ if (dtp->dt_vector != NULL)
+ return;
+
+ if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL)
+ return;
+
+ dt_proc_lock(dtp, P);
+
+ if (Plookup_by_addr(P, *pc, NULL, 0, &sym) == 0)
+ *pc = sym.st_value;
+
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+}
+
+static void
+dt_aggregate_umod(dtrace_hdl_t *dtp, uint64_t *data)
+{
+ uint64_t pid = data[0];
+ uint64_t *pc = &data[1];
+ struct ps_prochandle *P;
+ const prmap_t *map;
+
+ if (dtp->dt_vector != NULL)
+ return;
+
+ if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL)
+ return;
+
+ dt_proc_lock(dtp, P);
+
+ if ((map = Paddr_to_map(P, *pc)) != NULL)
+ *pc = map->pr_vaddr;
+
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+}
+
+static void
+dt_aggregate_sym(dtrace_hdl_t *dtp, uint64_t *data)
+{
+ GElf_Sym sym;
+ uint64_t *pc = data;
+
+ if (dtrace_lookup_by_addr(dtp, *pc, &sym, NULL) == 0)
+ *pc = sym.st_value;
+}
+
+static void
+dt_aggregate_mod(dtrace_hdl_t *dtp, uint64_t *data)
+{
+ uint64_t *pc = data;
+ dt_module_t *dmp;
+
+ if (dtp->dt_vector != NULL) {
+ /*
+ * We don't have a way of just getting the module for a
+ * vectored open, and it doesn't seem to be worth defining
+ * one. This means that use of mod() won't get true
+ * aggregation in the postmortem case (some modules may
+ * appear more than once in aggregation output). It seems
+ * unlikely that anyone will ever notice or care...
+ */
+ return;
+ }
+
+ for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL;
+ dmp = dt_list_next(dmp)) {
+ if (*pc - dmp->dm_text_va < dmp->dm_text_size) {
+ *pc = dmp->dm_text_va;
+ return;
+ }
+ }
+}
+
+static dtrace_aggvarid_t
+dt_aggregate_aggvarid(dt_ahashent_t *ent)
+{
+ dtrace_aggdesc_t *agg = ent->dtahe_data.dtada_desc;
+ caddr_t data = ent->dtahe_data.dtada_data;
+ dtrace_recdesc_t *rec = agg->dtagd_rec;
+
+ /*
+ * First, we'll check the variable ID in the aggdesc. If it's valid,
+ * we'll return it. If not, we'll use the compiler-generated ID
+ * present as the first record.
+ */
+ if (agg->dtagd_varid != DTRACE_AGGVARIDNONE)
+ return (agg->dtagd_varid);
+
+ agg->dtagd_varid = *((dtrace_aggvarid_t *)(uintptr_t)(data +
+ rec->dtrd_offset));
+
+ return (agg->dtagd_varid);
+}
+
+
+static int
+dt_aggregate_snap_cpu(dtrace_hdl_t *dtp, processorid_t cpu)
+{
+ dtrace_epid_t id;
+ uint64_t hashval;
+ size_t offs, roffs, size, ndx;
+ int i, j, rval;
+ caddr_t addr, data;
+ dtrace_recdesc_t *rec;
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ dtrace_aggdesc_t *agg;
+ dt_ahash_t *hash = &agp->dtat_hash;
+ dt_ahashent_t *h;
+ dtrace_bufdesc_t b = agp->dtat_buf, *buf = &b;
+ dtrace_aggdata_t *aggdata;
+ int flags = agp->dtat_flags;
+
+ buf->dtbd_cpu = cpu;
+
+#ifdef illumos
+ if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, buf) == -1) {
+#else
+ if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, &buf) == -1) {
+#endif
+ if (errno == ENOENT) {
+ /*
+ * If that failed with ENOENT, it may be because the
+ * CPU was unconfigured. This is okay; we'll just
+ * do nothing but return success.
+ */
+ return (0);
+ }
+
+ return (dt_set_errno(dtp, errno));
+ }
+
+ if (buf->dtbd_drops != 0) {
+ if (dt_handle_cpudrop(dtp, cpu,
+ DTRACEDROP_AGGREGATION, buf->dtbd_drops) == -1)
+ return (-1);
+ }
+
+ if (buf->dtbd_size == 0)
+ return (0);
+
+ if (hash->dtah_hash == NULL) {
+ size_t size;
+
+ hash->dtah_size = DTRACE_AHASHSIZE;
+ size = hash->dtah_size * sizeof (dt_ahashent_t *);
+
+ if ((hash->dtah_hash = malloc(size)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ bzero(hash->dtah_hash, size);
+ }
+
+ for (offs = 0; offs < buf->dtbd_size; ) {
+ /*
+ * We're guaranteed to have an ID.
+ */
+ id = *((dtrace_epid_t *)((uintptr_t)buf->dtbd_data +
+ (uintptr_t)offs));
+
+ if (id == DTRACE_AGGIDNONE) {
+ /*
+ * This is filler to assure proper alignment of the
+ * next record; we simply ignore it.
+ */
+ offs += sizeof (id);
+ continue;
+ }
+
+ if ((rval = dt_aggid_lookup(dtp, id, &agg)) != 0)
+ return (rval);
+
+ addr = buf->dtbd_data + offs;
+ size = agg->dtagd_size;
+ hashval = 0;
+
+ for (j = 0; j < agg->dtagd_nrecs - 1; j++) {
+ rec = &agg->dtagd_rec[j];
+ roffs = rec->dtrd_offset;
+
+ switch (rec->dtrd_action) {
+ case DTRACEACT_USYM:
+ dt_aggregate_usym(dtp,
+ /* LINTED - alignment */
+ (uint64_t *)&addr[roffs]);
+ break;
+
+ case DTRACEACT_UMOD:
+ dt_aggregate_umod(dtp,
+ /* LINTED - alignment */
+ (uint64_t *)&addr[roffs]);
+ break;
+
+ case DTRACEACT_SYM:
+ /* LINTED - alignment */
+ dt_aggregate_sym(dtp, (uint64_t *)&addr[roffs]);
+ break;
+
+ case DTRACEACT_MOD:
+ /* LINTED - alignment */
+ dt_aggregate_mod(dtp, (uint64_t *)&addr[roffs]);
+ break;
+
+ default:
+ break;
+ }
+
+ for (i = 0; i < rec->dtrd_size; i++)
+ hashval += addr[roffs + i];
+ }
+
+ ndx = hashval % hash->dtah_size;
+
+ for (h = hash->dtah_hash[ndx]; h != NULL; h = h->dtahe_next) {
+ if (h->dtahe_hashval != hashval)
+ continue;
+
+ if (h->dtahe_size != size)
+ continue;
+
+ aggdata = &h->dtahe_data;
+ data = aggdata->dtada_data;
+
+ for (j = 0; j < agg->dtagd_nrecs - 1; j++) {
+ rec = &agg->dtagd_rec[j];
+ roffs = rec->dtrd_offset;
+
+ for (i = 0; i < rec->dtrd_size; i++)
+ if (addr[roffs + i] != data[roffs + i])
+ goto hashnext;
+ }
+
+ /*
+ * We found it. Now we need to apply the aggregating
+ * action on the data here.
+ */
+ rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
+ roffs = rec->dtrd_offset;
+ /* LINTED - alignment */
+ h->dtahe_aggregate((int64_t *)&data[roffs],
+ /* LINTED - alignment */
+ (int64_t *)&addr[roffs], rec->dtrd_size);
+
+ /*
+ * If we're keeping per CPU data, apply the aggregating
+ * action there as well.
+ */
+ if (aggdata->dtada_percpu != NULL) {
+ data = aggdata->dtada_percpu[cpu];
+
+ /* LINTED - alignment */
+ h->dtahe_aggregate((int64_t *)data,
+ /* LINTED - alignment */
+ (int64_t *)&addr[roffs], rec->dtrd_size);
+ }
+
+ goto bufnext;
+hashnext:
+ continue;
+ }
+
+ /*
+ * If we're here, we couldn't find an entry for this record.
+ */
+ if ((h = malloc(sizeof (dt_ahashent_t))) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ bzero(h, sizeof (dt_ahashent_t));
+ aggdata = &h->dtahe_data;
+
+ if ((aggdata->dtada_data = malloc(size)) == NULL) {
+ free(h);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ bcopy(addr, aggdata->dtada_data, size);
+ aggdata->dtada_size = size;
+ aggdata->dtada_desc = agg;
+ aggdata->dtada_handle = dtp;
+ (void) dt_epid_lookup(dtp, agg->dtagd_epid,
+ &aggdata->dtada_edesc, &aggdata->dtada_pdesc);
+ aggdata->dtada_normal = 1;
+
+ h->dtahe_hashval = hashval;
+ h->dtahe_size = size;
+ (void) dt_aggregate_aggvarid(h);
+
+ rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
+
+ if (flags & DTRACE_A_PERCPU) {
+ int max_cpus = agp->dtat_maxcpu;
+ caddr_t *percpu = malloc(max_cpus * sizeof (caddr_t));
+
+ if (percpu == NULL) {
+ free(aggdata->dtada_data);
+ free(h);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ for (j = 0; j < max_cpus; j++) {
+ percpu[j] = malloc(rec->dtrd_size);
+
+ if (percpu[j] == NULL) {
+ while (--j >= 0)
+ free(percpu[j]);
+
+ free(aggdata->dtada_data);
+ free(h);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ if (j == cpu) {
+ bcopy(&addr[rec->dtrd_offset],
+ percpu[j], rec->dtrd_size);
+ } else {
+ bzero(percpu[j], rec->dtrd_size);
+ }
+ }
+
+ aggdata->dtada_percpu = percpu;
+ }
+
+ switch (rec->dtrd_action) {
+ case DTRACEAGG_MIN:
+ h->dtahe_aggregate = dt_aggregate_min;
+ break;
+
+ case DTRACEAGG_MAX:
+ h->dtahe_aggregate = dt_aggregate_max;
+ break;
+
+ case DTRACEAGG_LQUANTIZE:
+ h->dtahe_aggregate = dt_aggregate_lquantize;
+ break;
+
+ case DTRACEAGG_LLQUANTIZE:
+ h->dtahe_aggregate = dt_aggregate_llquantize;
+ break;
+
+ case DTRACEAGG_COUNT:
+ case DTRACEAGG_SUM:
+ case DTRACEAGG_AVG:
+ case DTRACEAGG_STDDEV:
+ case DTRACEAGG_QUANTIZE:
+ h->dtahe_aggregate = dt_aggregate_count;
+ break;
+
+ default:
+ return (dt_set_errno(dtp, EDT_BADAGG));
+ }
+
+ if (hash->dtah_hash[ndx] != NULL)
+ hash->dtah_hash[ndx]->dtahe_prev = h;
+
+ h->dtahe_next = hash->dtah_hash[ndx];
+ hash->dtah_hash[ndx] = h;
+
+ if (hash->dtah_all != NULL)
+ hash->dtah_all->dtahe_prevall = h;
+
+ h->dtahe_nextall = hash->dtah_all;
+ hash->dtah_all = h;
+bufnext:
+ offs += agg->dtagd_size;
+ }
+
+ return (0);
+}
+
+int
+dtrace_aggregate_snap(dtrace_hdl_t *dtp)
+{
+ int i, rval;
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ hrtime_t now = gethrtime();
+ dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_AGGRATE];
+
+ if (dtp->dt_lastagg != 0) {
+ if (now - dtp->dt_lastagg < interval)
+ return (0);
+
+ dtp->dt_lastagg += interval;
+ } else {
+ dtp->dt_lastagg = now;
+ }
+
+ if (!dtp->dt_active)
+ return (dt_set_errno(dtp, EINVAL));
+
+ if (agp->dtat_buf.dtbd_size == 0)
+ return (0);
+
+ for (i = 0; i < agp->dtat_ncpus; i++) {
+ if ((rval = dt_aggregate_snap_cpu(dtp, agp->dtat_cpus[i])))
+ return (rval);
+ }
+
+ return (0);
+}
+
+static int
+dt_aggregate_hashcmp(const void *lhs, const void *rhs)
+{
+ dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
+ dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
+ dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
+ dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
+
+ if (lagg->dtagd_nrecs < ragg->dtagd_nrecs)
+ return (DT_LESSTHAN);
+
+ if (lagg->dtagd_nrecs > ragg->dtagd_nrecs)
+ return (DT_GREATERTHAN);
+
+ return (0);
+}
+
+static int
+dt_aggregate_varcmp(const void *lhs, const void *rhs)
+{
+ dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
+ dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
+ dtrace_aggvarid_t lid, rid;
+
+ lid = dt_aggregate_aggvarid(lh);
+ rid = dt_aggregate_aggvarid(rh);
+
+ if (lid < rid)
+ return (DT_LESSTHAN);
+
+ if (lid > rid)
+ return (DT_GREATERTHAN);
+
+ return (0);
+}
+
+static int
+dt_aggregate_keycmp(const void *lhs, const void *rhs)
+{
+ dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
+ dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
+ dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
+ dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
+ dtrace_recdesc_t *lrec, *rrec;
+ char *ldata, *rdata;
+ int rval, i, j, keypos, nrecs;
+
+ if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0)
+ return (rval);
+
+ nrecs = lagg->dtagd_nrecs - 1;
+ assert(nrecs == ragg->dtagd_nrecs - 1);
+
+ keypos = dt_keypos + 1 >= nrecs ? 0 : dt_keypos;
+
+ for (i = 1; i < nrecs; i++) {
+ uint64_t lval, rval;
+ int ndx = i + keypos;
+
+ if (ndx >= nrecs)
+ ndx = ndx - nrecs + 1;
+
+ lrec = &lagg->dtagd_rec[ndx];
+ rrec = &ragg->dtagd_rec[ndx];
+
+ ldata = lh->dtahe_data.dtada_data + lrec->dtrd_offset;
+ rdata = rh->dtahe_data.dtada_data + rrec->dtrd_offset;
+
+ if (lrec->dtrd_size < rrec->dtrd_size)
+ return (DT_LESSTHAN);
+
+ if (lrec->dtrd_size > rrec->dtrd_size)
+ return (DT_GREATERTHAN);
+
+ switch (lrec->dtrd_size) {
+ case sizeof (uint64_t):
+ /* LINTED - alignment */
+ lval = *((uint64_t *)ldata);
+ /* LINTED - alignment */
+ rval = *((uint64_t *)rdata);
+ break;
+
+ case sizeof (uint32_t):
+ /* LINTED - alignment */
+ lval = *((uint32_t *)ldata);
+ /* LINTED - alignment */
+ rval = *((uint32_t *)rdata);
+ break;
+
+ case sizeof (uint16_t):
+ /* LINTED - alignment */
+ lval = *((uint16_t *)ldata);
+ /* LINTED - alignment */
+ rval = *((uint16_t *)rdata);
+ break;
+
+ case sizeof (uint8_t):
+ lval = *((uint8_t *)ldata);
+ rval = *((uint8_t *)rdata);
+ break;
+
+ default:
+ switch (lrec->dtrd_action) {
+ case DTRACEACT_UMOD:
+ case DTRACEACT_UADDR:
+ case DTRACEACT_USYM:
+ for (j = 0; j < 2; j++) {
+ /* LINTED - alignment */
+ lval = ((uint64_t *)ldata)[j];
+ /* LINTED - alignment */
+ rval = ((uint64_t *)rdata)[j];
+
+ if (lval < rval)
+ return (DT_LESSTHAN);
+
+ if (lval > rval)
+ return (DT_GREATERTHAN);
+ }
+
+ break;
+
+ default:
+ for (j = 0; j < lrec->dtrd_size; j++) {
+ lval = ((uint8_t *)ldata)[j];
+ rval = ((uint8_t *)rdata)[j];
+
+ if (lval < rval)
+ return (DT_LESSTHAN);
+
+ if (lval > rval)
+ return (DT_GREATERTHAN);
+ }
+ }
+
+ continue;
+ }
+
+ if (lval < rval)
+ return (DT_LESSTHAN);
+
+ if (lval > rval)
+ return (DT_GREATERTHAN);
+ }
+
+ return (0);
+}
+
+static int
+dt_aggregate_valcmp(const void *lhs, const void *rhs)
+{
+ dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
+ dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
+ dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
+ dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
+ caddr_t ldata = lh->dtahe_data.dtada_data;
+ caddr_t rdata = rh->dtahe_data.dtada_data;
+ dtrace_recdesc_t *lrec, *rrec;
+ int64_t *laddr, *raddr;
+ int rval;
+
+ assert(lagg->dtagd_nrecs == ragg->dtagd_nrecs);
+
+ lrec = &lagg->dtagd_rec[lagg->dtagd_nrecs - 1];
+ rrec = &ragg->dtagd_rec[ragg->dtagd_nrecs - 1];
+
+ assert(lrec->dtrd_action == rrec->dtrd_action);
+
+ laddr = (int64_t *)(uintptr_t)(ldata + lrec->dtrd_offset);
+ raddr = (int64_t *)(uintptr_t)(rdata + rrec->dtrd_offset);
+
+ switch (lrec->dtrd_action) {
+ case DTRACEAGG_AVG:
+ rval = dt_aggregate_averagecmp(laddr, raddr);
+ break;
+
+ case DTRACEAGG_STDDEV:
+ rval = dt_aggregate_stddevcmp(laddr, raddr);
+ break;
+
+ case DTRACEAGG_QUANTIZE:
+ rval = dt_aggregate_quantizedcmp(laddr, raddr);
+ break;
+
+ case DTRACEAGG_LQUANTIZE:
+ rval = dt_aggregate_lquantizedcmp(laddr, raddr);
+ break;
+
+ case DTRACEAGG_LLQUANTIZE:
+ rval = dt_aggregate_llquantizedcmp(laddr, raddr);
+ break;
+
+ case DTRACEAGG_COUNT:
+ case DTRACEAGG_SUM:
+ case DTRACEAGG_MIN:
+ case DTRACEAGG_MAX:
+ rval = dt_aggregate_countcmp(laddr, raddr);
+ break;
+
+ default:
+ assert(0);
+ }
+
+ return (rval);
+}
+
+static int
+dt_aggregate_valkeycmp(const void *lhs, const void *rhs)
+{
+ int rval;
+
+ if ((rval = dt_aggregate_valcmp(lhs, rhs)) != 0)
+ return (rval);
+
+ /*
+ * If we're here, the values for the two aggregation elements are
+ * equal. We already know that the key layout is the same for the two
+ * elements; we must now compare the keys themselves as a tie-breaker.
+ */
+ return (dt_aggregate_keycmp(lhs, rhs));
+}
+
+static int
+dt_aggregate_keyvarcmp(const void *lhs, const void *rhs)
+{
+ int rval;
+
+ if ((rval = dt_aggregate_keycmp(lhs, rhs)) != 0)
+ return (rval);
+
+ return (dt_aggregate_varcmp(lhs, rhs));
+}
+
+static int
+dt_aggregate_varkeycmp(const void *lhs, const void *rhs)
+{
+ int rval;
+
+ if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0)
+ return (rval);
+
+ return (dt_aggregate_keycmp(lhs, rhs));
+}
+
+static int
+dt_aggregate_valvarcmp(const void *lhs, const void *rhs)
+{
+ int rval;
+
+ if ((rval = dt_aggregate_valkeycmp(lhs, rhs)) != 0)
+ return (rval);
+
+ return (dt_aggregate_varcmp(lhs, rhs));
+}
+
+static int
+dt_aggregate_varvalcmp(const void *lhs, const void *rhs)
+{
+ int rval;
+
+ if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0)
+ return (rval);
+
+ return (dt_aggregate_valkeycmp(lhs, rhs));
+}
+
+static int
+dt_aggregate_keyvarrevcmp(const void *lhs, const void *rhs)
+{
+ return (dt_aggregate_keyvarcmp(rhs, lhs));
+}
+
+static int
+dt_aggregate_varkeyrevcmp(const void *lhs, const void *rhs)
+{
+ return (dt_aggregate_varkeycmp(rhs, lhs));
+}
+
+static int
+dt_aggregate_valvarrevcmp(const void *lhs, const void *rhs)
+{
+ return (dt_aggregate_valvarcmp(rhs, lhs));
+}
+
+static int
+dt_aggregate_varvalrevcmp(const void *lhs, const void *rhs)
+{
+ return (dt_aggregate_varvalcmp(rhs, lhs));
+}
+
+static int
+dt_aggregate_bundlecmp(const void *lhs, const void *rhs)
+{
+ dt_ahashent_t **lh = *((dt_ahashent_t ***)lhs);
+ dt_ahashent_t **rh = *((dt_ahashent_t ***)rhs);
+ int i, rval;
+
+ if (dt_keysort) {
+ /*
+ * If we're sorting on keys, we need to scan until we find the
+ * last entry -- that's the representative key. (The order of
+ * the bundle is values followed by key to accommodate the
+ * default behavior of sorting by value.) If the keys are
+ * equal, we'll fall into the value comparison loop, below.
+ */
+ for (i = 0; lh[i + 1] != NULL; i++)
+ continue;
+
+ assert(i != 0);
+ assert(rh[i + 1] == NULL);
+
+ if ((rval = dt_aggregate_keycmp(&lh[i], &rh[i])) != 0)
+ return (rval);
+ }
+
+ for (i = 0; ; i++) {
+ if (lh[i + 1] == NULL) {
+ /*
+ * All of the values are equal; if we're sorting on
+ * keys, then we're only here because the keys were
+ * found to be equal and these records are therefore
+ * equal. If we're not sorting on keys, we'll use the
+ * key comparison from the representative key as the
+ * tie-breaker.
+ */
+ if (dt_keysort)
+ return (0);
+
+ assert(i != 0);
+ assert(rh[i + 1] == NULL);
+ return (dt_aggregate_keycmp(&lh[i], &rh[i]));
+ } else {
+ if ((rval = dt_aggregate_valcmp(&lh[i], &rh[i])) != 0)
+ return (rval);
+ }
+ }
+}
+
+int
+dt_aggregate_go(dtrace_hdl_t *dtp)
+{
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ dtrace_optval_t size, cpu;
+ dtrace_bufdesc_t *buf = &agp->dtat_buf;
+ int rval, i;
+
+ assert(agp->dtat_maxcpu == 0);
+ assert(agp->dtat_ncpu == 0);
+ assert(agp->dtat_cpus == NULL);
+
+ agp->dtat_maxcpu = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
+ agp->dtat_ncpu = dt_sysconf(dtp, _SC_NPROCESSORS_MAX);
+ agp->dtat_cpus = malloc(agp->dtat_ncpu * sizeof (processorid_t));
+
+ if (agp->dtat_cpus == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ /*
+ * Use the aggregation buffer size as reloaded from the kernel.
+ */
+ size = dtp->dt_options[DTRACEOPT_AGGSIZE];
+
+ rval = dtrace_getopt(dtp, "aggsize", &size);
+ assert(rval == 0);
+
+ if (size == 0 || size == DTRACEOPT_UNSET)
+ return (0);
+
+ buf = &agp->dtat_buf;
+ buf->dtbd_size = size;
+
+ if ((buf->dtbd_data = malloc(buf->dtbd_size)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ /*
+ * Now query for the CPUs enabled.
+ */
+ rval = dtrace_getopt(dtp, "cpu", &cpu);
+ assert(rval == 0 && cpu != DTRACEOPT_UNSET);
+
+ if (cpu != DTRACE_CPUALL) {
+ assert(cpu < agp->dtat_ncpu);
+ agp->dtat_cpus[agp->dtat_ncpus++] = (processorid_t)cpu;
+
+ return (0);
+ }
+
+ agp->dtat_ncpus = 0;
+ for (i = 0; i < agp->dtat_maxcpu; i++) {
+ if (dt_status(dtp, i) == -1)
+ continue;
+
+ agp->dtat_cpus[agp->dtat_ncpus++] = i;
+ }
+
+ return (0);
+}
+
+static int
+dt_aggwalk_rval(dtrace_hdl_t *dtp, dt_ahashent_t *h, int rval)
+{
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ dtrace_aggdata_t *data;
+ dtrace_aggdesc_t *aggdesc;
+ dtrace_recdesc_t *rec;
+ int i;
+
+ switch (rval) {
+ case DTRACE_AGGWALK_NEXT:
+ break;
+
+ case DTRACE_AGGWALK_CLEAR: {
+ uint32_t size, offs = 0;
+
+ aggdesc = h->dtahe_data.dtada_desc;
+ rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
+ size = rec->dtrd_size;
+ data = &h->dtahe_data;
+
+ if (rec->dtrd_action == DTRACEAGG_LQUANTIZE) {
+ offs = sizeof (uint64_t);
+ size -= sizeof (uint64_t);
+ }
+
+ bzero(&data->dtada_data[rec->dtrd_offset] + offs, size);
+
+ if (data->dtada_percpu == NULL)
+ break;
+
+ for (i = 0; i < dtp->dt_aggregate.dtat_maxcpu; i++)
+ bzero(data->dtada_percpu[i] + offs, size);
+ break;
+ }
+
+ case DTRACE_AGGWALK_ERROR:
+ /*
+ * We assume that errno is already set in this case.
+ */
+ return (dt_set_errno(dtp, errno));
+
+ case DTRACE_AGGWALK_ABORT:
+ return (dt_set_errno(dtp, EDT_DIRABORT));
+
+ case DTRACE_AGGWALK_DENORMALIZE:
+ h->dtahe_data.dtada_normal = 1;
+ return (0);
+
+ case DTRACE_AGGWALK_NORMALIZE:
+ if (h->dtahe_data.dtada_normal == 0) {
+ h->dtahe_data.dtada_normal = 1;
+ return (dt_set_errno(dtp, EDT_BADRVAL));
+ }
+
+ return (0);
+
+ case DTRACE_AGGWALK_REMOVE: {
+ dtrace_aggdata_t *aggdata = &h->dtahe_data;
+ int max_cpus = agp->dtat_maxcpu;
+
+ /*
+ * First, remove this hash entry from its hash chain.
+ */
+ if (h->dtahe_prev != NULL) {
+ h->dtahe_prev->dtahe_next = h->dtahe_next;
+ } else {
+ dt_ahash_t *hash = &agp->dtat_hash;
+ size_t ndx = h->dtahe_hashval % hash->dtah_size;
+
+ assert(hash->dtah_hash[ndx] == h);
+ hash->dtah_hash[ndx] = h->dtahe_next;
+ }
+
+ if (h->dtahe_next != NULL)
+ h->dtahe_next->dtahe_prev = h->dtahe_prev;
+
+ /*
+ * Now remove it from the list of all hash entries.
+ */
+ if (h->dtahe_prevall != NULL) {
+ h->dtahe_prevall->dtahe_nextall = h->dtahe_nextall;
+ } else {
+ dt_ahash_t *hash = &agp->dtat_hash;
+
+ assert(hash->dtah_all == h);
+ hash->dtah_all = h->dtahe_nextall;
+ }
+
+ if (h->dtahe_nextall != NULL)
+ h->dtahe_nextall->dtahe_prevall = h->dtahe_prevall;
+
+ /*
+ * We're unlinked. We can safely destroy the data.
+ */
+ if (aggdata->dtada_percpu != NULL) {
+ for (i = 0; i < max_cpus; i++)
+ free(aggdata->dtada_percpu[i]);
+ free(aggdata->dtada_percpu);
+ }
+
+ free(aggdata->dtada_data);
+ free(h);
+
+ return (0);
+ }
+
+ default:
+ return (dt_set_errno(dtp, EDT_BADRVAL));
+ }
+
+ return (0);
+}
+
+void
+dt_aggregate_qsort(dtrace_hdl_t *dtp, void *base, size_t nel, size_t width,
+ int (*compar)(const void *, const void *))
+{
+ int rev = dt_revsort, key = dt_keysort, keypos = dt_keypos;
+ dtrace_optval_t keyposopt = dtp->dt_options[DTRACEOPT_AGGSORTKEYPOS];
+
+ dt_revsort = (dtp->dt_options[DTRACEOPT_AGGSORTREV] != DTRACEOPT_UNSET);
+ dt_keysort = (dtp->dt_options[DTRACEOPT_AGGSORTKEY] != DTRACEOPT_UNSET);
+
+ if (keyposopt != DTRACEOPT_UNSET && keyposopt <= INT_MAX) {
+ dt_keypos = (int)keyposopt;
+ } else {
+ dt_keypos = 0;
+ }
+
+ if (compar == NULL) {
+ if (!dt_keysort) {
+ compar = dt_aggregate_varvalcmp;
+ } else {
+ compar = dt_aggregate_varkeycmp;
+ }
+ }
+
+ qsort(base, nel, width, compar);
+
+ dt_revsort = rev;
+ dt_keysort = key;
+ dt_keypos = keypos;
+}
+
+int
+dtrace_aggregate_walk(dtrace_hdl_t *dtp, dtrace_aggregate_f *func, void *arg)
+{
+ dt_ahashent_t *h, *next;
+ dt_ahash_t *hash = &dtp->dt_aggregate.dtat_hash;
+
+ for (h = hash->dtah_all; h != NULL; h = next) {
+ /*
+ * dt_aggwalk_rval() can potentially remove the current hash
+ * entry; we need to load the next hash entry before calling
+ * into it.
+ */
+ next = h->dtahe_nextall;
+
+ if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+dt_aggregate_total(dtrace_hdl_t *dtp, boolean_t clear)
+{
+ dt_ahashent_t *h;
+ dtrace_aggdata_t **total;
+ dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id;
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ dt_ahash_t *hash = &agp->dtat_hash;
+ uint32_t tflags;
+
+ tflags = DTRACE_A_TOTAL | DTRACE_A_HASNEGATIVES | DTRACE_A_HASPOSITIVES;
+
+ /*
+ * If we need to deliver per-aggregation totals, we're going to take
+ * three passes over the aggregate: one to clear everything out and
+ * determine our maximum aggregation ID, one to actually total
+ * everything up, and a final pass to assign the totals to the
+ * individual elements.
+ */
+ for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+ dtrace_aggdata_t *aggdata = &h->dtahe_data;
+
+ if ((id = dt_aggregate_aggvarid(h)) > max)
+ max = id;
+
+ aggdata->dtada_total = 0;
+ aggdata->dtada_flags &= ~tflags;
+ }
+
+ if (clear || max == DTRACE_AGGVARIDNONE)
+ return (0);
+
+ total = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *));
+
+ if (total == NULL)
+ return (-1);
+
+ for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+ dtrace_aggdata_t *aggdata = &h->dtahe_data;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ dtrace_recdesc_t *rec;
+ caddr_t data;
+ int64_t val, *addr;
+
+ rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
+ data = aggdata->dtada_data;
+ addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset);
+
+ switch (rec->dtrd_action) {
+ case DTRACEAGG_STDDEV:
+ val = dt_stddev((uint64_t *)addr, 1);
+ break;
+
+ case DTRACEAGG_SUM:
+ case DTRACEAGG_COUNT:
+ val = *addr;
+ break;
+
+ case DTRACEAGG_AVG:
+ val = addr[0] ? (addr[1] / addr[0]) : 0;
+ break;
+
+ default:
+ continue;
+ }
+
+ if (total[agg->dtagd_varid] == NULL) {
+ total[agg->dtagd_varid] = aggdata;
+ aggdata->dtada_flags |= DTRACE_A_TOTAL;
+ } else {
+ aggdata = total[agg->dtagd_varid];
+ }
+
+ if (val > 0)
+ aggdata->dtada_flags |= DTRACE_A_HASPOSITIVES;
+
+ if (val < 0) {
+ aggdata->dtada_flags |= DTRACE_A_HASNEGATIVES;
+ val = -val;
+ }
+
+ if (dtp->dt_options[DTRACEOPT_AGGZOOM] != DTRACEOPT_UNSET) {
+ val = (int64_t)((long double)val *
+ (1 / DTRACE_AGGZOOM_MAX));
+
+ if (val > aggdata->dtada_total)
+ aggdata->dtada_total = val;
+ } else {
+ aggdata->dtada_total += val;
+ }
+ }
+
+ /*
+ * And now one final pass to set everyone's total.
+ */
+ for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+ dtrace_aggdata_t *aggdata = &h->dtahe_data, *t;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+
+ if ((t = total[agg->dtagd_varid]) == NULL || aggdata == t)
+ continue;
+
+ aggdata->dtada_total = t->dtada_total;
+ aggdata->dtada_flags |= (t->dtada_flags & tflags);
+ }
+
+ dt_free(dtp, total);
+
+ return (0);
+}
+
+static int
+dt_aggregate_minmaxbin(dtrace_hdl_t *dtp, boolean_t clear)
+{
+ dt_ahashent_t *h;
+ dtrace_aggdata_t **minmax;
+ dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id;
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ dt_ahash_t *hash = &agp->dtat_hash;
+
+ for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+ dtrace_aggdata_t *aggdata = &h->dtahe_data;
+
+ if ((id = dt_aggregate_aggvarid(h)) > max)
+ max = id;
+
+ aggdata->dtada_minbin = 0;
+ aggdata->dtada_maxbin = 0;
+ aggdata->dtada_flags &= ~DTRACE_A_MINMAXBIN;
+ }
+
+ if (clear || max == DTRACE_AGGVARIDNONE)
+ return (0);
+
+ minmax = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *));
+
+ if (minmax == NULL)
+ return (-1);
+
+ for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+ dtrace_aggdata_t *aggdata = &h->dtahe_data;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ dtrace_recdesc_t *rec;
+ caddr_t data;
+ int64_t *addr;
+ int minbin = -1, maxbin = -1, i;
+ int start = 0, size;
+
+ rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
+ size = rec->dtrd_size / sizeof (int64_t);
+ data = aggdata->dtada_data;
+ addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset);
+
+ switch (rec->dtrd_action) {
+ case DTRACEAGG_LQUANTIZE:
+ /*
+ * For lquantize(), we always display the entire range
+ * of the aggregation when aggpack is set.
+ */
+ start = 1;
+ minbin = start;
+ maxbin = size - 1 - start;
+ break;
+
+ case DTRACEAGG_QUANTIZE:
+ for (i = start; i < size; i++) {
+ if (!addr[i])
+ continue;
+
+ if (minbin == -1)
+ minbin = i - start;
+
+ maxbin = i - start;
+ }
+
+ if (minbin == -1) {
+ /*
+ * If we have no data (e.g., due to a clear()
+ * or negative increments), we'll use the
+ * zero bucket as both our min and max.
+ */
+ minbin = maxbin = DTRACE_QUANTIZE_ZEROBUCKET;
+ }
+
+ break;
+
+ default:
+ continue;
+ }
+
+ if (minmax[agg->dtagd_varid] == NULL) {
+ minmax[agg->dtagd_varid] = aggdata;
+ aggdata->dtada_flags |= DTRACE_A_MINMAXBIN;
+ aggdata->dtada_minbin = minbin;
+ aggdata->dtada_maxbin = maxbin;
+ continue;
+ }
+
+ if (minbin < minmax[agg->dtagd_varid]->dtada_minbin)
+ minmax[agg->dtagd_varid]->dtada_minbin = minbin;
+
+ if (maxbin > minmax[agg->dtagd_varid]->dtada_maxbin)
+ minmax[agg->dtagd_varid]->dtada_maxbin = maxbin;
+ }
+
+ /*
+ * And now one final pass to set everyone's minbin and maxbin.
+ */
+ for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+ dtrace_aggdata_t *aggdata = &h->dtahe_data, *mm;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+
+ if ((mm = minmax[agg->dtagd_varid]) == NULL || aggdata == mm)
+ continue;
+
+ aggdata->dtada_minbin = mm->dtada_minbin;
+ aggdata->dtada_maxbin = mm->dtada_maxbin;
+ aggdata->dtada_flags |= DTRACE_A_MINMAXBIN;
+ }
+
+ dt_free(dtp, minmax);
+
+ return (0);
+}
+
+static int
+dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg,
+ int (*sfunc)(const void *, const void *))
+{
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ dt_ahashent_t *h, **sorted;
+ dt_ahash_t *hash = &agp->dtat_hash;
+ size_t i, nentries = 0;
+ int rval = -1;
+
+ agp->dtat_flags &= ~(DTRACE_A_TOTAL | DTRACE_A_MINMAXBIN);
+
+ if (dtp->dt_options[DTRACEOPT_AGGHIST] != DTRACEOPT_UNSET) {
+ agp->dtat_flags |= DTRACE_A_TOTAL;
+
+ if (dt_aggregate_total(dtp, B_FALSE) != 0)
+ return (-1);
+ }
+
+ if (dtp->dt_options[DTRACEOPT_AGGPACK] != DTRACEOPT_UNSET) {
+ agp->dtat_flags |= DTRACE_A_MINMAXBIN;
+
+ if (dt_aggregate_minmaxbin(dtp, B_FALSE) != 0)
+ return (-1);
+ }
+
+ for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall)
+ nentries++;
+
+ sorted = dt_alloc(dtp, nentries * sizeof (dt_ahashent_t *));
+
+ if (sorted == NULL)
+ goto out;
+
+ for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall)
+ sorted[i++] = h;
+
+ (void) pthread_mutex_lock(&dt_qsort_lock);
+
+ if (sfunc == NULL) {
+ dt_aggregate_qsort(dtp, sorted, nentries,
+ sizeof (dt_ahashent_t *), NULL);
+ } else {
+ /*
+ * If we've been explicitly passed a sorting function,
+ * we'll use that -- ignoring the values of the "aggsortrev",
+ * "aggsortkey" and "aggsortkeypos" options.
+ */
+ qsort(sorted, nentries, sizeof (dt_ahashent_t *), sfunc);
+ }
+
+ (void) pthread_mutex_unlock(&dt_qsort_lock);
+
+ for (i = 0; i < nentries; i++) {
+ h = sorted[i];
+
+ if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
+ goto out;
+ }
+
+ rval = 0;
+out:
+ if (agp->dtat_flags & DTRACE_A_TOTAL)
+ (void) dt_aggregate_total(dtp, B_TRUE);
+
+ if (agp->dtat_flags & DTRACE_A_MINMAXBIN)
+ (void) dt_aggregate_minmaxbin(dtp, B_TRUE);
+
+ dt_free(dtp, sorted);
+ return (rval);
+}
+
+int
+dtrace_aggregate_walk_sorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg)
+{
+ return (dt_aggregate_walk_sorted(dtp, func, arg, NULL));
+}
+
+int
+dtrace_aggregate_walk_keysorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg)
+{
+ return (dt_aggregate_walk_sorted(dtp, func,
+ arg, dt_aggregate_varkeycmp));
+}
+
+int
+dtrace_aggregate_walk_valsorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg)
+{
+ return (dt_aggregate_walk_sorted(dtp, func,
+ arg, dt_aggregate_varvalcmp));
+}
+
+int
+dtrace_aggregate_walk_keyvarsorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg)
+{
+ return (dt_aggregate_walk_sorted(dtp, func,
+ arg, dt_aggregate_keyvarcmp));
+}
+
+int
+dtrace_aggregate_walk_valvarsorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg)
+{
+ return (dt_aggregate_walk_sorted(dtp, func,
+ arg, dt_aggregate_valvarcmp));
+}
+
+int
+dtrace_aggregate_walk_keyrevsorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg)
+{
+ return (dt_aggregate_walk_sorted(dtp, func,
+ arg, dt_aggregate_varkeyrevcmp));
+}
+
+int
+dtrace_aggregate_walk_valrevsorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg)
+{
+ return (dt_aggregate_walk_sorted(dtp, func,
+ arg, dt_aggregate_varvalrevcmp));
+}
+
+int
+dtrace_aggregate_walk_keyvarrevsorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg)
+{
+ return (dt_aggregate_walk_sorted(dtp, func,
+ arg, dt_aggregate_keyvarrevcmp));
+}
+
+int
+dtrace_aggregate_walk_valvarrevsorted(dtrace_hdl_t *dtp,
+ dtrace_aggregate_f *func, void *arg)
+{
+ return (dt_aggregate_walk_sorted(dtp, func,
+ arg, dt_aggregate_valvarrevcmp));
+}
+
+int
+dtrace_aggregate_walk_joined(dtrace_hdl_t *dtp, dtrace_aggvarid_t *aggvars,
+ int naggvars, dtrace_aggregate_walk_joined_f *func, void *arg)
+{
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ dt_ahashent_t *h, **sorted = NULL, ***bundle, **nbundle;
+ const dtrace_aggdata_t **data;
+ dt_ahashent_t *zaggdata = NULL;
+ dt_ahash_t *hash = &agp->dtat_hash;
+ size_t nentries = 0, nbundles = 0, start, zsize = 0, bundlesize;
+ dtrace_aggvarid_t max = 0, aggvar;
+ int rval = -1, *map, *remap = NULL;
+ int i, j;
+ dtrace_optval_t sortpos = dtp->dt_options[DTRACEOPT_AGGSORTPOS];
+
+ /*
+ * If the sorting position is greater than the number of aggregation
+ * variable IDs, we silently set it to 0.
+ */
+ if (sortpos == DTRACEOPT_UNSET || sortpos >= naggvars)
+ sortpos = 0;
+
+ /*
+ * First we need to translate the specified aggregation variable IDs
+ * into a linear map that will allow us to translate an aggregation
+ * variable ID into its position in the specified aggvars.
+ */
+ for (i = 0; i < naggvars; i++) {
+ if (aggvars[i] == DTRACE_AGGVARIDNONE || aggvars[i] < 0)
+ return (dt_set_errno(dtp, EDT_BADAGGVAR));
+
+ if (aggvars[i] > max)
+ max = aggvars[i];
+ }
+
+ if ((map = dt_zalloc(dtp, (max + 1) * sizeof (int))) == NULL)
+ return (-1);
+
+ zaggdata = dt_zalloc(dtp, naggvars * sizeof (dt_ahashent_t));
+
+ if (zaggdata == NULL)
+ goto out;
+
+ for (i = 0; i < naggvars; i++) {
+ int ndx = i + sortpos;
+
+ if (ndx >= naggvars)
+ ndx -= naggvars;
+
+ aggvar = aggvars[ndx];
+ assert(aggvar <= max);
+
+ if (map[aggvar]) {
+ /*
+ * We have an aggregation variable that is present
+ * more than once in the array of aggregation
+ * variables. While it's unclear why one might want
+ * to do this, it's legal. To support this construct,
+ * we will allocate a remap that will indicate the
+ * position from which this aggregation variable
+ * should be pulled. (That is, where the remap will
+ * map from one position to another.)
+ */
+ if (remap == NULL) {
+ remap = dt_zalloc(dtp, naggvars * sizeof (int));
+
+ if (remap == NULL)
+ goto out;
+ }
+
+ /*
+ * Given that the variable is already present, assert
+ * that following through the mapping and adjusting
+ * for the sort position yields the same aggregation
+ * variable ID.
+ */
+ assert(aggvars[(map[aggvar] - 1 + sortpos) %
+ naggvars] == aggvars[ndx]);
+
+ remap[i] = map[aggvar];
+ continue;
+ }
+
+ map[aggvar] = i + 1;
+ }
+
+ /*
+ * We need to take two passes over the data to size our allocation, so
+ * we'll use the first pass to also fill in the zero-filled data to be
+ * used to properly format a zero-valued aggregation.
+ */
+ for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+ dtrace_aggvarid_t id;
+ int ndx;
+
+ if ((id = dt_aggregate_aggvarid(h)) > max || !(ndx = map[id]))
+ continue;
+
+ if (zaggdata[ndx - 1].dtahe_size == 0) {
+ zaggdata[ndx - 1].dtahe_size = h->dtahe_size;
+ zaggdata[ndx - 1].dtahe_data = h->dtahe_data;
+ }
+
+ nentries++;
+ }
+
+ if (nentries == 0) {
+ /*
+ * We couldn't find any entries; there is nothing else to do.
+ */
+ rval = 0;
+ goto out;
+ }
+
+ /*
+ * Before we sort the data, we're going to look for any holes in our
+ * zero-filled data. This will occur if an aggregation variable that
+ * we are being asked to print has not yet been assigned the result of
+ * any aggregating action for _any_ tuple. The issue becomes that we
+ * would like a zero value to be printed for all columns for this
+ * aggregation, but without any record description, we don't know the
+ * aggregating action that corresponds to the aggregation variable. To
+ * try to find a match, we're simply going to lookup aggregation IDs
+ * (which are guaranteed to be contiguous and to start from 1), looking
+ * for the specified aggregation variable ID. If we find a match,
+ * we'll use that. If we iterate over all aggregation IDs and don't
+ * find a match, then we must be an anonymous enabling. (Anonymous
+ * enablings can't currently derive either aggregation variable IDs or
+ * aggregation variable names given only an aggregation ID.) In this
+ * obscure case (anonymous enabling, multiple aggregation printa() with
+ * some aggregations not represented for any tuple), our defined
+ * behavior is that the zero will be printed in the format of the first
+ * aggregation variable that contains any non-zero value.
+ */
+ for (i = 0; i < naggvars; i++) {
+ if (zaggdata[i].dtahe_size == 0) {
+ dtrace_aggvarid_t aggvar;
+
+ aggvar = aggvars[(i - sortpos + naggvars) % naggvars];
+ assert(zaggdata[i].dtahe_data.dtada_data == NULL);
+
+ for (j = DTRACE_AGGIDNONE + 1; ; j++) {
+ dtrace_aggdesc_t *agg;
+ dtrace_aggdata_t *aggdata;
+
+ if (dt_aggid_lookup(dtp, j, &agg) != 0)
+ break;
+
+ if (agg->dtagd_varid != aggvar)
+ continue;
+
+ /*
+ * We have our description -- now we need to
+ * cons up the zaggdata entry for it.
+ */
+ aggdata = &zaggdata[i].dtahe_data;
+ aggdata->dtada_size = agg->dtagd_size;
+ aggdata->dtada_desc = agg;
+ aggdata->dtada_handle = dtp;
+ (void) dt_epid_lookup(dtp, agg->dtagd_epid,
+ &aggdata->dtada_edesc,
+ &aggdata->dtada_pdesc);
+ aggdata->dtada_normal = 1;
+ zaggdata[i].dtahe_hashval = 0;
+ zaggdata[i].dtahe_size = agg->dtagd_size;
+ break;
+ }
+
+ if (zaggdata[i].dtahe_size == 0) {
+ caddr_t data;
+
+ /*
+ * We couldn't find this aggregation, meaning
+ * that we have never seen it before for any
+ * tuple _and_ this is an anonymous enabling.
+ * That is, we're in the obscure case outlined
+ * above. In this case, our defined behavior
+ * is to format the data in the format of the
+ * first non-zero aggregation -- of which, of
+ * course, we know there to be at least one
+ * (or nentries would have been zero).
+ */
+ for (j = 0; j < naggvars; j++) {
+ if (zaggdata[j].dtahe_size != 0)
+ break;
+ }
+
+ assert(j < naggvars);
+ zaggdata[i] = zaggdata[j];
+
+ data = zaggdata[i].dtahe_data.dtada_data;
+ assert(data != NULL);
+ }
+ }
+ }
+
+ /*
+ * Now we need to allocate our zero-filled data for use for
+ * aggregations that don't have a value corresponding to a given key.
+ */
+ for (i = 0; i < naggvars; i++) {
+ dtrace_aggdata_t *aggdata = &zaggdata[i].dtahe_data;
+ dtrace_aggdesc_t *aggdesc = aggdata->dtada_desc;
+ dtrace_recdesc_t *rec;
+ uint64_t larg;
+ caddr_t zdata;
+
+ zsize = zaggdata[i].dtahe_size;
+ assert(zsize != 0);
+
+ if ((zdata = dt_zalloc(dtp, zsize)) == NULL) {
+ /*
+ * If we failed to allocated some zero-filled data, we
+ * need to zero out the remaining dtada_data pointers
+ * to prevent the wrong data from being freed below.
+ */
+ for (j = i; j < naggvars; j++)
+ zaggdata[j].dtahe_data.dtada_data = NULL;
+ goto out;
+ }
+
+ aggvar = aggvars[(i - sortpos + naggvars) % naggvars];
+
+ /*
+ * First, the easy bit. To maintain compatibility with
+ * consumers that pull the compiler-generated ID out of the
+ * data, we put that ID at the top of the zero-filled data.
+ */
+ rec = &aggdesc->dtagd_rec[0];
+ /* LINTED - alignment */
+ *((dtrace_aggvarid_t *)(zdata + rec->dtrd_offset)) = aggvar;
+
+ rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
+
+ /*
+ * Now for the more complicated part. If (and only if) this
+ * is an lquantize() aggregating action, zero-filled data is
+ * not equivalent to an empty record: we must also get the
+ * parameters for the lquantize().
+ */
+ if (rec->dtrd_action == DTRACEAGG_LQUANTIZE) {
+ if (aggdata->dtada_data != NULL) {
+ /*
+ * The easier case here is if we actually have
+ * some prototype data -- in which case we
+ * manually dig it out of the aggregation
+ * record.
+ */
+ /* LINTED - alignment */
+ larg = *((uint64_t *)(aggdata->dtada_data +
+ rec->dtrd_offset));
+ } else {
+ /*
+ * We don't have any prototype data. As a
+ * result, we know that we _do_ have the
+ * compiler-generated information. (If this
+ * were an anonymous enabling, all of our
+ * zero-filled data would have prototype data
+ * -- either directly or indirectly.) So as
+ * gross as it is, we'll grovel around in the
+ * compiler-generated information to find the
+ * lquantize() parameters.
+ */
+ dtrace_stmtdesc_t *sdp;
+ dt_ident_t *aid;
+ dt_idsig_t *isp;
+
+ sdp = (dtrace_stmtdesc_t *)(uintptr_t)
+ aggdesc->dtagd_rec[0].dtrd_uarg;
+ aid = sdp->dtsd_aggdata;
+ isp = (dt_idsig_t *)aid->di_data;
+ assert(isp->dis_auxinfo != 0);
+ larg = isp->dis_auxinfo;
+ }
+
+ /* LINTED - alignment */
+ *((uint64_t *)(zdata + rec->dtrd_offset)) = larg;
+ }
+
+ aggdata->dtada_data = zdata;
+ }
+
+ /*
+ * Now that we've dealt with setting up our zero-filled data, we can
+ * allocate our sorted array, and take another pass over the data to
+ * fill it.
+ */
+ sorted = dt_alloc(dtp, nentries * sizeof (dt_ahashent_t *));
+
+ if (sorted == NULL)
+ goto out;
+
+ for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall) {
+ dtrace_aggvarid_t id;
+
+ if ((id = dt_aggregate_aggvarid(h)) > max || !map[id])
+ continue;
+
+ sorted[i++] = h;
+ }
+
+ assert(i == nentries);
+
+ /*
+ * We've loaded our array; now we need to sort by value to allow us
+ * to create bundles of like value. We're going to acquire the
+ * dt_qsort_lock here, and hold it across all of our subsequent
+ * comparison and sorting.
+ */
+ (void) pthread_mutex_lock(&dt_qsort_lock);
+
+ qsort(sorted, nentries, sizeof (dt_ahashent_t *),
+ dt_aggregate_keyvarcmp);
+
+ /*
+ * Now we need to go through and create bundles. Because the number
+ * of bundles is bounded by the size of the sorted array, we're going
+ * to reuse the underlying storage. And note that "bundle" is an
+ * array of pointers to arrays of pointers to dt_ahashent_t -- making
+ * its type (regrettably) "dt_ahashent_t ***". (Regrettable because
+ * '*' -- like '_' and 'X' -- should never appear in triplicate in
+ * an ideal world.)
+ */
+ bundle = (dt_ahashent_t ***)sorted;
+
+ for (i = 1, start = 0; i <= nentries; i++) {
+ if (i < nentries &&
+ dt_aggregate_keycmp(&sorted[i], &sorted[i - 1]) == 0)
+ continue;
+
+ /*
+ * We have a bundle boundary. Everything from start to
+ * (i - 1) belongs in one bundle.
+ */
+ assert(i - start <= naggvars);
+ bundlesize = (naggvars + 2) * sizeof (dt_ahashent_t *);
+
+ if ((nbundle = dt_zalloc(dtp, bundlesize)) == NULL) {
+ (void) pthread_mutex_unlock(&dt_qsort_lock);
+ goto out;
+ }
+
+ for (j = start; j < i; j++) {
+ dtrace_aggvarid_t id = dt_aggregate_aggvarid(sorted[j]);
+
+ assert(id <= max);
+ assert(map[id] != 0);
+ assert(map[id] - 1 < naggvars);
+ assert(nbundle[map[id] - 1] == NULL);
+ nbundle[map[id] - 1] = sorted[j];
+
+ if (nbundle[naggvars] == NULL)
+ nbundle[naggvars] = sorted[j];
+ }
+
+ for (j = 0; j < naggvars; j++) {
+ if (nbundle[j] != NULL)
+ continue;
+
+ /*
+ * Before we assume that this aggregation variable
+ * isn't present (and fall back to using the
+ * zero-filled data allocated earlier), check the
+ * remap. If we have a remapping, we'll drop it in
+ * here. Note that we might be remapping an
+ * aggregation variable that isn't present for this
+ * key; in this case, the aggregation data that we
+ * copy will point to the zeroed data.
+ */
+ if (remap != NULL && remap[j]) {
+ assert(remap[j] - 1 < j);
+ assert(nbundle[remap[j] - 1] != NULL);
+ nbundle[j] = nbundle[remap[j] - 1];
+ } else {
+ nbundle[j] = &zaggdata[j];
+ }
+ }
+
+ bundle[nbundles++] = nbundle;
+ start = i;
+ }
+
+ /*
+ * Now we need to re-sort based on the first value.
+ */
+ dt_aggregate_qsort(dtp, bundle, nbundles, sizeof (dt_ahashent_t **),
+ dt_aggregate_bundlecmp);
+
+ (void) pthread_mutex_unlock(&dt_qsort_lock);
+
+ /*
+ * We're done! Now we just need to go back over the sorted bundles,
+ * calling the function.
+ */
+ data = alloca((naggvars + 1) * sizeof (dtrace_aggdata_t *));
+
+ for (i = 0; i < nbundles; i++) {
+ for (j = 0; j < naggvars; j++)
+ data[j + 1] = NULL;
+
+ for (j = 0; j < naggvars; j++) {
+ int ndx = j - sortpos;
+
+ if (ndx < 0)
+ ndx += naggvars;
+
+ assert(bundle[i][ndx] != NULL);
+ data[j + 1] = &bundle[i][ndx]->dtahe_data;
+ }
+
+ for (j = 0; j < naggvars; j++)
+ assert(data[j + 1] != NULL);
+
+ /*
+ * The representative key is the last element in the bundle.
+ * Assert that we have one, and then set it to be the first
+ * element of data.
+ */
+ assert(bundle[i][j] != NULL);
+ data[0] = &bundle[i][j]->dtahe_data;
+
+ if ((rval = func(data, naggvars + 1, arg)) == -1)
+ goto out;
+ }
+
+ rval = 0;
+out:
+ for (i = 0; i < nbundles; i++)
+ dt_free(dtp, bundle[i]);
+
+ if (zaggdata != NULL) {
+ for (i = 0; i < naggvars; i++)
+ dt_free(dtp, zaggdata[i].dtahe_data.dtada_data);
+ }
+
+ dt_free(dtp, zaggdata);
+ dt_free(dtp, sorted);
+ dt_free(dtp, remap);
+ dt_free(dtp, map);
+
+ return (rval);
+}
+
+int
+dtrace_aggregate_print(dtrace_hdl_t *dtp, FILE *fp,
+ dtrace_aggregate_walk_f *func)
+{
+ dt_print_aggdata_t pd;
+
+ bzero(&pd, sizeof (pd));
+
+ pd.dtpa_dtp = dtp;
+ pd.dtpa_fp = fp;
+ pd.dtpa_allunprint = 1;
+
+ if (func == NULL)
+ func = dtrace_aggregate_walk_sorted;
+
+ if ((*func)(dtp, dt_print_agg, &pd) == -1)
+ return (dt_set_errno(dtp, dtp->dt_errno));
+
+ return (0);
+}
+
+void
+dtrace_aggregate_clear(dtrace_hdl_t *dtp)
+{
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ dt_ahash_t *hash = &agp->dtat_hash;
+ dt_ahashent_t *h;
+ dtrace_aggdata_t *data;
+ dtrace_aggdesc_t *aggdesc;
+ dtrace_recdesc_t *rec;
+ int i, max_cpus = agp->dtat_maxcpu;
+
+ for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+ aggdesc = h->dtahe_data.dtada_desc;
+ rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
+ data = &h->dtahe_data;
+
+ bzero(&data->dtada_data[rec->dtrd_offset], rec->dtrd_size);
+
+ if (data->dtada_percpu == NULL)
+ continue;
+
+ for (i = 0; i < max_cpus; i++)
+ bzero(data->dtada_percpu[i], rec->dtrd_size);
+ }
+}
+
+void
+dt_aggregate_destroy(dtrace_hdl_t *dtp)
+{
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+ dt_ahash_t *hash = &agp->dtat_hash;
+ dt_ahashent_t *h, *next;
+ dtrace_aggdata_t *aggdata;
+ int i, max_cpus = agp->dtat_maxcpu;
+
+ if (hash->dtah_hash == NULL) {
+ assert(hash->dtah_all == NULL);
+ } else {
+ free(hash->dtah_hash);
+
+ for (h = hash->dtah_all; h != NULL; h = next) {
+ next = h->dtahe_nextall;
+
+ aggdata = &h->dtahe_data;
+
+ if (aggdata->dtada_percpu != NULL) {
+ for (i = 0; i < max_cpus; i++)
+ free(aggdata->dtada_percpu[i]);
+ free(aggdata->dtada_percpu);
+ }
+
+ free(aggdata->dtada_data);
+ free(h);
+ }
+
+ hash->dtah_hash = NULL;
+ hash->dtah_all = NULL;
+ hash->dtah_size = 0;
+ }
+
+ free(agp->dtat_buf.dtbd_data);
+ free(agp->dtat_cpus);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c
new file mode 100644
index 000000000000..f937261c3541
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c
@@ -0,0 +1,503 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <dt_impl.h>
+#include <dt_parser.h>
+#include <dt_as.h>
+
+void
+dt_irlist_create(dt_irlist_t *dlp)
+{
+ bzero(dlp, sizeof (dt_irlist_t));
+ dlp->dl_label = 1;
+}
+
+void
+dt_irlist_destroy(dt_irlist_t *dlp)
+{
+ dt_irnode_t *dip, *nip;
+
+ for (dip = dlp->dl_list; dip != NULL; dip = nip) {
+ nip = dip->di_next;
+ free(dip);
+ }
+}
+
+void
+dt_irlist_append(dt_irlist_t *dlp, dt_irnode_t *dip)
+{
+ if (dlp->dl_last != NULL)
+ dlp->dl_last->di_next = dip;
+ else
+ dlp->dl_list = dip;
+
+ dlp->dl_last = dip;
+
+ if (dip->di_label == DT_LBL_NONE || dip->di_instr != DIF_INSTR_NOP)
+ dlp->dl_len++; /* don't count forward refs in instr count */
+}
+
+uint_t
+dt_irlist_label(dt_irlist_t *dlp)
+{
+ return (dlp->dl_label++);
+}
+
+/*ARGSUSED*/
+static int
+dt_countvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
+{
+ size_t *np = data;
+
+ if (idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW))
+ (*np)++; /* include variable in vartab */
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_copyvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
+{
+ dt_pcb_t *pcb = data;
+ dtrace_difv_t *dvp;
+ ssize_t stroff;
+ dt_node_t dn;
+
+ if (!(idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW)))
+ return (0); /* omit variable from vartab */
+
+ dvp = &pcb->pcb_difo->dtdo_vartab[pcb->pcb_asvidx++];
+ stroff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);
+
+ if (stroff == -1L)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+ if (stroff > DIF_STROFF_MAX)
+ longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);
+
+ dvp->dtdv_name = (uint_t)stroff;
+ dvp->dtdv_id = idp->di_id;
+ dvp->dtdv_flags = 0;
+
+ dvp->dtdv_kind = (idp->di_kind == DT_IDENT_ARRAY) ?
+ DIFV_KIND_ARRAY : DIFV_KIND_SCALAR;
+
+ if (idp->di_flags & DT_IDFLG_LOCAL)
+ dvp->dtdv_scope = DIFV_SCOPE_LOCAL;
+ else if (idp->di_flags & DT_IDFLG_TLS)
+ dvp->dtdv_scope = DIFV_SCOPE_THREAD;
+ else
+ dvp->dtdv_scope = DIFV_SCOPE_GLOBAL;
+
+ if (idp->di_flags & DT_IDFLG_DIFR)
+ dvp->dtdv_flags |= DIFV_F_REF;
+ if (idp->di_flags & DT_IDFLG_DIFW)
+ dvp->dtdv_flags |= DIFV_F_MOD;
+
+ bzero(&dn, sizeof (dn));
+ dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type, B_FALSE);
+ dt_node_diftype(pcb->pcb_hdl, &dn, &dvp->dtdv_type);
+
+ idp->di_flags &= ~(DT_IDFLG_DIFR | DT_IDFLG_DIFW);
+ return (0);
+}
+
+static ssize_t
+dt_copystr(const char *s, size_t n, size_t off, dt_pcb_t *pcb)
+{
+ bcopy(s, pcb->pcb_difo->dtdo_strtab + off, n);
+ return (n);
+}
+
+/*
+ * Rewrite the xlate/xlarg instruction at dtdo_buf[i] so that the instruction's
+ * xltab index reflects the offset 'xi' of the assigned dtdo_xlmtab[] location.
+ * We track the cumulative references to translators and members in the pcb's
+ * pcb_asxrefs[] array, a two-dimensional array of bitmaps indexed by the
+ * global translator id and then by the corresponding translator member id.
+ */
+static void
+dt_as_xlate(dt_pcb_t *pcb, dtrace_difo_t *dp,
+ uint_t i, uint_t xi, dt_node_t *dnp)
+{
+ dtrace_hdl_t *dtp = pcb->pcb_hdl;
+ dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator;
+
+ assert(i < dp->dtdo_len);
+ assert(xi < dp->dtdo_xlmlen);
+
+ assert(dnp->dn_kind == DT_NODE_MEMBER);
+ assert(dnp->dn_membexpr->dn_kind == DT_NODE_XLATOR);
+
+ assert(dxp->dx_id < dtp->dt_xlatorid);
+ assert(dnp->dn_membid < dxp->dx_nmembers);
+
+ if (pcb->pcb_asxrefs == NULL) {
+ pcb->pcb_asxreflen = dtp->dt_xlatorid;
+ pcb->pcb_asxrefs =
+ dt_zalloc(dtp, sizeof (ulong_t *) * pcb->pcb_asxreflen);
+ if (pcb->pcb_asxrefs == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ if (pcb->pcb_asxrefs[dxp->dx_id] == NULL) {
+ pcb->pcb_asxrefs[dxp->dx_id] =
+ dt_zalloc(dtp, BT_SIZEOFMAP(dxp->dx_nmembers));
+ if (pcb->pcb_asxrefs[dxp->dx_id] == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ dp->dtdo_buf[i] = DIF_INSTR_XLATE(
+ DIF_INSTR_OP(dp->dtdo_buf[i]), xi, DIF_INSTR_RD(dp->dtdo_buf[i]));
+
+ BT_SET(pcb->pcb_asxrefs[dxp->dx_id], dnp->dn_membid);
+ dp->dtdo_xlmtab[xi] = dnp;
+}
+
+static void
+dt_as_undef(const dt_ident_t *idp, uint_t offset)
+{
+ const char *kind, *mark = (idp->di_flags & DT_IDFLG_USER) ? "``" : "`";
+ const dtrace_syminfo_t *dts = idp->di_data;
+
+ if (idp->di_flags & DT_IDFLG_USER)
+ kind = "user";
+ else if (idp->di_flags & DT_IDFLG_PRIM)
+ kind = "primary kernel";
+ else
+ kind = "loadable kernel";
+
+ yylineno = idp->di_lineno;
+
+ xyerror(D_ASRELO, "relocation remains against %s symbol %s%s%s (offset "
+ "0x%x)\n", kind, dts->dts_object, mark, dts->dts_name, offset);
+}
+
+dtrace_difo_t *
+dt_as(dt_pcb_t *pcb)
+{
+ dtrace_hdl_t *dtp = pcb->pcb_hdl;
+ dt_irlist_t *dlp = &pcb->pcb_ir;
+ uint_t *labels = NULL;
+ dt_irnode_t *dip;
+ dtrace_difo_t *dp;
+ dt_ident_t *idp;
+
+ size_t n = 0;
+ uint_t i;
+
+ uint_t kmask, kbits, umask, ubits;
+ uint_t krel = 0, urel = 0, xlrefs = 0;
+
+ /*
+ * Select bitmasks based upon the desired symbol linking policy. We
+ * test (di_extern->di_flags & xmask) == xbits to determine if the
+ * symbol should have a relocation entry generated in the loop below.
+ *
+ * DT_LINK_KERNEL = kernel symbols static, user symbols dynamic
+ * DT_LINK_PRIMARY = primary kernel symbols static, others dynamic
+ * DT_LINK_DYNAMIC = all symbols dynamic
+ * DT_LINK_STATIC = all symbols static
+ *
+ * By 'static' we mean that we use the symbol's value at compile-time
+ * in the final DIF. By 'dynamic' we mean that we create a relocation
+ * table entry for the symbol's value so it can be relocated later.
+ */
+ switch (dtp->dt_linkmode) {
+ case DT_LINK_KERNEL:
+ kmask = 0;
+ kbits = -1u;
+ umask = DT_IDFLG_USER;
+ ubits = DT_IDFLG_USER;
+ break;
+ case DT_LINK_PRIMARY:
+ kmask = DT_IDFLG_USER | DT_IDFLG_PRIM;
+ kbits = 0;
+ umask = DT_IDFLG_USER;
+ ubits = DT_IDFLG_USER;
+ break;
+ case DT_LINK_DYNAMIC:
+ kmask = DT_IDFLG_USER;
+ kbits = 0;
+ umask = DT_IDFLG_USER;
+ ubits = DT_IDFLG_USER;
+ break;
+ case DT_LINK_STATIC:
+ kmask = umask = 0;
+ kbits = ubits = -1u;
+ break;
+ default:
+ xyerror(D_UNKNOWN, "internal error -- invalid link mode %u\n",
+ dtp->dt_linkmode);
+ }
+
+ assert(pcb->pcb_difo == NULL);
+ pcb->pcb_difo = dt_zalloc(dtp, sizeof (dtrace_difo_t));
+
+ if ((dp = pcb->pcb_difo) == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * dlp->dl_len);
+
+ if (dp->dtdo_buf == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+
+ if ((labels = dt_alloc(dtp, sizeof (uint_t) * dlp->dl_label)) == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+
+ /*
+ * Make an initial pass through the instruction list, filling in the
+ * instruction buffer with valid instructions and skipping labeled nops.
+ * While doing this, we also fill in our labels[] translation table
+ * and we count up the number of relocation table entries we will need.
+ */
+ for (i = 0, dip = dlp->dl_list; dip != NULL; dip = dip->di_next) {
+ if (dip->di_label != DT_LBL_NONE)
+ labels[dip->di_label] = i;
+
+ if (dip->di_label == DT_LBL_NONE ||
+ dip->di_instr != DIF_INSTR_NOP)
+ dp->dtdo_buf[i++] = dip->di_instr;
+
+ if (dip->di_extern == NULL)
+ continue; /* no external references needed */
+
+ switch (DIF_INSTR_OP(dip->di_instr)) {
+ case DIF_OP_SETX:
+ idp = dip->di_extern;
+ if ((idp->di_flags & kmask) == kbits)
+ krel++;
+ else if ((idp->di_flags & umask) == ubits)
+ urel++;
+ break;
+ case DIF_OP_XLATE:
+ case DIF_OP_XLARG:
+ xlrefs++;
+ break;
+ default:
+ xyerror(D_UNKNOWN, "unexpected assembler relocation "
+ "for opcode 0x%x\n", DIF_INSTR_OP(dip->di_instr));
+ }
+ }
+
+ assert(i == dlp->dl_len);
+ dp->dtdo_len = dlp->dl_len;
+
+ /*
+ * Make a second pass through the instructions, relocating each branch
+ * label to the index of the final instruction in the buffer and noting
+ * any other instruction-specific DIFO flags such as dtdo_destructive.
+ */
+ for (i = 0; i < dp->dtdo_len; i++) {
+ dif_instr_t instr = dp->dtdo_buf[i];
+ uint_t op = DIF_INSTR_OP(instr);
+
+ if (op == DIF_OP_CALL) {
+ if (DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUT ||
+ DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUTSTR)
+ dp->dtdo_destructive = 1;
+ continue;
+ }
+
+ if (op >= DIF_OP_BA && op <= DIF_OP_BLEU) {
+ assert(DIF_INSTR_LABEL(instr) < dlp->dl_label);
+ dp->dtdo_buf[i] = DIF_INSTR_BRANCH(op,
+ labels[DIF_INSTR_LABEL(instr)]);
+ }
+ }
+
+ dt_free(dtp, labels);
+ pcb->pcb_asvidx = 0;
+
+ /*
+ * Allocate memory for the appropriate number of variable records and
+ * then fill in each variable record. As we populate the variable
+ * table we insert the corresponding variable names into the strtab.
+ */
+ (void) dt_idhash_iter(dtp->dt_tls, dt_countvar, &n);
+ (void) dt_idhash_iter(dtp->dt_globals, dt_countvar, &n);
+ (void) dt_idhash_iter(pcb->pcb_locals, dt_countvar, &n);
+
+ if (n != 0) {
+ dp->dtdo_vartab = dt_alloc(dtp, n * sizeof (dtrace_difv_t));
+ dp->dtdo_varlen = (uint32_t)n;
+
+ if (dp->dtdo_vartab == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+
+ (void) dt_idhash_iter(dtp->dt_tls, dt_copyvar, pcb);
+ (void) dt_idhash_iter(dtp->dt_globals, dt_copyvar, pcb);
+ (void) dt_idhash_iter(pcb->pcb_locals, dt_copyvar, pcb);
+ }
+
+ /*
+ * Allocate memory for the appropriate number of relocation table
+ * entries based upon our kernel and user counts from the first pass.
+ */
+ if (krel != 0) {
+ dp->dtdo_kreltab = dt_alloc(dtp,
+ krel * sizeof (dof_relodesc_t));
+ dp->dtdo_krelen = krel;
+
+ if (dp->dtdo_kreltab == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ if (urel != 0) {
+ dp->dtdo_ureltab = dt_alloc(dtp,
+ urel * sizeof (dof_relodesc_t));
+ dp->dtdo_urelen = urel;
+
+ if (dp->dtdo_ureltab == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ if (xlrefs != 0) {
+ dp->dtdo_xlmtab = dt_zalloc(dtp, sizeof (dt_node_t *) * xlrefs);
+ dp->dtdo_xlmlen = xlrefs;
+
+ if (dp->dtdo_xlmtab == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ /*
+ * If any relocations are needed, make another pass through the
+ * instruction list and fill in the relocation table entries.
+ */
+ if (krel + urel + xlrefs != 0) {
+ uint_t knodef = pcb->pcb_cflags & DTRACE_C_KNODEF;
+ uint_t unodef = pcb->pcb_cflags & DTRACE_C_UNODEF;
+
+ dof_relodesc_t *krp = dp->dtdo_kreltab;
+ dof_relodesc_t *urp = dp->dtdo_ureltab;
+ dt_node_t **xlp = dp->dtdo_xlmtab;
+
+ i = 0; /* dtdo_buf[] index */
+
+ for (dip = dlp->dl_list; dip != NULL; dip = dip->di_next) {
+ dof_relodesc_t *rp;
+ ssize_t soff;
+ uint_t nodef;
+
+ if (dip->di_label != DT_LBL_NONE &&
+ dip->di_instr == DIF_INSTR_NOP)
+ continue; /* skip label declarations */
+
+ i++; /* advance dtdo_buf[] index */
+
+ if (DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLATE ||
+ DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLARG) {
+ assert(dp->dtdo_buf[i - 1] == dip->di_instr);
+ dt_as_xlate(pcb, dp, i - 1, (uint_t)
+ (xlp++ - dp->dtdo_xlmtab), dip->di_extern);
+ continue;
+ }
+
+ if ((idp = dip->di_extern) == NULL)
+ continue; /* no relocation entry needed */
+
+ if ((idp->di_flags & kmask) == kbits) {
+ nodef = knodef;
+ rp = krp++;
+ } else if ((idp->di_flags & umask) == ubits) {
+ nodef = unodef;
+ rp = urp++;
+ } else
+ continue;
+
+ if (!nodef)
+ dt_as_undef(idp, i);
+
+ assert(DIF_INSTR_OP(dip->di_instr) == DIF_OP_SETX);
+ soff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);
+
+ if (soff == -1L)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+ if (soff > DIF_STROFF_MAX)
+ longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);
+
+ rp->dofr_name = (dof_stridx_t)soff;
+ rp->dofr_type = DOF_RELO_SETX;
+ rp->dofr_offset = DIF_INSTR_INTEGER(dip->di_instr) *
+ sizeof (uint64_t);
+ rp->dofr_data = 0;
+ }
+
+ assert(krp == dp->dtdo_kreltab + dp->dtdo_krelen);
+ assert(urp == dp->dtdo_ureltab + dp->dtdo_urelen);
+ assert(xlp == dp->dtdo_xlmtab + dp->dtdo_xlmlen);
+ assert(i == dp->dtdo_len);
+ }
+
+ /*
+ * Allocate memory for the compiled string table and then copy the
+ * chunks from the string table into the final string buffer.
+ */
+ if ((n = dt_strtab_size(pcb->pcb_strtab)) != 0) {
+ if ((dp->dtdo_strtab = dt_alloc(dtp, n)) == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+
+ (void) dt_strtab_write(pcb->pcb_strtab,
+ (dt_strtab_write_f *)dt_copystr, pcb);
+ dp->dtdo_strlen = (uint32_t)n;
+ }
+
+ /*
+ * Allocate memory for the compiled integer table and then copy the
+ * integer constants from the table into the final integer buffer.
+ */
+ if ((n = dt_inttab_size(pcb->pcb_inttab)) != 0) {
+ if ((dp->dtdo_inttab = dt_alloc(dtp,
+ n * sizeof (uint64_t))) == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dt_inttab_write(pcb->pcb_inttab, dp->dtdo_inttab);
+ dp->dtdo_intlen = (uint32_t)n;
+ }
+
+ /*
+ * Fill in the DIFO return type from the type associated with the
+ * node saved in pcb_dret, and then clear pcb_difo and pcb_dret
+ * now that the assembler has completed successfully.
+ */
+ dt_node_diftype(dtp, pcb->pcb_dret, &dp->dtdo_rtype);
+ pcb->pcb_difo = NULL;
+ pcb->pcb_dret = NULL;
+
+ if (pcb->pcb_cflags & DTRACE_C_DIFV)
+ dt_dis(dp, stderr);
+
+ return (dp);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.h
new file mode 100644
index 000000000000..2acd94091206
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_AS_H
+#define _DT_AS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/dtrace.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct dt_irnode {
+ uint_t di_label; /* label number or DT_LBL_NONE */
+ dif_instr_t di_instr; /* instruction opcode */
+ void *di_extern; /* opcode-specific external reference */
+ struct dt_irnode *di_next; /* next instruction */
+} dt_irnode_t;
+
+#define DT_LBL_NONE 0 /* no label on this instruction */
+
+typedef struct dt_irlist {
+ dt_irnode_t *dl_list; /* pointer to first node in list */
+ dt_irnode_t *dl_last; /* pointer to last node in list */
+ uint_t dl_len; /* number of valid instructions */
+ uint_t dl_label; /* next label number to assign */
+} dt_irlist_t;
+
+extern void dt_irlist_create(dt_irlist_t *);
+extern void dt_irlist_destroy(dt_irlist_t *);
+extern void dt_irlist_append(dt_irlist_t *, dt_irnode_t *);
+extern uint_t dt_irlist_label(dt_irlist_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_AS_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.c
new file mode 100644
index 000000000000..324e778213ca
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.c
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * DTrace Memory Buffer Routines
+ *
+ * The routines in this file are used to create an automatically resizing
+ * memory buffer that can be written to like a file. Memory buffers are
+ * used to construct DOF to ioctl() to dtrace(7D), and provide semantics that
+ * simplify caller code. Specifically, any allocation errors result in an
+ * error code being set inside the buffer which is maintained persistently and
+ * propagates to another buffer if the buffer in error is concatenated. These
+ * semantics permit callers to execute a large series of writes without needing
+ * to check for errors and then perform a single check before using the buffer.
+ */
+
+#include <sys/sysmacros.h>
+#include <strings.h>
+
+#include <dt_impl.h>
+#include <dt_buf.h>
+
+void
+dt_buf_create(dtrace_hdl_t *dtp, dt_buf_t *bp, const char *name, size_t len)
+{
+ if (len == 0)
+ len = _dtrace_bufsize;
+
+ bp->dbu_buf = bp->dbu_ptr = dt_zalloc(dtp, len);
+ bp->dbu_len = len;
+
+ if (bp->dbu_buf == NULL)
+ bp->dbu_err = dtrace_errno(dtp);
+ else
+ bp->dbu_err = 0;
+
+ bp->dbu_resizes = 0;
+ bp->dbu_name = name;
+}
+
+void
+dt_buf_destroy(dtrace_hdl_t *dtp, dt_buf_t *bp)
+{
+ dt_dprintf("dt_buf_destroy(%s): size=%lu resizes=%u\n",
+ bp->dbu_name, (ulong_t)bp->dbu_len, bp->dbu_resizes);
+
+ dt_free(dtp, bp->dbu_buf);
+}
+
+void
+dt_buf_reset(dtrace_hdl_t *dtp, dt_buf_t *bp)
+{
+ if ((bp->dbu_ptr = bp->dbu_buf) != NULL)
+ bp->dbu_err = 0;
+ else
+ dt_buf_create(dtp, bp, bp->dbu_name, bp->dbu_len);
+}
+
+void
+dt_buf_write(dtrace_hdl_t *dtp, dt_buf_t *bp,
+ const void *buf, size_t len, size_t align)
+{
+ size_t off = (size_t)(bp->dbu_ptr - bp->dbu_buf);
+ size_t adj = roundup(off, align) - off;
+
+ if (bp->dbu_err != 0) {
+ (void) dt_set_errno(dtp, bp->dbu_err);
+ return; /* write silently fails */
+ }
+
+ if (bp->dbu_ptr + adj + len > bp->dbu_buf + bp->dbu_len) {
+ size_t new_len = bp->dbu_len * 2;
+ uchar_t *new_buf;
+ uint_t r = 1;
+
+ while (bp->dbu_ptr + adj + len > bp->dbu_buf + new_len) {
+ new_len *= 2;
+ r++;
+ }
+
+ if ((new_buf = dt_zalloc(dtp, new_len)) == NULL) {
+ bp->dbu_err = dtrace_errno(dtp);
+ return;
+ }
+
+ bcopy(bp->dbu_buf, new_buf, off);
+ dt_free(dtp, bp->dbu_buf);
+
+ bp->dbu_buf = new_buf;
+ bp->dbu_ptr = new_buf + off;
+ bp->dbu_len = new_len;
+ bp->dbu_resizes += r;
+ }
+
+ bp->dbu_ptr += adj;
+ bcopy(buf, bp->dbu_ptr, len);
+ bp->dbu_ptr += len;
+}
+
+void
+dt_buf_concat(dtrace_hdl_t *dtp, dt_buf_t *dst,
+ const dt_buf_t *src, size_t align)
+{
+ if (dst->dbu_err == 0 && src->dbu_err != 0) {
+ (void) dt_set_errno(dtp, src->dbu_err);
+ dst->dbu_err = src->dbu_err;
+ } else {
+ dt_buf_write(dtp, dst, src->dbu_buf,
+ (size_t)(src->dbu_ptr - src->dbu_buf), align);
+ }
+}
+
+size_t
+dt_buf_offset(const dt_buf_t *bp, size_t align)
+{
+ size_t off = (size_t)(bp->dbu_ptr - bp->dbu_buf);
+ return (roundup(off, align));
+}
+
+size_t
+dt_buf_len(const dt_buf_t *bp)
+{
+ return (bp->dbu_ptr - bp->dbu_buf);
+}
+
+int
+dt_buf_error(const dt_buf_t *bp)
+{
+ return (bp->dbu_err);
+}
+
+void *
+dt_buf_ptr(const dt_buf_t *bp)
+{
+ return (bp->dbu_buf);
+}
+
+void *
+dt_buf_claim(dtrace_hdl_t *dtp, dt_buf_t *bp)
+{
+ void *buf = bp->dbu_buf;
+
+ if (bp->dbu_err != 0) {
+ dt_free(dtp, buf);
+ buf = NULL;
+ }
+
+ bp->dbu_buf = bp->dbu_ptr = NULL;
+ bp->dbu_len = 0;
+
+ return (buf);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.h
new file mode 100644
index 000000000000..eb93e13cb751
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_BUF_H
+#define _DT_BUF_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dtrace.h>
+
+typedef struct dt_buf {
+ const char *dbu_name; /* string name for debugging */
+ uchar_t *dbu_buf; /* buffer base address */
+ uchar_t *dbu_ptr; /* current buffer location */
+ size_t dbu_len; /* buffer size in bytes */
+ int dbu_err; /* errno value if error */
+ int dbu_resizes; /* number of resizes */
+} dt_buf_t;
+
+extern void dt_buf_create(dtrace_hdl_t *, dt_buf_t *, const char *, size_t);
+extern void dt_buf_destroy(dtrace_hdl_t *, dt_buf_t *);
+extern void dt_buf_reset(dtrace_hdl_t *, dt_buf_t *);
+
+extern void dt_buf_write(dtrace_hdl_t *, dt_buf_t *,
+ const void *, size_t, size_t);
+
+extern void dt_buf_concat(dtrace_hdl_t *, dt_buf_t *,
+ const dt_buf_t *, size_t);
+
+extern size_t dt_buf_offset(const dt_buf_t *, size_t);
+extern size_t dt_buf_len(const dt_buf_t *);
+
+extern int dt_buf_error(const dt_buf_t *);
+extern void *dt_buf_ptr(const dt_buf_t *);
+
+extern void *dt_buf_claim(dtrace_hdl_t *, dt_buf_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_BUF_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
new file mode 100644
index 000000000000..8ec5dd61b8ee
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
@@ -0,0 +1,2612 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent Inc. All rights reserved.
+ * Copyright 2015 Gary Mills
+ */
+
+/*
+ * DTrace D Language Compiler
+ *
+ * The code in this source file implements the main engine for the D language
+ * compiler. The driver routine for the compiler is dt_compile(), below. The
+ * compiler operates on either stdio FILEs or in-memory strings as its input
+ * and can produce either dtrace_prog_t structures from a D program or a single
+ * dtrace_difo_t structure from a D expression. Multiple entry points are
+ * provided as wrappers around dt_compile() for the various input/output pairs.
+ * The compiler itself is implemented across the following source files:
+ *
+ * dt_lex.l - lex scanner
+ * dt_grammar.y - yacc grammar
+ * dt_parser.c - parse tree creation and semantic checking
+ * dt_decl.c - declaration stack processing
+ * dt_xlator.c - D translator lookup and creation
+ * dt_ident.c - identifier and symbol table routines
+ * dt_pragma.c - #pragma processing and D pragmas
+ * dt_printf.c - D printf() and printa() argument checking and processing
+ * dt_cc.c - compiler driver and dtrace_prog_t construction
+ * dt_cg.c - DIF code generator
+ * dt_as.c - DIF assembler
+ * dt_dof.c - dtrace_prog_t -> DOF conversion
+ *
+ * Several other source files provide collections of utility routines used by
+ * these major files. The compiler itself is implemented in multiple passes:
+ *
+ * (1) The input program is scanned and parsed by dt_lex.l and dt_grammar.y
+ * and parse tree nodes are constructed using the routines in dt_parser.c.
+ * This node construction pass is described further in dt_parser.c.
+ *
+ * (2) The parse tree is "cooked" by assigning each clause a context (see the
+ * routine dt_setcontext(), below) based on its probe description and then
+ * recursively descending the tree performing semantic checking. The cook
+ * routines are also implemented in dt_parser.c and described there.
+ *
+ * (3) For actions that are DIF expression statements, the DIF code generator
+ * and assembler are invoked to create a finished DIFO for the statement.
+ *
+ * (4) The dtrace_prog_t data structures for the program clauses and actions
+ * are built, containing pointers to any DIFOs created in step (3).
+ *
+ * (5) The caller invokes a routine in dt_dof.c to convert the finished program
+ * into DOF format for use in anonymous tracing or enabling in the kernel.
+ *
+ * In the implementation, steps 2-4 are intertwined in that they are performed
+ * in order for each clause as part of a loop that executes over the clauses.
+ *
+ * The D compiler currently implements nearly no optimization. The compiler
+ * implements integer constant folding as part of pass (1), and a set of very
+ * simple peephole optimizations as part of pass (3). As with any C compiler,
+ * a large number of optimizations are possible on both the intermediate data
+ * structures and the generated DIF code. These possibilities should be
+ * investigated in the context of whether they will have any substantive effect
+ * on the overall DTrace probe effect before they are undertaken.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/sysmacros.h>
+
+#include <assert.h>
+#include <string.h>
+#include <strings.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ucontext.h>
+#include <limits.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <dt_module.h>
+#include <dt_program.h>
+#include <dt_provider.h>
+#include <dt_printf.h>
+#include <dt_pid.h>
+#include <dt_grammar.h>
+#include <dt_ident.h>
+#include <dt_string.h>
+#include <dt_impl.h>
+
+static const dtrace_diftype_t dt_void_rtype = {
+ DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, 0
+};
+
+static const dtrace_diftype_t dt_int_rtype = {
+ DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, sizeof (uint64_t)
+};
+
+static void *dt_compile(dtrace_hdl_t *, int, dtrace_probespec_t, void *,
+ uint_t, int, char *const[], FILE *, const char *);
+
+/*ARGSUSED*/
+static int
+dt_idreset(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored)
+{
+ idp->di_flags &= ~(DT_IDFLG_REF | DT_IDFLG_MOD |
+ DT_IDFLG_DIFR | DT_IDFLG_DIFW);
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_idpragma(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored)
+{
+ yylineno = idp->di_lineno;
+ xyerror(D_PRAGMA_UNUSED, "unused #pragma %s\n", (char *)idp->di_iarg);
+ return (0);
+}
+
+static dtrace_stmtdesc_t *
+dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp,
+ dtrace_attribute_t descattr, dtrace_attribute_t stmtattr)
+{
+ dtrace_stmtdesc_t *sdp = dtrace_stmt_create(dtp, edp);
+
+ if (sdp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ assert(yypcb->pcb_stmt == NULL);
+ yypcb->pcb_stmt = sdp;
+
+ sdp->dtsd_descattr = descattr;
+ sdp->dtsd_stmtattr = stmtattr;
+
+ return (sdp);
+}
+
+static dtrace_actdesc_t *
+dt_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *new;
+
+ if ((new = dtrace_stmt_action(dtp, sdp)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ return (new);
+}
+
+/*
+ * Utility function to determine if a given action description is destructive.
+ * The dtdo_destructive bit is set for us by the DIF assembler (see dt_as.c).
+ */
+static int
+dt_action_destructive(const dtrace_actdesc_t *ap)
+{
+ return (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind) || (ap->dtad_kind ==
+ DTRACEACT_DIFEXPR && ap->dtad_difo->dtdo_destructive));
+}
+
+static void
+dt_stmt_append(dtrace_stmtdesc_t *sdp, const dt_node_t *dnp)
+{
+ dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
+ dtrace_actdesc_t *ap, *tap;
+ int commit = 0;
+ int speculate = 0;
+ int datarec = 0;
+
+ /*
+ * Make sure that the new statement jibes with the rest of the ECB.
+ */
+ for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
+ if (ap->dtad_kind == DTRACEACT_COMMIT) {
+ if (commit) {
+ dnerror(dnp, D_COMM_COMM, "commit( ) may "
+ "not follow commit( )\n");
+ }
+
+ if (datarec) {
+ dnerror(dnp, D_COMM_DREC, "commit( ) may "
+ "not follow data-recording action(s)\n");
+ }
+
+ for (tap = ap; tap != NULL; tap = tap->dtad_next) {
+ if (!DTRACEACT_ISAGG(tap->dtad_kind))
+ continue;
+
+ dnerror(dnp, D_AGG_COMM, "aggregating actions "
+ "may not follow commit( )\n");
+ }
+
+ commit = 1;
+ continue;
+ }
+
+ if (ap->dtad_kind == DTRACEACT_SPECULATE) {
+ if (speculate) {
+ dnerror(dnp, D_SPEC_SPEC, "speculate( ) may "
+ "not follow speculate( )\n");
+ }
+
+ if (commit) {
+ dnerror(dnp, D_SPEC_COMM, "speculate( ) may "
+ "not follow commit( )\n");
+ }
+
+ if (datarec) {
+ dnerror(dnp, D_SPEC_DREC, "speculate( ) may "
+ "not follow data-recording action(s)\n");
+ }
+
+ speculate = 1;
+ continue;
+ }
+
+ if (DTRACEACT_ISAGG(ap->dtad_kind)) {
+ if (speculate) {
+ dnerror(dnp, D_AGG_SPEC, "aggregating actions "
+ "may not follow speculate( )\n");
+ }
+
+ datarec = 1;
+ continue;
+ }
+
+ if (speculate) {
+ if (dt_action_destructive(ap)) {
+ dnerror(dnp, D_ACT_SPEC, "destructive actions "
+ "may not follow speculate( )\n");
+ }
+
+ if (ap->dtad_kind == DTRACEACT_EXIT) {
+ dnerror(dnp, D_EXIT_SPEC, "exit( ) may not "
+ "follow speculate( )\n");
+ }
+ }
+
+ /*
+ * Exclude all non data-recording actions.
+ */
+ if (dt_action_destructive(ap) ||
+ ap->dtad_kind == DTRACEACT_DISCARD)
+ continue;
+
+ if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
+ ap->dtad_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_CTF &&
+ ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
+ continue;
+
+ if (commit) {
+ dnerror(dnp, D_DREC_COMM, "data-recording actions "
+ "may not follow commit( )\n");
+ }
+
+ if (!speculate)
+ datarec = 1;
+ }
+
+ if (dtrace_stmt_add(yypcb->pcb_hdl, yypcb->pcb_prog, sdp) != 0)
+ longjmp(yypcb->pcb_jmpbuf, dtrace_errno(yypcb->pcb_hdl));
+
+ if (yypcb->pcb_stmt == sdp)
+ yypcb->pcb_stmt = NULL;
+}
+
+/*
+ * For the first element of an aggregation tuple or for printa(), we create a
+ * simple DIF program that simply returns the immediate value that is the ID
+ * of the aggregation itself. This could be optimized in the future by
+ * creating a new in-kernel dtad_kind that just returns an integer.
+ */
+static void
+dt_action_difconst(dtrace_actdesc_t *ap, uint_t id, dtrace_actkind_t kind)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dtrace_difo_t *dp = dt_zalloc(dtp, sizeof (dtrace_difo_t));
+
+ if (dp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * 2);
+ dp->dtdo_inttab = dt_alloc(dtp, sizeof (uint64_t));
+
+ if (dp->dtdo_buf == NULL || dp->dtdo_inttab == NULL) {
+ dt_difo_free(dtp, dp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ dp->dtdo_buf[0] = DIF_INSTR_SETX(0, 1); /* setx DIF_INTEGER[0], %r1 */
+ dp->dtdo_buf[1] = DIF_INSTR_RET(1); /* ret %r1 */
+ dp->dtdo_len = 2;
+ dp->dtdo_inttab[0] = id;
+ dp->dtdo_intlen = 1;
+ dp->dtdo_rtype = dt_int_rtype;
+
+ ap->dtad_difo = dp;
+ ap->dtad_kind = kind;
+}
+
+static void
+dt_action_clear(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dt_ident_t *aid;
+ dtrace_actdesc_t *ap;
+ dt_node_t *anp;
+
+ char n[DT_TYPE_NAMELEN];
+ int argc = 0;
+
+ for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)
+ argc++; /* count up arguments for error messages below */
+
+ if (argc != 1) {
+ dnerror(dnp, D_CLEAR_PROTO,
+ "%s( ) prototype mismatch: %d args passed, 1 expected\n",
+ dnp->dn_ident->di_name, argc);
+ }
+
+ anp = dnp->dn_args;
+ assert(anp != NULL);
+
+ if (anp->dn_kind != DT_NODE_AGG) {
+ dnerror(dnp, D_CLEAR_AGGARG,
+ "%s( ) argument #1 is incompatible with prototype:\n"
+ "\tprototype: aggregation\n\t argument: %s\n",
+ dnp->dn_ident->di_name,
+ dt_node_type_name(anp, n, sizeof (n)));
+ }
+
+ aid = anp->dn_ident;
+
+ if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) {
+ dnerror(dnp, D_CLEAR_AGGBAD,
+ "undefined aggregation: @%s\n", aid->di_name);
+ }
+
+ ap = dt_stmt_action(dtp, sdp);
+ dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT);
+ ap->dtad_arg = DT_ACT_CLEAR;
+}
+
+static void
+dt_action_normalize(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dt_ident_t *aid;
+ dtrace_actdesc_t *ap;
+ dt_node_t *anp, *normal;
+ int denormal = (strcmp(dnp->dn_ident->di_name, "denormalize") == 0);
+
+ char n[DT_TYPE_NAMELEN];
+ int argc = 0;
+
+ for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)
+ argc++; /* count up arguments for error messages below */
+
+ if ((denormal && argc != 1) || (!denormal && argc != 2)) {
+ dnerror(dnp, D_NORMALIZE_PROTO,
+ "%s( ) prototype mismatch: %d args passed, %d expected\n",
+ dnp->dn_ident->di_name, argc, denormal ? 1 : 2);
+ }
+
+ anp = dnp->dn_args;
+ assert(anp != NULL);
+
+ if (anp->dn_kind != DT_NODE_AGG) {
+ dnerror(dnp, D_NORMALIZE_AGGARG,
+ "%s( ) argument #1 is incompatible with prototype:\n"
+ "\tprototype: aggregation\n\t argument: %s\n",
+ dnp->dn_ident->di_name,
+ dt_node_type_name(anp, n, sizeof (n)));
+ }
+
+ if ((normal = anp->dn_list) != NULL && !dt_node_is_scalar(normal)) {
+ dnerror(dnp, D_NORMALIZE_SCALAR,
+ "%s( ) argument #2 must be of scalar type\n",
+ dnp->dn_ident->di_name);
+ }
+
+ aid = anp->dn_ident;
+
+ if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) {
+ dnerror(dnp, D_NORMALIZE_AGGBAD,
+ "undefined aggregation: @%s\n", aid->di_name);
+ }
+
+ ap = dt_stmt_action(dtp, sdp);
+ dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT);
+
+ if (denormal) {
+ ap->dtad_arg = DT_ACT_DENORMALIZE;
+ return;
+ }
+
+ ap->dtad_arg = DT_ACT_NORMALIZE;
+
+ assert(normal != NULL);
+ ap = dt_stmt_action(dtp, sdp);
+ dt_cg(yypcb, normal);
+
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_LIBACT;
+ ap->dtad_arg = DT_ACT_NORMALIZE;
+}
+
+static void
+dt_action_trunc(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dt_ident_t *aid;
+ dtrace_actdesc_t *ap;
+ dt_node_t *anp, *trunc;
+
+ char n[DT_TYPE_NAMELEN];
+ int argc = 0;
+
+ for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)
+ argc++; /* count up arguments for error messages below */
+
+ if (argc > 2 || argc < 1) {
+ dnerror(dnp, D_TRUNC_PROTO,
+ "%s( ) prototype mismatch: %d args passed, %s expected\n",
+ dnp->dn_ident->di_name, argc,
+ argc < 1 ? "at least 1" : "no more than 2");
+ }
+
+ anp = dnp->dn_args;
+ assert(anp != NULL);
+ trunc = anp->dn_list;
+
+ if (anp->dn_kind != DT_NODE_AGG) {
+ dnerror(dnp, D_TRUNC_AGGARG,
+ "%s( ) argument #1 is incompatible with prototype:\n"
+ "\tprototype: aggregation\n\t argument: %s\n",
+ dnp->dn_ident->di_name,
+ dt_node_type_name(anp, n, sizeof (n)));
+ }
+
+ if (argc == 2) {
+ assert(trunc != NULL);
+ if (!dt_node_is_scalar(trunc)) {
+ dnerror(dnp, D_TRUNC_SCALAR,
+ "%s( ) argument #2 must be of scalar type\n",
+ dnp->dn_ident->di_name);
+ }
+ }
+
+ aid = anp->dn_ident;
+
+ if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) {
+ dnerror(dnp, D_TRUNC_AGGBAD,
+ "undefined aggregation: @%s\n", aid->di_name);
+ }
+
+ ap = dt_stmt_action(dtp, sdp);
+ dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT);
+ ap->dtad_arg = DT_ACT_TRUNC;
+
+ ap = dt_stmt_action(dtp, sdp);
+
+ if (argc == 1) {
+ dt_action_difconst(ap, 0, DTRACEACT_LIBACT);
+ } else {
+ assert(trunc != NULL);
+ dt_cg(yypcb, trunc);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_LIBACT;
+ }
+
+ ap->dtad_arg = DT_ACT_TRUNC;
+}
+
+static void
+dt_action_printa(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dt_ident_t *aid, *fid;
+ dtrace_actdesc_t *ap;
+ const char *format;
+ dt_node_t *anp, *proto = NULL;
+
+ char n[DT_TYPE_NAMELEN];
+ int argc = 0, argr = 0;
+
+ for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)
+ argc++; /* count up arguments for error messages below */
+
+ switch (dnp->dn_args->dn_kind) {
+ case DT_NODE_STRING:
+ format = dnp->dn_args->dn_string;
+ anp = dnp->dn_args->dn_list;
+ argr = 2;
+ break;
+ case DT_NODE_AGG:
+ format = NULL;
+ anp = dnp->dn_args;
+ argr = 1;
+ break;
+ default:
+ format = NULL;
+ anp = dnp->dn_args;
+ argr = 1;
+ }
+
+ if (argc < argr) {
+ dnerror(dnp, D_PRINTA_PROTO,
+ "%s( ) prototype mismatch: %d args passed, %d expected\n",
+ dnp->dn_ident->di_name, argc, argr);
+ }
+
+ assert(anp != NULL);
+
+ while (anp != NULL) {
+ if (anp->dn_kind != DT_NODE_AGG) {
+ dnerror(dnp, D_PRINTA_AGGARG,
+ "%s( ) argument #%d is incompatible with "
+ "prototype:\n\tprototype: aggregation\n"
+ "\t argument: %s\n", dnp->dn_ident->di_name, argr,
+ dt_node_type_name(anp, n, sizeof (n)));
+ }
+
+ aid = anp->dn_ident;
+ fid = aid->di_iarg;
+
+ if (aid->di_gen == dtp->dt_gen &&
+ !(aid->di_flags & DT_IDFLG_MOD)) {
+ dnerror(dnp, D_PRINTA_AGGBAD,
+ "undefined aggregation: @%s\n", aid->di_name);
+ }
+
+ /*
+ * If we have multiple aggregations, we must be sure that
+ * their key signatures match.
+ */
+ if (proto != NULL) {
+ dt_printa_validate(proto, anp);
+ } else {
+ proto = anp;
+ }
+
+ if (format != NULL) {
+ yylineno = dnp->dn_line;
+
+ sdp->dtsd_fmtdata =
+ dt_printf_create(yypcb->pcb_hdl, format);
+ dt_printf_validate(sdp->dtsd_fmtdata,
+ DT_PRINTF_AGGREGATION, dnp->dn_ident, 1,
+ fid->di_id, ((dt_idsig_t *)aid->di_data)->dis_args);
+ format = NULL;
+ }
+
+ ap = dt_stmt_action(dtp, sdp);
+ dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_PRINTA);
+
+ anp = anp->dn_list;
+ argr++;
+ }
+}
+
+static void
+dt_action_printflike(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp,
+ dtrace_actkind_t kind)
+{
+ dt_node_t *anp, *arg1;
+ dtrace_actdesc_t *ap = NULL;
+ char n[DT_TYPE_NAMELEN], *str;
+
+ assert(DTRACEACT_ISPRINTFLIKE(kind));
+
+ if (dnp->dn_args->dn_kind != DT_NODE_STRING) {
+ dnerror(dnp, D_PRINTF_ARG_FMT,
+ "%s( ) argument #1 is incompatible with prototype:\n"
+ "\tprototype: string constant\n\t argument: %s\n",
+ dnp->dn_ident->di_name,
+ dt_node_type_name(dnp->dn_args, n, sizeof (n)));
+ }
+
+ arg1 = dnp->dn_args->dn_list;
+ yylineno = dnp->dn_line;
+ str = dnp->dn_args->dn_string;
+
+
+ /*
+ * If this is an freopen(), we use an empty string to denote that
+ * stdout should be restored. For other printf()-like actions, an
+ * empty format string is illegal: an empty format string would
+ * result in malformed DOF, and the compiler thus flags an empty
+ * format string as a compile-time error. To avoid propagating the
+ * freopen() special case throughout the system, we simply transpose
+ * an empty string into a sentinel string (DT_FREOPEN_RESTORE) that
+ * denotes that stdout should be restored.
+ */
+ if (kind == DTRACEACT_FREOPEN) {
+ if (strcmp(str, DT_FREOPEN_RESTORE) == 0) {
+ /*
+ * Our sentinel is always an invalid argument to
+ * freopen(), but if it's been manually specified, we
+ * must fail now instead of when the freopen() is
+ * actually evaluated.
+ */
+ dnerror(dnp, D_FREOPEN_INVALID,
+ "%s( ) argument #1 cannot be \"%s\"\n",
+ dnp->dn_ident->di_name, DT_FREOPEN_RESTORE);
+ }
+
+ if (str[0] == '\0')
+ str = DT_FREOPEN_RESTORE;
+ }
+
+ sdp->dtsd_fmtdata = dt_printf_create(dtp, str);
+
+ dt_printf_validate(sdp->dtsd_fmtdata, DT_PRINTF_EXACTLEN,
+ dnp->dn_ident, 1, DTRACEACT_AGGREGATION, arg1);
+
+ if (arg1 == NULL) {
+ dif_instr_t *dbuf;
+ dtrace_difo_t *dp;
+
+ if ((dbuf = dt_alloc(dtp, sizeof (dif_instr_t))) == NULL ||
+ (dp = dt_zalloc(dtp, sizeof (dtrace_difo_t))) == NULL) {
+ dt_free(dtp, dbuf);
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ dbuf[0] = DIF_INSTR_RET(DIF_REG_R0); /* ret %r0 */
+
+ dp->dtdo_buf = dbuf;
+ dp->dtdo_len = 1;
+ dp->dtdo_rtype = dt_int_rtype;
+
+ ap = dt_stmt_action(dtp, sdp);
+ ap->dtad_difo = dp;
+ ap->dtad_kind = kind;
+ return;
+ }
+
+ for (anp = arg1; anp != NULL; anp = anp->dn_list) {
+ ap = dt_stmt_action(dtp, sdp);
+ dt_cg(yypcb, anp);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = kind;
+ }
+}
+
+static void
+dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ int ctflib;
+
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+ boolean_t istrace = (dnp->dn_ident->di_id == DT_ACT_TRACE);
+ const char *act = istrace ? "trace" : "print";
+
+ if (dt_node_is_void(dnp->dn_args)) {
+ dnerror(dnp->dn_args, istrace ? D_TRACE_VOID : D_PRINT_VOID,
+ "%s( ) may not be applied to a void expression\n", act);
+ }
+
+ if (dt_node_resolve(dnp->dn_args, DT_IDENT_XLPTR) != NULL) {
+ dnerror(dnp->dn_args, istrace ? D_TRACE_DYN : D_PRINT_DYN,
+ "%s( ) may not be applied to a translated pointer\n", act);
+ }
+
+ if (dnp->dn_args->dn_kind == DT_NODE_AGG) {
+ dnerror(dnp->dn_args, istrace ? D_TRACE_AGG : D_PRINT_AGG,
+ "%s( ) may not be applied to an aggregation%s\n", act,
+ istrace ? "" : " -- did you mean printa()?");
+ }
+
+ dt_cg(yypcb, dnp->dn_args);
+
+ /*
+ * The print() action behaves identically to trace(), except that it
+ * stores the CTF type of the argument (if present) within the DOF for
+ * the DIFEXPR action. To do this, we set the 'dtsd_strdata' to point
+ * to the fully-qualified CTF type ID for the result of the DIF
+ * action. We use the ID instead of the name to handles complex types
+ * like arrays and function pointers that can't be resolved by
+ * ctf_type_lookup(). This is later processed by dtrace_dof_create()
+ * and turned into a reference into the string table so that we can
+ * get the type information when we process the data after the fact. In
+ * the case where we are referring to userland CTF data, we also need to
+ * to identify which ctf container in question we care about and encode
+ * that within the name.
+ */
+ if (dnp->dn_ident->di_id == DT_ACT_PRINT) {
+ dt_node_t *dret;
+ size_t n;
+ dt_module_t *dmp;
+
+ dret = yypcb->pcb_dret;
+ dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);
+
+ n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, dret->dn_type) + 1;
+ if (dmp->dm_pid != 0) {
+ ctflib = dt_module_getlibid(dtp, dmp, dret->dn_ctfp);
+ assert(ctflib >= 0);
+ n = snprintf(NULL, 0, "%s`%d`%ld", dmp->dm_name,
+ ctflib, dret->dn_type) + 1;
+ } else {
+ n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name,
+ dret->dn_type) + 1;
+ }
+ sdp->dtsd_strdata = dt_alloc(dtp, n);
+ if (sdp->dtsd_strdata == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ (void) snprintf(sdp->dtsd_strdata, n, "%s`%ld", dmp->dm_name,
+ dret->dn_type);
+ if (dmp->dm_pid != 0) {
+ (void) snprintf(sdp->dtsd_strdata, n, "%s`%d`%ld",
+ dmp->dm_name, ctflib, dret->dn_type);
+ } else {
+ (void) snprintf(sdp->dtsd_strdata, n, "%s`%ld",
+ dmp->dm_name, dret->dn_type);
+ }
+ }
+
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_DIFEXPR;
+}
+
+static void
+dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ dt_node_t *addr = dnp->dn_args;
+ dt_node_t *max = dnp->dn_args->dn_list;
+ dt_node_t *size;
+
+ char n[DT_TYPE_NAMELEN];
+
+ if (dt_node_is_integer(addr) == 0 && dt_node_is_pointer(addr) == 0) {
+ dnerror(addr, D_TRACEMEM_ADDR,
+ "tracemem( ) argument #1 is incompatible with "
+ "prototype:\n\tprototype: pointer or integer\n"
+ "\t argument: %s\n",
+ dt_node_type_name(addr, n, sizeof (n)));
+ }
+
+ if (dt_node_is_posconst(max) == 0) {
+ dnerror(max, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must "
+ "be a non-zero positive integral constant expression\n");
+ }
+
+ if ((size = max->dn_list) != NULL) {
+ if (size->dn_list != NULL) {
+ dnerror(size, D_TRACEMEM_ARGS, "tracemem ( ) prototype "
+ "mismatch: expected at most 3 args\n");
+ }
+
+ if (!dt_node_is_scalar(size)) {
+ dnerror(size, D_TRACEMEM_DYNSIZE, "tracemem ( ) "
+ "dynamic size (argument #3) must be of "
+ "scalar type\n");
+ }
+
+ dt_cg(yypcb, size);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_difo->dtdo_rtype = dt_int_rtype;
+ ap->dtad_kind = DTRACEACT_TRACEMEM_DYNSIZE;
+
+ ap = dt_stmt_action(dtp, sdp);
+ }
+
+ dt_cg(yypcb, addr);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_TRACEMEM;
+
+ ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;
+ ap->dtad_difo->dtdo_rtype.dtdt_size = max->dn_value;
+}
+
+static void
+dt_action_stack_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap, dt_node_t *arg0)
+{
+ ap->dtad_kind = DTRACEACT_STACK;
+
+ if (dtp->dt_options[DTRACEOPT_STACKFRAMES] != DTRACEOPT_UNSET) {
+ ap->dtad_arg = dtp->dt_options[DTRACEOPT_STACKFRAMES];
+ } else {
+ ap->dtad_arg = 0;
+ }
+
+ if (arg0 != NULL) {
+ if (arg0->dn_list != NULL) {
+ dnerror(arg0, D_STACK_PROTO, "stack( ) prototype "
+ "mismatch: too many arguments\n");
+ }
+
+ if (dt_node_is_posconst(arg0) == 0) {
+ dnerror(arg0, D_STACK_SIZE, "stack( ) size must be a "
+ "non-zero positive integral constant expression\n");
+ }
+
+ ap->dtad_arg = arg0->dn_value;
+ }
+}
+
+static void
+dt_action_stack(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+ dt_action_stack_args(dtp, ap, dnp->dn_args);
+}
+
+static void
+dt_action_ustack_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap, dt_node_t *dnp)
+{
+ uint32_t nframes = 0;
+ uint32_t strsize = 0; /* default string table size */
+ dt_node_t *arg0 = dnp->dn_args;
+ dt_node_t *arg1 = arg0 != NULL ? arg0->dn_list : NULL;
+
+ assert(dnp->dn_ident->di_id == DT_ACT_JSTACK ||
+ dnp->dn_ident->di_id == DT_ACT_USTACK);
+
+ if (dnp->dn_ident->di_id == DT_ACT_JSTACK) {
+ if (dtp->dt_options[DTRACEOPT_JSTACKFRAMES] != DTRACEOPT_UNSET)
+ nframes = dtp->dt_options[DTRACEOPT_JSTACKFRAMES];
+
+ if (dtp->dt_options[DTRACEOPT_JSTACKSTRSIZE] != DTRACEOPT_UNSET)
+ strsize = dtp->dt_options[DTRACEOPT_JSTACKSTRSIZE];
+
+ ap->dtad_kind = DTRACEACT_JSTACK;
+ } else {
+ assert(dnp->dn_ident->di_id == DT_ACT_USTACK);
+
+ if (dtp->dt_options[DTRACEOPT_USTACKFRAMES] != DTRACEOPT_UNSET)
+ nframes = dtp->dt_options[DTRACEOPT_USTACKFRAMES];
+
+ ap->dtad_kind = DTRACEACT_USTACK;
+ }
+
+ if (arg0 != NULL) {
+ if (!dt_node_is_posconst(arg0)) {
+ dnerror(arg0, D_USTACK_FRAMES, "ustack( ) argument #1 "
+ "must be a non-zero positive integer constant\n");
+ }
+ nframes = (uint32_t)arg0->dn_value;
+ }
+
+ if (arg1 != NULL) {
+ if (arg1->dn_kind != DT_NODE_INT ||
+ ((arg1->dn_flags & DT_NF_SIGNED) &&
+ (int64_t)arg1->dn_value < 0)) {
+ dnerror(arg1, D_USTACK_STRSIZE, "ustack( ) argument #2 "
+ "must be a positive integer constant\n");
+ }
+
+ if (arg1->dn_list != NULL) {
+ dnerror(arg1, D_USTACK_PROTO, "ustack( ) prototype "
+ "mismatch: too many arguments\n");
+ }
+
+ strsize = (uint32_t)arg1->dn_value;
+ }
+
+ ap->dtad_arg = DTRACE_USTACK_ARG(nframes, strsize);
+}
+
+static void
+dt_action_ustack(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+ dt_action_ustack_args(dtp, ap, dnp);
+}
+
+static void
+dt_action_setopt(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap;
+ dt_node_t *arg0, *arg1;
+
+ /*
+ * The prototype guarantees that we are called with either one or
+ * two arguments, and that any arguments that are present are strings.
+ */
+ arg0 = dnp->dn_args;
+ arg1 = arg0->dn_list;
+
+ ap = dt_stmt_action(dtp, sdp);
+ dt_cg(yypcb, arg0);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_LIBACT;
+ ap->dtad_arg = DT_ACT_SETOPT;
+
+ ap = dt_stmt_action(dtp, sdp);
+
+ if (arg1 == NULL) {
+ dt_action_difconst(ap, 0, DTRACEACT_LIBACT);
+ } else {
+ dt_cg(yypcb, arg1);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_LIBACT;
+ }
+
+ ap->dtad_arg = DT_ACT_SETOPT;
+}
+
+/*ARGSUSED*/
+static void
+dt_action_symmod_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap,
+ dt_node_t *dnp, dtrace_actkind_t kind)
+{
+ assert(kind == DTRACEACT_SYM || kind == DTRACEACT_MOD ||
+ kind == DTRACEACT_USYM || kind == DTRACEACT_UMOD ||
+ kind == DTRACEACT_UADDR);
+
+ dt_cg(yypcb, dnp);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = kind;
+ ap->dtad_difo->dtdo_rtype.dtdt_size = sizeof (uint64_t);
+}
+
+static void
+dt_action_symmod(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp,
+ dtrace_actkind_t kind)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+ dt_action_symmod_args(dtp, ap, dnp->dn_args, kind);
+}
+
+/*ARGSUSED*/
+static void
+dt_action_ftruncate(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ /*
+ * Library actions need a DIFO that serves as an argument. As
+ * ftruncate() doesn't take an argument, we generate the constant 0
+ * in a DIFO; this constant will be ignored when the ftruncate() is
+ * processed.
+ */
+ dt_action_difconst(ap, 0, DTRACEACT_LIBACT);
+ ap->dtad_arg = DT_ACT_FTRUNCATE;
+}
+
+/*ARGSUSED*/
+static void
+dt_action_stop(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ ap->dtad_kind = DTRACEACT_STOP;
+ ap->dtad_arg = 0;
+}
+
+/*ARGSUSED*/
+static void
+dt_action_breakpoint(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ ap->dtad_kind = DTRACEACT_BREAKPOINT;
+ ap->dtad_arg = 0;
+}
+
+/*ARGSUSED*/
+static void
+dt_action_panic(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ ap->dtad_kind = DTRACEACT_PANIC;
+ ap->dtad_arg = 0;
+}
+
+static void
+dt_action_chill(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ dt_cg(yypcb, dnp->dn_args);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_CHILL;
+}
+
+static void
+dt_action_raise(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ dt_cg(yypcb, dnp->dn_args);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_RAISE;
+}
+
+static void
+dt_action_exit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ dt_cg(yypcb, dnp->dn_args);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_EXIT;
+ ap->dtad_difo->dtdo_rtype.dtdt_size = sizeof (int);
+}
+
+static void
+dt_action_speculate(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ dt_cg(yypcb, dnp->dn_args);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_SPECULATE;
+}
+
+static void
+dt_action_printm(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ dt_node_t *size = dnp->dn_args;
+ dt_node_t *addr = dnp->dn_args->dn_list;
+
+ char n[DT_TYPE_NAMELEN];
+
+ if (dt_node_is_posconst(size) == 0) {
+ dnerror(size, D_PRINTM_SIZE, "printm( ) argument #1 must "
+ "be a non-zero positive integral constant expression\n");
+ }
+
+ if (dt_node_is_pointer(addr) == 0) {
+ dnerror(addr, D_PRINTM_ADDR,
+ "printm( ) argument #2 is incompatible with "
+ "prototype:\n\tprototype: pointer\n"
+ "\t argument: %s\n",
+ dt_node_type_name(addr, n, sizeof (n)));
+ }
+
+ dt_cg(yypcb, addr);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_PRINTM;
+
+ ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;
+ ap->dtad_difo->dtdo_rtype.dtdt_size = size->dn_value + sizeof(uintptr_t);
+}
+
+static void
+dt_action_commit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ dt_cg(yypcb, dnp->dn_args);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_COMMIT;
+}
+
+static void
+dt_action_discard(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ dt_cg(yypcb, dnp->dn_args);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_DISCARD;
+}
+
+static void
+dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ switch (dnp->dn_expr->dn_ident->di_id) {
+ case DT_ACT_BREAKPOINT:
+ dt_action_breakpoint(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_CHILL:
+ dt_action_chill(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_CLEAR:
+ dt_action_clear(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_COMMIT:
+ dt_action_commit(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_DENORMALIZE:
+ dt_action_normalize(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_DISCARD:
+ dt_action_discard(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_EXIT:
+ dt_action_exit(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_FREOPEN:
+ dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_FREOPEN);
+ break;
+ case DT_ACT_FTRUNCATE:
+ dt_action_ftruncate(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_MOD:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_MOD);
+ break;
+ case DT_ACT_NORMALIZE:
+ dt_action_normalize(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_PANIC:
+ dt_action_panic(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_PRINT:
+ dt_action_trace(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_PRINTA:
+ dt_action_printa(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_PRINTF:
+ dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_PRINTF);
+ break;
+ case DT_ACT_PRINTM:
+ dt_action_printm(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_RAISE:
+ dt_action_raise(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_SETOPT:
+ dt_action_setopt(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_SPECULATE:
+ dt_action_speculate(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_STACK:
+ dt_action_stack(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_STOP:
+ dt_action_stop(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_SYM:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_SYM);
+ break;
+ case DT_ACT_SYSTEM:
+ dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_SYSTEM);
+ break;
+ case DT_ACT_TRACE:
+ dt_action_trace(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_TRACEMEM:
+ dt_action_tracemem(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_TRUNC:
+ dt_action_trunc(dtp, dnp->dn_expr, sdp);
+ break;
+ case DT_ACT_UADDR:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UADDR);
+ break;
+ case DT_ACT_UMOD:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UMOD);
+ break;
+ case DT_ACT_USYM:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_USYM);
+ break;
+ case DT_ACT_USTACK:
+ case DT_ACT_JSTACK:
+ dt_action_ustack(dtp, dnp->dn_expr, sdp);
+ break;
+ default:
+ dnerror(dnp->dn_expr, D_UNKNOWN, "tracing function %s( ) is "
+ "not yet supported\n", dnp->dn_expr->dn_ident->di_name);
+ }
+}
+
+static void
+dt_compile_exp(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+ dt_cg(yypcb, dnp->dn_expr);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_difo->dtdo_rtype = dt_void_rtype;
+ ap->dtad_kind = DTRACEACT_DIFEXPR;
+}
+
+static void
+dt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dt_ident_t *aid, *fid;
+ dt_node_t *anp, *incr = NULL;
+ dtrace_actdesc_t *ap;
+ uint_t n = 1, argmax;
+ uint64_t arg = 0;
+
+ /*
+ * If the aggregation has no aggregating function applied to it, then
+ * this statement has no effect. Flag this as a programming error.
+ */
+ if (dnp->dn_aggfun == NULL) {
+ dnerror(dnp, D_AGG_NULL, "expression has null effect: @%s\n",
+ dnp->dn_ident->di_name);
+ }
+
+ aid = dnp->dn_ident;
+ fid = dnp->dn_aggfun->dn_ident;
+
+ if (dnp->dn_aggfun->dn_args != NULL &&
+ dt_node_is_scalar(dnp->dn_aggfun->dn_args) == 0) {
+ dnerror(dnp->dn_aggfun, D_AGG_SCALAR, "%s( ) argument #1 must "
+ "be of scalar type\n", fid->di_name);
+ }
+
+ /*
+ * The ID of the aggregation itself is implicitly recorded as the first
+ * member of each aggregation tuple so we can distinguish them later.
+ */
+ ap = dt_stmt_action(dtp, sdp);
+ dt_action_difconst(ap, aid->di_id, DTRACEACT_DIFEXPR);
+
+ for (anp = dnp->dn_aggtup; anp != NULL; anp = anp->dn_list) {
+ ap = dt_stmt_action(dtp, sdp);
+ n++;
+
+ if (anp->dn_kind == DT_NODE_FUNC) {
+ if (anp->dn_ident->di_id == DT_ACT_STACK) {
+ dt_action_stack_args(dtp, ap, anp->dn_args);
+ continue;
+ }
+
+ if (anp->dn_ident->di_id == DT_ACT_USTACK ||
+ anp->dn_ident->di_id == DT_ACT_JSTACK) {
+ dt_action_ustack_args(dtp, ap, anp);
+ continue;
+ }
+
+ switch (anp->dn_ident->di_id) {
+ case DT_ACT_UADDR:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_UADDR);
+ continue;
+
+ case DT_ACT_USYM:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_USYM);
+ continue;
+
+ case DT_ACT_UMOD:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_UMOD);
+ continue;
+
+ case DT_ACT_SYM:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_SYM);
+ continue;
+
+ case DT_ACT_MOD:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_MOD);
+ continue;
+
+ default:
+ break;
+ }
+ }
+
+ dt_cg(yypcb, anp);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_DIFEXPR;
+ }
+
+ if (fid->di_id == DTRACEAGG_LQUANTIZE) {
+ /*
+ * For linear quantization, we have between two and four
+ * arguments in addition to the expression:
+ *
+ * arg1 => Base value
+ * arg2 => Limit value
+ * arg3 => Quantization level step size (defaults to 1)
+ * arg4 => Quantization increment value (defaults to 1)
+ */
+ dt_node_t *arg1 = dnp->dn_aggfun->dn_args->dn_list;
+ dt_node_t *arg2 = arg1->dn_list;
+ dt_node_t *arg3 = arg2->dn_list;
+ dt_idsig_t *isp;
+ uint64_t nlevels, step = 1, oarg;
+ int64_t baseval, limitval;
+
+ if (arg1->dn_kind != DT_NODE_INT) {
+ dnerror(arg1, D_LQUANT_BASETYPE, "lquantize( ) "
+ "argument #1 must be an integer constant\n");
+ }
+
+ baseval = (int64_t)arg1->dn_value;
+
+ if (baseval < INT32_MIN || baseval > INT32_MAX) {
+ dnerror(arg1, D_LQUANT_BASEVAL, "lquantize( ) "
+ "argument #1 must be a 32-bit quantity\n");
+ }
+
+ if (arg2->dn_kind != DT_NODE_INT) {
+ dnerror(arg2, D_LQUANT_LIMTYPE, "lquantize( ) "
+ "argument #2 must be an integer constant\n");
+ }
+
+ limitval = (int64_t)arg2->dn_value;
+
+ if (limitval < INT32_MIN || limitval > INT32_MAX) {
+ dnerror(arg2, D_LQUANT_LIMVAL, "lquantize( ) "
+ "argument #2 must be a 32-bit quantity\n");
+ }
+
+ if (limitval < baseval) {
+ dnerror(dnp, D_LQUANT_MISMATCH,
+ "lquantize( ) base (argument #1) must be less "
+ "than limit (argument #2)\n");
+ }
+
+ if (arg3 != NULL) {
+ if (!dt_node_is_posconst(arg3)) {
+ dnerror(arg3, D_LQUANT_STEPTYPE, "lquantize( ) "
+ "argument #3 must be a non-zero positive "
+ "integer constant\n");
+ }
+
+ if ((step = arg3->dn_value) > UINT16_MAX) {
+ dnerror(arg3, D_LQUANT_STEPVAL, "lquantize( ) "
+ "argument #3 must be a 16-bit quantity\n");
+ }
+ }
+
+ nlevels = (limitval - baseval) / step;
+
+ if (nlevels == 0) {
+ dnerror(dnp, D_LQUANT_STEPLARGE,
+ "lquantize( ) step (argument #3) too large: must "
+ "have at least one quantization level\n");
+ }
+
+ if (nlevels > UINT16_MAX) {
+ dnerror(dnp, D_LQUANT_STEPSMALL, "lquantize( ) step "
+ "(argument #3) too small: number of quantization "
+ "levels must be a 16-bit quantity\n");
+ }
+
+ arg = (step << DTRACE_LQUANTIZE_STEPSHIFT) |
+ (nlevels << DTRACE_LQUANTIZE_LEVELSHIFT) |
+ ((baseval << DTRACE_LQUANTIZE_BASESHIFT) &
+ DTRACE_LQUANTIZE_BASEMASK);
+
+ assert(arg != 0);
+
+ isp = (dt_idsig_t *)aid->di_data;
+
+ if (isp->dis_auxinfo == 0) {
+ /*
+ * This is the first time we've seen an lquantize()
+ * for this aggregation; we'll store our argument
+ * as the auxiliary signature information.
+ */
+ isp->dis_auxinfo = arg;
+ } else if ((oarg = isp->dis_auxinfo) != arg) {
+ /*
+ * If we have seen this lquantize() before and the
+ * argument doesn't match the original argument, pick
+ * the original argument apart to concisely report the
+ * mismatch.
+ */
+ int obaseval = DTRACE_LQUANTIZE_BASE(oarg);
+ int onlevels = DTRACE_LQUANTIZE_LEVELS(oarg);
+ int ostep = DTRACE_LQUANTIZE_STEP(oarg);
+
+ if (obaseval != baseval) {
+ dnerror(dnp, D_LQUANT_MATCHBASE, "lquantize( ) "
+ "base (argument #1) doesn't match previous "
+ "declaration: expected %d, found %d\n",
+ obaseval, (int)baseval);
+ }
+
+ if (onlevels * ostep != nlevels * step) {
+ dnerror(dnp, D_LQUANT_MATCHLIM, "lquantize( ) "
+ "limit (argument #2) doesn't match previous"
+ " declaration: expected %d, found %d\n",
+ obaseval + onlevels * ostep,
+ (int)baseval + (int)nlevels * (int)step);
+ }
+
+ if (ostep != step) {
+ dnerror(dnp, D_LQUANT_MATCHSTEP, "lquantize( ) "
+ "step (argument #3) doesn't match previous "
+ "declaration: expected %d, found %d\n",
+ ostep, (int)step);
+ }
+
+ /*
+ * We shouldn't be able to get here -- one of the
+ * parameters must be mismatched if the arguments
+ * didn't match.
+ */
+ assert(0);
+ }
+
+ incr = arg3 != NULL ? arg3->dn_list : NULL;
+ argmax = 5;
+ }
+
+ if (fid->di_id == DTRACEAGG_LLQUANTIZE) {
+ /*
+ * For log/linear quantizations, we have between one and five
+ * arguments in addition to the expression:
+ *
+ * arg1 => Factor
+ * arg2 => Low magnitude
+ * arg3 => High magnitude
+ * arg4 => Number of steps per magnitude
+ * arg5 => Quantization increment value (defaults to 1)
+ */
+ dt_node_t *llarg = dnp->dn_aggfun->dn_args->dn_list;
+ uint64_t oarg, order, v;
+ dt_idsig_t *isp;
+ int i;
+
+ struct {
+ char *str; /* string identifier */
+ int badtype; /* error on bad type */
+ int badval; /* error on bad value */
+ int mismatch; /* error on bad match */
+ int shift; /* shift value */
+ uint16_t value; /* value itself */
+ } args[] = {
+ { "factor", D_LLQUANT_FACTORTYPE,
+ D_LLQUANT_FACTORVAL, D_LLQUANT_FACTORMATCH,
+ DTRACE_LLQUANTIZE_FACTORSHIFT },
+ { "low magnitude", D_LLQUANT_LOWTYPE,
+ D_LLQUANT_LOWVAL, D_LLQUANT_LOWMATCH,
+ DTRACE_LLQUANTIZE_LOWSHIFT },
+ { "high magnitude", D_LLQUANT_HIGHTYPE,
+ D_LLQUANT_HIGHVAL, D_LLQUANT_HIGHMATCH,
+ DTRACE_LLQUANTIZE_HIGHSHIFT },
+ { "linear steps per magnitude", D_LLQUANT_NSTEPTYPE,
+ D_LLQUANT_NSTEPVAL, D_LLQUANT_NSTEPMATCH,
+ DTRACE_LLQUANTIZE_NSTEPSHIFT },
+ { NULL }
+ };
+
+ assert(arg == 0);
+
+ for (i = 0; args[i].str != NULL; i++) {
+ if (llarg->dn_kind != DT_NODE_INT) {
+ dnerror(llarg, args[i].badtype, "llquantize( ) "
+ "argument #%d (%s) must be an "
+ "integer constant\n", i + 1, args[i].str);
+ }
+
+ if ((uint64_t)llarg->dn_value > UINT16_MAX) {
+ dnerror(llarg, args[i].badval, "llquantize( ) "
+ "argument #%d (%s) must be an unsigned "
+ "16-bit quantity\n", i + 1, args[i].str);
+ }
+
+ args[i].value = (uint16_t)llarg->dn_value;
+
+ assert(!(arg & ((uint64_t)UINT16_MAX <<
+ args[i].shift)));
+ arg |= ((uint64_t)args[i].value << args[i].shift);
+ llarg = llarg->dn_list;
+ }
+
+ assert(arg != 0);
+
+ if (args[0].value < 2) {
+ dnerror(dnp, D_LLQUANT_FACTORSMALL, "llquantize( ) "
+ "factor (argument #1) must be two or more\n");
+ }
+
+ if (args[1].value >= args[2].value) {
+ dnerror(dnp, D_LLQUANT_MAGRANGE, "llquantize( ) "
+ "high magnitude (argument #3) must be greater "
+ "than low magnitude (argument #2)\n");
+ }
+
+ if (args[3].value < args[0].value) {
+ dnerror(dnp, D_LLQUANT_FACTORNSTEPS, "llquantize( ) "
+ "factor (argument #1) must be less than or "
+ "equal to the number of linear steps per "
+ "magnitude (argument #4)\n");
+ }
+
+ for (v = args[0].value; v < args[3].value; v *= args[0].value)
+ continue;
+
+ if ((args[3].value % args[0].value) || (v % args[3].value)) {
+ dnerror(dnp, D_LLQUANT_FACTOREVEN, "llquantize( ) "
+ "factor (argument #1) must evenly divide the "
+ "number of steps per magnitude (argument #4), "
+ "and the number of steps per magnitude must evenly "
+ "divide a power of the factor\n");
+ }
+
+ for (i = 0, order = 1; i <= args[2].value + 1; i++) {
+ if (order * args[0].value > order) {
+ order *= args[0].value;
+ continue;
+ }
+
+ dnerror(dnp, D_LLQUANT_MAGTOOBIG, "llquantize( ) "
+ "factor (%d) raised to power of high magnitude "
+ "(%d) plus 1 overflows 64-bits\n", args[0].value,
+ args[2].value);
+ }
+
+ isp = (dt_idsig_t *)aid->di_data;
+
+ if (isp->dis_auxinfo == 0) {
+ /*
+ * This is the first time we've seen an llquantize()
+ * for this aggregation; we'll store our argument
+ * as the auxiliary signature information.
+ */
+ isp->dis_auxinfo = arg;
+ } else if ((oarg = isp->dis_auxinfo) != arg) {
+ /*
+ * If we have seen this llquantize() before and the
+ * argument doesn't match the original argument, pick
+ * the original argument apart to concisely report the
+ * mismatch.
+ */
+ int expected = 0, found = 0;
+
+ for (i = 0; expected == found; i++) {
+ assert(args[i].str != NULL);
+
+ expected = (oarg >> args[i].shift) & UINT16_MAX;
+ found = (arg >> args[i].shift) & UINT16_MAX;
+ }
+
+ dnerror(dnp, args[i - 1].mismatch, "llquantize( ) "
+ "%s (argument #%d) doesn't match previous "
+ "declaration: expected %d, found %d\n",
+ args[i - 1].str, i, expected, found);
+ }
+
+ incr = llarg;
+ argmax = 6;
+ }
+
+ if (fid->di_id == DTRACEAGG_QUANTIZE) {
+ incr = dnp->dn_aggfun->dn_args->dn_list;
+ argmax = 2;
+ }
+
+ if (incr != NULL) {
+ if (!dt_node_is_scalar(incr)) {
+ dnerror(dnp, D_PROTO_ARG, "%s( ) increment value "
+ "(argument #%d) must be of scalar type\n",
+ fid->di_name, argmax);
+ }
+
+ if ((anp = incr->dn_list) != NULL) {
+ int argc = argmax;
+
+ for (; anp != NULL; anp = anp->dn_list)
+ argc++;
+
+ dnerror(incr, D_PROTO_LEN, "%s( ) prototype "
+ "mismatch: %d args passed, at most %d expected",
+ fid->di_name, argc, argmax);
+ }
+
+ ap = dt_stmt_action(dtp, sdp);
+ n++;
+
+ dt_cg(yypcb, incr);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_difo->dtdo_rtype = dt_void_rtype;
+ ap->dtad_kind = DTRACEACT_DIFEXPR;
+ }
+
+ assert(sdp->dtsd_aggdata == NULL);
+ sdp->dtsd_aggdata = aid;
+
+ ap = dt_stmt_action(dtp, sdp);
+ assert(fid->di_kind == DT_IDENT_AGGFUNC);
+ assert(DTRACEACT_ISAGG(fid->di_id));
+ ap->dtad_kind = fid->di_id;
+ ap->dtad_ntuple = n;
+ ap->dtad_arg = arg;
+
+ if (dnp->dn_aggfun->dn_args != NULL) {
+ dt_cg(yypcb, dnp->dn_aggfun->dn_args);
+ ap->dtad_difo = dt_as(yypcb);
+ }
+}
+
+static void
+dt_compile_one_clause(dtrace_hdl_t *dtp, dt_node_t *cnp, dt_node_t *pnp)
+{
+ dtrace_ecbdesc_t *edp;
+ dtrace_stmtdesc_t *sdp;
+ dt_node_t *dnp;
+
+ yylineno = pnp->dn_line;
+ dt_setcontext(dtp, pnp->dn_desc);
+ (void) dt_node_cook(cnp, DT_IDFLG_REF);
+
+ if (DT_TREEDUMP_PASS(dtp, 2))
+ dt_node_printr(cnp, stderr, 0);
+
+ if ((edp = dt_ecbdesc_create(dtp, pnp->dn_desc)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ assert(yypcb->pcb_ecbdesc == NULL);
+ yypcb->pcb_ecbdesc = edp;
+
+ if (cnp->dn_pred != NULL) {
+ dt_cg(yypcb, cnp->dn_pred);
+ edp->dted_pred.dtpdd_difo = dt_as(yypcb);
+ }
+
+ if (cnp->dn_acts == NULL) {
+ dt_stmt_append(dt_stmt_create(dtp, edp,
+ cnp->dn_ctxattr, _dtrace_defattr), cnp);
+ }
+
+ for (dnp = cnp->dn_acts; dnp != NULL; dnp = dnp->dn_list) {
+ assert(yypcb->pcb_stmt == NULL);
+ sdp = dt_stmt_create(dtp, edp, cnp->dn_ctxattr, cnp->dn_attr);
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_DEXPR:
+ if (dnp->dn_expr->dn_kind == DT_NODE_AGG)
+ dt_compile_agg(dtp, dnp->dn_expr, sdp);
+ else
+ dt_compile_exp(dtp, dnp, sdp);
+ break;
+ case DT_NODE_DFUNC:
+ dt_compile_fun(dtp, dnp, sdp);
+ break;
+ case DT_NODE_AGG:
+ dt_compile_agg(dtp, dnp, sdp);
+ break;
+ default:
+ dnerror(dnp, D_UNKNOWN, "internal error -- node kind "
+ "%u is not a valid statement\n", dnp->dn_kind);
+ }
+
+ assert(yypcb->pcb_stmt == sdp);
+ dt_stmt_append(sdp, dnp);
+ }
+
+ assert(yypcb->pcb_ecbdesc == edp);
+ dt_ecbdesc_release(dtp, edp);
+ dt_endcontext(dtp);
+ yypcb->pcb_ecbdesc = NULL;
+}
+
+static void
+dt_compile_clause(dtrace_hdl_t *dtp, dt_node_t *cnp)
+{
+ dt_node_t *pnp;
+
+ for (pnp = cnp->dn_pdescs; pnp != NULL; pnp = pnp->dn_list)
+ dt_compile_one_clause(dtp, cnp, pnp);
+}
+
+static void
+dt_compile_xlator(dt_node_t *dnp)
+{
+ dt_xlator_t *dxp = dnp->dn_xlator;
+ dt_node_t *mnp;
+
+ for (mnp = dnp->dn_members; mnp != NULL; mnp = mnp->dn_list) {
+ assert(dxp->dx_membdif[mnp->dn_membid] == NULL);
+ dt_cg(yypcb, mnp);
+ dxp->dx_membdif[mnp->dn_membid] = dt_as(yypcb);
+ }
+}
+
+void
+dt_setcontext(dtrace_hdl_t *dtp, dtrace_probedesc_t *pdp)
+{
+ const dtrace_pattr_t *pap;
+ dt_probe_t *prp;
+ dt_provider_t *pvp;
+ dt_ident_t *idp;
+ char attrstr[8];
+ int err;
+
+ /*
+ * Both kernel and pid based providers are allowed to have names
+ * ending with what could be interpreted as a number. We assume it's
+ * a pid and that we may need to dynamically create probes for
+ * that process if:
+ *
+ * (1) The provider doesn't exist, or,
+ * (2) The provider exists and has DTRACE_PRIV_PROC privilege.
+ *
+ * On an error, dt_pid_create_probes() will set the error message
+ * and tag -- we just have to longjmp() out of here.
+ */
+ if (isdigit(pdp->dtpd_provider[strlen(pdp->dtpd_provider) - 1]) &&
+ ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) == NULL ||
+ pvp->pv_desc.dtvd_priv.dtpp_flags & DTRACE_PRIV_PROC) &&
+ dt_pid_create_probes(pdp, dtp, yypcb) != 0) {
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+ }
+
+ /*
+ * Call dt_probe_info() to get the probe arguments and attributes. If
+ * a representative probe is found, set 'pap' to the probe provider's
+ * attributes. Otherwise set 'pap' to default Unstable attributes.
+ */
+ if ((prp = dt_probe_info(dtp, pdp, &yypcb->pcb_pinfo)) == NULL) {
+ pap = &_dtrace_prvdesc;
+ err = dtrace_errno(dtp);
+ bzero(&yypcb->pcb_pinfo, sizeof (dtrace_probeinfo_t));
+ yypcb->pcb_pinfo.dtp_attr = pap->dtpa_provider;
+ yypcb->pcb_pinfo.dtp_arga = pap->dtpa_args;
+ } else {
+ pap = &prp->pr_pvp->pv_desc.dtvd_attr;
+ err = 0;
+ }
+
+ if (err == EDT_NOPROBE && !(yypcb->pcb_cflags & DTRACE_C_ZDEFS)) {
+ xyerror(D_PDESC_ZERO, "probe description %s:%s:%s:%s does not "
+ "match any probes\n", pdp->dtpd_provider, pdp->dtpd_mod,
+ pdp->dtpd_func, pdp->dtpd_name);
+ }
+
+ if (err != EDT_NOPROBE && err != EDT_UNSTABLE && err != 0)
+ xyerror(D_PDESC_INVAL, "%s\n", dtrace_errmsg(dtp, err));
+
+ dt_dprintf("set context to %s:%s:%s:%s [%u] prp=%p attr=%s argc=%d\n",
+ pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name,
+ pdp->dtpd_id, (void *)prp, dt_attr_str(yypcb->pcb_pinfo.dtp_attr,
+ attrstr, sizeof (attrstr)), yypcb->pcb_pinfo.dtp_argc);
+
+ /*
+ * Reset the stability attributes of D global variables that vary
+ * based on the attributes of the provider and context itself.
+ */
+ if ((idp = dt_idhash_lookup(dtp->dt_globals, "probeprov")) != NULL)
+ idp->di_attr = pap->dtpa_provider;
+ if ((idp = dt_idhash_lookup(dtp->dt_globals, "probemod")) != NULL)
+ idp->di_attr = pap->dtpa_mod;
+ if ((idp = dt_idhash_lookup(dtp->dt_globals, "probefunc")) != NULL)
+ idp->di_attr = pap->dtpa_func;
+ if ((idp = dt_idhash_lookup(dtp->dt_globals, "probename")) != NULL)
+ idp->di_attr = pap->dtpa_name;
+ if ((idp = dt_idhash_lookup(dtp->dt_globals, "args")) != NULL)
+ idp->di_attr = pap->dtpa_args;
+
+ yypcb->pcb_pdesc = pdp;
+ yypcb->pcb_probe = prp;
+}
+
+/*
+ * Reset context-dependent variables and state at the end of cooking a D probe
+ * definition clause. This ensures that external declarations between clauses
+ * do not reference any stale context-dependent data from the previous clause.
+ */
+void
+dt_endcontext(dtrace_hdl_t *dtp)
+{
+ static const char *const cvars[] = {
+ "probeprov", "probemod", "probefunc", "probename", "args", NULL
+ };
+
+ dt_ident_t *idp;
+ int i;
+
+ for (i = 0; cvars[i] != NULL; i++) {
+ if ((idp = dt_idhash_lookup(dtp->dt_globals, cvars[i])) != NULL)
+ idp->di_attr = _dtrace_defattr;
+ }
+
+ yypcb->pcb_pdesc = NULL;
+ yypcb->pcb_probe = NULL;
+}
+
+static int
+dt_reduceid(dt_idhash_t *dhp, dt_ident_t *idp, dtrace_hdl_t *dtp)
+{
+ if (idp->di_vers != 0 && idp->di_vers > dtp->dt_vmax)
+ dt_idhash_delete(dhp, idp);
+
+ return (0);
+}
+
+/*
+ * When dtrace_setopt() is called for "version", it calls dt_reduce() to remove
+ * any identifiers or translators that have been previously defined as bound to
+ * a version greater than the specified version. Therefore, in our current
+ * version implementation, establishing a binding is a one-way transformation.
+ * In addition, no versioning is currently provided for types as our .d library
+ * files do not define any types and we reserve prefixes DTRACE_ and dtrace_
+ * for our exclusive use. If required, type versioning will require more work.
+ */
+int
+dt_reduce(dtrace_hdl_t *dtp, dt_version_t v)
+{
+ char s[DT_VERSION_STRMAX];
+ dt_xlator_t *dxp, *nxp;
+
+ if (v > dtp->dt_vmax)
+ return (dt_set_errno(dtp, EDT_VERSREDUCED));
+ else if (v == dtp->dt_vmax)
+ return (0); /* no reduction necessary */
+
+ dt_dprintf("reducing api version to %s\n",
+ dt_version_num2str(v, s, sizeof (s)));
+
+ dtp->dt_vmax = v;
+
+ for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = nxp) {
+ nxp = dt_list_next(dxp);
+ if ((dxp->dx_souid.di_vers != 0 && dxp->dx_souid.di_vers > v) ||
+ (dxp->dx_ptrid.di_vers != 0 && dxp->dx_ptrid.di_vers > v))
+ dt_list_delete(&dtp->dt_xlators, dxp);
+ }
+
+ (void) dt_idhash_iter(dtp->dt_macros, (dt_idhash_f *)dt_reduceid, dtp);
+ (void) dt_idhash_iter(dtp->dt_aggs, (dt_idhash_f *)dt_reduceid, dtp);
+ (void) dt_idhash_iter(dtp->dt_globals, (dt_idhash_f *)dt_reduceid, dtp);
+ (void) dt_idhash_iter(dtp->dt_tls, (dt_idhash_f *)dt_reduceid, dtp);
+
+ return (0);
+}
+
+/*
+ * Fork and exec the cpp(1) preprocessor to run over the specified input file,
+ * and return a FILE handle for the cpp output. We use the /dev/fd filesystem
+ * here to simplify the code by leveraging file descriptor inheritance.
+ */
+static FILE *
+dt_preproc(dtrace_hdl_t *dtp, FILE *ifp)
+{
+ int argc = dtp->dt_cpp_argc;
+ char **argv = malloc(sizeof (char *) * (argc + 5));
+ FILE *ofp = tmpfile();
+
+#ifdef illumos
+ char ipath[20], opath[20]; /* big enough for /dev/fd/ + INT_MAX + \0 */
+#endif
+ char verdef[32]; /* big enough for -D__SUNW_D_VERSION=0x%08x + \0 */
+
+ struct sigaction act, oact;
+ sigset_t mask, omask;
+
+ int wstat, estat;
+ pid_t pid;
+#ifdef illumos
+ off64_t off;
+#else
+ off_t off = 0;
+#endif
+ int c;
+
+ if (argv == NULL || ofp == NULL) {
+ (void) dt_set_errno(dtp, errno);
+ goto err;
+ }
+
+ /*
+ * If the input is a seekable file, see if it is an interpreter file.
+ * If we see #!, seek past the first line because cpp will choke on it.
+ * We start cpp just prior to the \n at the end of this line so that
+ * it still sees the newline, ensuring that #line values are correct.
+ */
+ if (isatty(fileno(ifp)) == 0 && (off = ftello64(ifp)) != -1) {
+ if ((c = fgetc(ifp)) == '#' && (c = fgetc(ifp)) == '!') {
+ for (off += 2; c != '\n'; off++) {
+ if ((c = fgetc(ifp)) == EOF)
+ break;
+ }
+ if (c == '\n')
+ off--; /* start cpp just prior to \n */
+ }
+ (void) fflush(ifp);
+ (void) fseeko64(ifp, off, SEEK_SET);
+ }
+
+#ifdef illumos
+ (void) snprintf(ipath, sizeof (ipath), "/dev/fd/%d", fileno(ifp));
+ (void) snprintf(opath, sizeof (opath), "/dev/fd/%d", fileno(ofp));
+#endif
+
+ bcopy(dtp->dt_cpp_argv, argv, sizeof (char *) * argc);
+
+ (void) snprintf(verdef, sizeof (verdef),
+ "-D__SUNW_D_VERSION=0x%08x", dtp->dt_vmax);
+ argv[argc++] = verdef;
+
+#ifdef illumos
+ switch (dtp->dt_stdcmode) {
+ case DT_STDC_XA:
+ case DT_STDC_XT:
+ argv[argc++] = "-D__STDC__=0";
+ break;
+ case DT_STDC_XC:
+ argv[argc++] = "-D__STDC__=1";
+ break;
+ }
+
+ argv[argc++] = ipath;
+ argv[argc++] = opath;
+#else
+ argv[argc++] = "-P";
+#endif
+ argv[argc] = NULL;
+
+ /*
+ * libdtrace must be able to be embedded in other programs that may
+ * include application-specific signal handlers. Therefore, if we
+ * need to fork to run cpp(1), we must avoid generating a SIGCHLD
+ * that could confuse the containing application. To do this,
+ * we block SIGCHLD and reset its disposition to SIG_DFL.
+ * We restore our signal state once we are done.
+ */
+ (void) sigemptyset(&mask);
+ (void) sigaddset(&mask, SIGCHLD);
+ (void) sigprocmask(SIG_BLOCK, &mask, &omask);
+
+ bzero(&act, sizeof (act));
+ act.sa_handler = SIG_DFL;
+ (void) sigaction(SIGCHLD, &act, &oact);
+
+ if ((pid = fork1()) == -1) {
+ (void) sigaction(SIGCHLD, &oact, NULL);
+ (void) sigprocmask(SIG_SETMASK, &omask, NULL);
+ (void) dt_set_errno(dtp, EDT_CPPFORK);
+ goto err;
+ }
+
+ if (pid == 0) {
+#ifndef illumos
+ if (isatty(fileno(ifp)) == 0)
+ lseek(fileno(ifp), off, SEEK_SET);
+ dup2(fileno(ifp), 0);
+ dup2(fileno(ofp), 1);
+#endif
+ (void) execvp(dtp->dt_cpp_path, argv);
+ _exit(errno == ENOENT ? 127 : 126);
+ }
+
+ do {
+ dt_dprintf("waiting for %s (PID %d)\n", dtp->dt_cpp_path,
+ (int)pid);
+ } while (waitpid(pid, &wstat, 0) == -1 && errno == EINTR);
+
+ (void) sigaction(SIGCHLD, &oact, NULL);
+ (void) sigprocmask(SIG_SETMASK, &omask, NULL);
+
+ dt_dprintf("%s returned exit status 0x%x\n", dtp->dt_cpp_path, wstat);
+ estat = WIFEXITED(wstat) ? WEXITSTATUS(wstat) : -1;
+
+ if (estat != 0) {
+ switch (estat) {
+ case 126:
+ (void) dt_set_errno(dtp, EDT_CPPEXEC);
+ break;
+ case 127:
+ (void) dt_set_errno(dtp, EDT_CPPENT);
+ break;
+ default:
+ (void) dt_set_errno(dtp, EDT_CPPERR);
+ }
+ goto err;
+ }
+
+ free(argv);
+ (void) fflush(ofp);
+ (void) fseek(ofp, 0, SEEK_SET);
+ return (ofp);
+
+err:
+ free(argv);
+ (void) fclose(ofp);
+ return (NULL);
+}
+
+static void
+dt_lib_depend_error(dtrace_hdl_t *dtp, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap);
+ va_end(ap);
+}
+
+int
+dt_lib_depend_add(dtrace_hdl_t *dtp, dt_list_t *dlp, const char *arg)
+{
+ dt_lib_depend_t *dld;
+ const char *end;
+
+ assert(arg != NULL);
+
+ if ((end = strrchr(arg, '/')) == NULL)
+ return (dt_set_errno(dtp, EINVAL));
+
+ if ((dld = dt_zalloc(dtp, sizeof (dt_lib_depend_t))) == NULL)
+ return (-1);
+
+ if ((dld->dtld_libpath = dt_alloc(dtp, MAXPATHLEN)) == NULL) {
+ dt_free(dtp, dld);
+ return (-1);
+ }
+
+ (void) strlcpy(dld->dtld_libpath, arg, end - arg + 2);
+ if ((dld->dtld_library = strdup(arg)) == NULL) {
+ dt_free(dtp, dld->dtld_libpath);
+ dt_free(dtp, dld);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ dt_list_append(dlp, dld);
+ return (0);
+}
+
+dt_lib_depend_t *
+dt_lib_depend_lookup(dt_list_t *dld, const char *arg)
+{
+ dt_lib_depend_t *dldn;
+
+ for (dldn = dt_list_next(dld); dldn != NULL;
+ dldn = dt_list_next(dldn)) {
+ if (strcmp(dldn->dtld_library, arg) == 0)
+ return (dldn);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Go through all the library files, and, if any library dependencies exist for
+ * that file, add it to that node's list of dependents. The result of this
+ * will be a graph which can then be topologically sorted to produce a
+ * compilation order.
+ */
+static int
+dt_lib_build_graph(dtrace_hdl_t *dtp)
+{
+ dt_lib_depend_t *dld, *dpld;
+
+ for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;
+ dld = dt_list_next(dld)) {
+ char *library = dld->dtld_library;
+
+ for (dpld = dt_list_next(&dld->dtld_dependencies); dpld != NULL;
+ dpld = dt_list_next(dpld)) {
+ dt_lib_depend_t *dlda;
+
+ if ((dlda = dt_lib_depend_lookup(&dtp->dt_lib_dep,
+ dpld->dtld_library)) == NULL) {
+ dt_lib_depend_error(dtp,
+ "Invalid library dependency in %s: %s\n",
+ dld->dtld_library, dpld->dtld_library);
+
+ return (dt_set_errno(dtp, EDT_COMPILER));
+ }
+
+ if ((dt_lib_depend_add(dtp, &dlda->dtld_dependents,
+ library)) != 0) {
+ return (-1); /* preserve dt_errno */
+ }
+ }
+ }
+ return (0);
+}
+
+static int
+dt_topo_sort(dtrace_hdl_t *dtp, dt_lib_depend_t *dld, int *count)
+{
+ dt_lib_depend_t *dpld, *dlda, *new;
+
+ dld->dtld_start = ++(*count);
+
+ for (dpld = dt_list_next(&dld->dtld_dependents); dpld != NULL;
+ dpld = dt_list_next(dpld)) {
+ dlda = dt_lib_depend_lookup(&dtp->dt_lib_dep,
+ dpld->dtld_library);
+ assert(dlda != NULL);
+
+ if (dlda->dtld_start == 0 &&
+ dt_topo_sort(dtp, dlda, count) == -1)
+ return (-1);
+ }
+
+ if ((new = dt_zalloc(dtp, sizeof (dt_lib_depend_t))) == NULL)
+ return (-1);
+
+ if ((new->dtld_library = strdup(dld->dtld_library)) == NULL) {
+ dt_free(dtp, new);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ new->dtld_start = dld->dtld_start;
+ new->dtld_finish = dld->dtld_finish = ++(*count);
+ dt_list_prepend(&dtp->dt_lib_dep_sorted, new);
+
+ dt_dprintf("library %s sorted (%d/%d)\n", new->dtld_library,
+ new->dtld_start, new->dtld_finish);
+
+ return (0);
+}
+
+static int
+dt_lib_depend_sort(dtrace_hdl_t *dtp)
+{
+ dt_lib_depend_t *dld, *dpld, *dlda;
+ int count = 0;
+
+ if (dt_lib_build_graph(dtp) == -1)
+ return (-1); /* preserve dt_errno */
+
+ /*
+ * Perform a topological sort of the graph that hangs off
+ * dtp->dt_lib_dep. The result of this process will be a
+ * dependency ordered list located at dtp->dt_lib_dep_sorted.
+ */
+ for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;
+ dld = dt_list_next(dld)) {
+ if (dld->dtld_start == 0 &&
+ dt_topo_sort(dtp, dld, &count) == -1)
+ return (-1); /* preserve dt_errno */;
+ }
+
+ /*
+ * Check the graph for cycles. If an ancestor's finishing time is
+ * less than any of its dependent's finishing times then a back edge
+ * exists in the graph and this is a cycle.
+ */
+ for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;
+ dld = dt_list_next(dld)) {
+ for (dpld = dt_list_next(&dld->dtld_dependents); dpld != NULL;
+ dpld = dt_list_next(dpld)) {
+ dlda = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted,
+ dpld->dtld_library);
+ assert(dlda != NULL);
+
+ if (dlda->dtld_finish > dld->dtld_finish) {
+ dt_lib_depend_error(dtp,
+ "Cyclic dependency detected: %s => %s\n",
+ dld->dtld_library, dpld->dtld_library);
+
+ return (dt_set_errno(dtp, EDT_COMPILER));
+ }
+ }
+ }
+
+ return (0);
+}
+
+static void
+dt_lib_depend_free(dtrace_hdl_t *dtp)
+{
+ dt_lib_depend_t *dld, *dlda;
+
+ while ((dld = dt_list_next(&dtp->dt_lib_dep)) != NULL) {
+ while ((dlda = dt_list_next(&dld->dtld_dependencies)) != NULL) {
+ dt_list_delete(&dld->dtld_dependencies, dlda);
+ dt_free(dtp, dlda->dtld_library);
+ dt_free(dtp, dlda->dtld_libpath);
+ dt_free(dtp, dlda);
+ }
+ while ((dlda = dt_list_next(&dld->dtld_dependents)) != NULL) {
+ dt_list_delete(&dld->dtld_dependents, dlda);
+ dt_free(dtp, dlda->dtld_library);
+ dt_free(dtp, dlda->dtld_libpath);
+ dt_free(dtp, dlda);
+ }
+ dt_list_delete(&dtp->dt_lib_dep, dld);
+ dt_free(dtp, dld->dtld_library);
+ dt_free(dtp, dld->dtld_libpath);
+ dt_free(dtp, dld);
+ }
+
+ while ((dld = dt_list_next(&dtp->dt_lib_dep_sorted)) != NULL) {
+ dt_list_delete(&dtp->dt_lib_dep_sorted, dld);
+ dt_free(dtp, dld->dtld_library);
+ dt_free(dtp, dld);
+ }
+}
+
+/*
+ * Open all the .d library files found in the specified directory and
+ * compile each one of them. We silently ignore any missing directories and
+ * other files found therein. We only fail (and thereby fail dt_load_libs()) if
+ * we fail to compile a library and the error is something other than #pragma D
+ * depends_on. Dependency errors are silently ignored to permit a library
+ * directory to contain libraries which may not be accessible depending on our
+ * privileges.
+ */
+static int
+dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
+{
+ struct dirent *dp;
+ const char *p, *end;
+ DIR *dirp;
+
+ char fname[PATH_MAX];
+ FILE *fp;
+ void *rv;
+ dt_lib_depend_t *dld;
+
+ if ((dirp = opendir(path)) == NULL) {
+ dt_dprintf("skipping lib dir %s: %s\n", path, strerror(errno));
+ return (0);
+ }
+
+ /* First, parse each file for library dependencies. */
+ while ((dp = readdir(dirp)) != NULL) {
+ if ((p = strrchr(dp->d_name, '.')) == NULL || strcmp(p, ".d"))
+ continue; /* skip any filename not ending in .d */
+
+ (void) snprintf(fname, sizeof (fname),
+ "%s/%s", path, dp->d_name);
+
+ if ((fp = fopen(fname, "r")) == NULL) {
+ dt_dprintf("skipping library %s: %s\n",
+ fname, strerror(errno));
+ continue;
+ }
+
+ /*
+ * Skip files whose name match an already processed library
+ */
+ for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;
+ dld = dt_list_next(dld)) {
+ end = strrchr(dld->dtld_library, '/');
+ /* dt_lib_depend_add ensures this */
+ assert(end != NULL);
+ if (strcmp(end + 1, dp->d_name) == 0)
+ break;
+ }
+
+ if (dld != NULL) {
+ dt_dprintf("skipping library %s, already processed "
+ "library with the same name: %s", dp->d_name,
+ dld->dtld_library);
+ (void) fclose(fp);
+ continue;
+ }
+
+ dtp->dt_filetag = fname;
+ if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0) {
+ (void) fclose(fp);
+ return (-1); /* preserve dt_errno */
+ }
+
+ rv = dt_compile(dtp, DT_CTX_DPROG,
+ DTRACE_PROBESPEC_NAME, NULL,
+ DTRACE_C_EMPTY | DTRACE_C_CTL, 0, NULL, fp, NULL);
+
+ if (rv != NULL && dtp->dt_errno &&
+ (dtp->dt_errno != EDT_COMPILER ||
+ dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) {
+ (void) fclose(fp);
+ return (-1); /* preserve dt_errno */
+ }
+
+ if (dtp->dt_errno)
+ dt_dprintf("error parsing library %s: %s\n",
+ fname, dtrace_errmsg(dtp, dtrace_errno(dtp)));
+
+ (void) fclose(fp);
+ dtp->dt_filetag = NULL;
+ }
+
+ (void) closedir(dirp);
+
+ return (0);
+}
+
+/*
+ * Perform a topological sorting of all the libraries found across the entire
+ * dt_lib_path. Once sorted, compile each one in topological order to cache its
+ * inlines and translators, etc. We silently ignore any missing directories and
+ * other files found therein. We only fail (and thereby fail dt_load_libs()) if
+ * we fail to compile a library and the error is something other than #pragma D
+ * depends_on. Dependency errors are silently ignored to permit a library
+ * directory to contain libraries which may not be accessible depending on our
+ * privileges.
+ */
+static int
+dt_load_libs_sort(dtrace_hdl_t *dtp)
+{
+ dtrace_prog_t *pgp;
+ FILE *fp;
+ dt_lib_depend_t *dld;
+
+ /*
+ * Finish building the graph containing the library dependencies
+ * and perform a topological sort to generate an ordered list
+ * for compilation.
+ */
+ if (dt_lib_depend_sort(dtp) == -1)
+ goto err;
+
+ for (dld = dt_list_next(&dtp->dt_lib_dep_sorted); dld != NULL;
+ dld = dt_list_next(dld)) {
+
+ if ((fp = fopen(dld->dtld_library, "r")) == NULL) {
+ dt_dprintf("skipping library %s: %s\n",
+ dld->dtld_library, strerror(errno));
+ continue;
+ }
+
+ dtp->dt_filetag = dld->dtld_library;
+ pgp = dtrace_program_fcompile(dtp, fp, DTRACE_C_EMPTY, 0, NULL);
+ (void) fclose(fp);
+ dtp->dt_filetag = NULL;
+
+ if (pgp == NULL && (dtp->dt_errno != EDT_COMPILER ||
+ dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND)))
+ goto err;
+
+ if (pgp == NULL) {
+ dt_dprintf("skipping library %s: %s\n",
+ dld->dtld_library,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ } else {
+ dld->dtld_loaded = B_TRUE;
+ dt_program_destroy(dtp, pgp);
+ }
+ }
+
+ dt_lib_depend_free(dtp);
+ return (0);
+
+err:
+ dt_lib_depend_free(dtp);
+ return (-1); /* preserve dt_errno */
+}
+
+/*
+ * Load the contents of any appropriate DTrace .d library files. These files
+ * contain inlines and translators that will be cached by the compiler. We
+ * defer this activity until the first compile to permit libdtrace clients to
+ * add their own library directories and so that we can properly report errors.
+ */
+static int
+dt_load_libs(dtrace_hdl_t *dtp)
+{
+ dt_dirpath_t *dirp;
+
+ if (dtp->dt_cflags & DTRACE_C_NOLIBS)
+ return (0); /* libraries already processed */
+
+ dtp->dt_cflags |= DTRACE_C_NOLIBS;
+
+ /*
+ * /usr/lib/dtrace is always at the head of the list. The rest of the
+ * list is specified in the precedence order the user requested. Process
+ * everything other than the head first. DTRACE_C_NOLIBS has already
+ * been spcified so dt_vopen will ensure that there is always one entry
+ * in dt_lib_path.
+ */
+ for (dirp = dt_list_next(dt_list_next(&dtp->dt_lib_path));
+ dirp != NULL; dirp = dt_list_next(dirp)) {
+ if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) {
+ dtp->dt_cflags &= ~DTRACE_C_NOLIBS;
+ return (-1); /* errno is set for us */
+ }
+ }
+
+ /* Handle /usr/lib/dtrace */
+ dirp = dt_list_next(&dtp->dt_lib_path);
+ if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) {
+ dtp->dt_cflags &= ~DTRACE_C_NOLIBS;
+ return (-1); /* errno is set for us */
+ }
+
+ if (dt_load_libs_sort(dtp) < 0)
+ return (-1); /* errno is set for us */
+
+ return (0);
+}
+
+static void *
+dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg,
+ uint_t cflags, int argc, char *const argv[], FILE *fp, const char *s)
+{
+ dt_node_t *dnp;
+ dt_decl_t *ddp;
+ dt_pcb_t pcb;
+ void *volatile rv;
+ int err;
+
+ if ((fp == NULL && s == NULL) || (cflags & ~DTRACE_C_MASK) != 0) {
+ (void) dt_set_errno(dtp, EINVAL);
+ return (NULL);
+ }
+
+ if (dt_list_next(&dtp->dt_lib_path) != NULL && dt_load_libs(dtp) != 0)
+ return (NULL); /* errno is set for us */
+
+ if (dtp->dt_globals->dh_nelems != 0)
+ (void) dt_idhash_iter(dtp->dt_globals, dt_idreset, NULL);
+
+ if (dtp->dt_tls->dh_nelems != 0)
+ (void) dt_idhash_iter(dtp->dt_tls, dt_idreset, NULL);
+
+ if (fp && (cflags & DTRACE_C_CPP) && (fp = dt_preproc(dtp, fp)) == NULL)
+ return (NULL); /* errno is set for us */
+
+ dt_pcb_push(dtp, &pcb);
+
+ pcb.pcb_fileptr = fp;
+ pcb.pcb_string = s;
+ pcb.pcb_strptr = s;
+ pcb.pcb_strlen = s ? strlen(s) : 0;
+ pcb.pcb_sargc = argc;
+ pcb.pcb_sargv = argv;
+ pcb.pcb_sflagv = argc ? calloc(argc, sizeof (ushort_t)) : NULL;
+ pcb.pcb_pspec = pspec;
+ pcb.pcb_cflags = dtp->dt_cflags | cflags;
+ pcb.pcb_amin = dtp->dt_amin;
+ pcb.pcb_yystate = -1;
+ pcb.pcb_context = context;
+ pcb.pcb_token = context;
+
+ if (context != DT_CTX_DPROG)
+ yybegin(YYS_EXPR);
+ else if (cflags & DTRACE_C_CTL)
+ yybegin(YYS_CONTROL);
+ else
+ yybegin(YYS_CLAUSE);
+
+ if ((err = setjmp(yypcb->pcb_jmpbuf)) != 0)
+ goto out;
+
+ if (yypcb->pcb_sargc != 0 && yypcb->pcb_sflagv == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ yypcb->pcb_idents = dt_idhash_create("ambiguous", NULL, 0, 0);
+ yypcb->pcb_locals = dt_idhash_create("clause local", NULL,
+ DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX);
+
+ if (yypcb->pcb_idents == NULL || yypcb->pcb_locals == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ /*
+ * Invoke the parser to evaluate the D source code. If any errors
+ * occur during parsing, an error function will be called and we
+ * will longjmp back to pcb_jmpbuf to abort. If parsing succeeds,
+ * we optionally display the parse tree if debugging is enabled.
+ */
+ if (yyparse() != 0 || yypcb->pcb_root == NULL)
+ xyerror(D_EMPTY, "empty D program translation unit\n");
+
+ yybegin(YYS_DONE);
+
+ if (cflags & DTRACE_C_CTL)
+ goto out;
+
+ if (context != DT_CTX_DTYPE && DT_TREEDUMP_PASS(dtp, 1))
+ dt_node_printr(yypcb->pcb_root, stderr, 0);
+
+ if (yypcb->pcb_pragmas != NULL)
+ (void) dt_idhash_iter(yypcb->pcb_pragmas, dt_idpragma, NULL);
+
+ if (argc > 1 && !(yypcb->pcb_cflags & DTRACE_C_ARGREF) &&
+ !(yypcb->pcb_sflagv[argc - 1] & DT_IDFLG_REF)) {
+ xyerror(D_MACRO_UNUSED, "extraneous argument '%s' ($%d is "
+ "not referenced)\n", yypcb->pcb_sargv[argc - 1], argc - 1);
+ }
+
+ /*
+ * Perform sugar transformations (for "if" / "else") and replace the
+ * existing clause chain with the new one.
+ */
+ if (context == DT_CTX_DPROG) {
+ dt_node_t *dnp, *next_dnp;
+ dt_node_t *new_list = NULL;
+
+ for (dnp = yypcb->pcb_root->dn_list;
+ dnp != NULL; dnp = next_dnp) {
+ /* remove this node from the list */
+ next_dnp = dnp->dn_list;
+ dnp->dn_list = NULL;
+
+ if (dnp->dn_kind == DT_NODE_CLAUSE)
+ dnp = dt_compile_sugar(dtp, dnp);
+ /* append node to the new list */
+ new_list = dt_node_link(new_list, dnp);
+ }
+ yypcb->pcb_root->dn_list = new_list;
+ }
+
+ /*
+ * If we have successfully created a parse tree for a D program, loop
+ * over the clauses and actions and instantiate the corresponding
+ * libdtrace program. If we are parsing a D expression, then we
+ * simply run the code generator and assembler on the resulting tree.
+ */
+ switch (context) {
+ case DT_CTX_DPROG:
+ assert(yypcb->pcb_root->dn_kind == DT_NODE_PROG);
+
+ if ((dnp = yypcb->pcb_root->dn_list) == NULL &&
+ !(yypcb->pcb_cflags & DTRACE_C_EMPTY))
+ xyerror(D_EMPTY, "empty D program translation unit\n");
+
+ if ((yypcb->pcb_prog = dt_program_create(dtp)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, dtrace_errno(dtp));
+
+ for (; dnp != NULL; dnp = dnp->dn_list) {
+ switch (dnp->dn_kind) {
+ case DT_NODE_CLAUSE:
+ if (DT_TREEDUMP_PASS(dtp, 4))
+ dt_printd(dnp, stderr, 0);
+ dt_compile_clause(dtp, dnp);
+ break;
+ case DT_NODE_XLATOR:
+ if (dtp->dt_xlatemode == DT_XL_DYNAMIC)
+ dt_compile_xlator(dnp);
+ break;
+ case DT_NODE_PROVIDER:
+ (void) dt_node_cook(dnp, DT_IDFLG_REF);
+ break;
+ }
+ }
+
+ yypcb->pcb_prog->dp_xrefs = yypcb->pcb_asxrefs;
+ yypcb->pcb_prog->dp_xrefslen = yypcb->pcb_asxreflen;
+ yypcb->pcb_asxrefs = NULL;
+ yypcb->pcb_asxreflen = 0;
+
+ rv = yypcb->pcb_prog;
+ break;
+
+ case DT_CTX_DEXPR:
+ (void) dt_node_cook(yypcb->pcb_root, DT_IDFLG_REF);
+ dt_cg(yypcb, yypcb->pcb_root);
+ rv = dt_as(yypcb);
+ break;
+
+ case DT_CTX_DTYPE:
+ ddp = (dt_decl_t *)yypcb->pcb_root; /* root is really a decl */
+ err = dt_decl_type(ddp, arg);
+ dt_decl_free(ddp);
+
+ if (err != 0)
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+
+ rv = NULL;
+ break;
+ }
+
+out:
+ if (context != DT_CTX_DTYPE && yypcb->pcb_root != NULL &&
+ DT_TREEDUMP_PASS(dtp, 3))
+ dt_node_printr(yypcb->pcb_root, stderr, 0);
+
+ if (dtp->dt_cdefs_fd != -1 && (ftruncate64(dtp->dt_cdefs_fd, 0) == -1 ||
+ lseek64(dtp->dt_cdefs_fd, 0, SEEK_SET) == -1 ||
+ ctf_write(dtp->dt_cdefs->dm_ctfp, dtp->dt_cdefs_fd) == CTF_ERR))
+ dt_dprintf("failed to update CTF cache: %s\n", strerror(errno));
+
+ if (dtp->dt_ddefs_fd != -1 && (ftruncate64(dtp->dt_ddefs_fd, 0) == -1 ||
+ lseek64(dtp->dt_ddefs_fd, 0, SEEK_SET) == -1 ||
+ ctf_write(dtp->dt_ddefs->dm_ctfp, dtp->dt_ddefs_fd) == CTF_ERR))
+ dt_dprintf("failed to update CTF cache: %s\n", strerror(errno));
+
+ if (yypcb->pcb_fileptr && (cflags & DTRACE_C_CPP))
+ (void) fclose(yypcb->pcb_fileptr); /* close dt_preproc() file */
+
+ dt_pcb_pop(dtp, err);
+ (void) dt_set_errno(dtp, err);
+ return (err ? NULL : rv);
+}
+
+dtrace_prog_t *
+dtrace_program_strcompile(dtrace_hdl_t *dtp, const char *s,
+ dtrace_probespec_t spec, uint_t cflags, int argc, char *const argv[])
+{
+ return (dt_compile(dtp, DT_CTX_DPROG,
+ spec, NULL, cflags, argc, argv, NULL, s));
+}
+
+dtrace_prog_t *
+dtrace_program_fcompile(dtrace_hdl_t *dtp, FILE *fp,
+ uint_t cflags, int argc, char *const argv[])
+{
+ return (dt_compile(dtp, DT_CTX_DPROG,
+ DTRACE_PROBESPEC_NAME, NULL, cflags, argc, argv, fp, NULL));
+}
+
+int
+dtrace_type_strcompile(dtrace_hdl_t *dtp, const char *s, dtrace_typeinfo_t *dtt)
+{
+ (void) dt_compile(dtp, DT_CTX_DTYPE,
+ DTRACE_PROBESPEC_NONE, dtt, 0, 0, NULL, NULL, s);
+ return (dtp->dt_errno ? -1 : 0);
+}
+
+int
+dtrace_type_fcompile(dtrace_hdl_t *dtp, FILE *fp, dtrace_typeinfo_t *dtt)
+{
+ (void) dt_compile(dtp, DT_CTX_DTYPE,
+ DTRACE_PROBESPEC_NONE, dtt, 0, 0, NULL, fp, NULL);
+ return (dtp->dt_errno ? -1 : 0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c
new file mode 100644
index 000000000000..e4580a8ab340
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c
@@ -0,0 +1,2140 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/isa_defs.h>
+
+#include <strings.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <dt_impl.h>
+#include <dt_grammar.h>
+#include <dt_parser.h>
+#include <dt_provider.h>
+
+static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *);
+
+static dt_irnode_t *
+dt_cg_node_alloc(uint_t label, dif_instr_t instr)
+{
+ dt_irnode_t *dip = malloc(sizeof (dt_irnode_t));
+
+ if (dip == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dip->di_label = label;
+ dip->di_instr = instr;
+ dip->di_extern = NULL;
+ dip->di_next = NULL;
+
+ return (dip);
+}
+
+/*
+ * Code generator wrapper function for ctf_member_info. If we are given a
+ * reference to a forward declaration tag, search the entire type space for
+ * the actual definition and then call ctf_member_info on the result.
+ */
+static ctf_file_t *
+dt_cg_membinfo(ctf_file_t *fp, ctf_id_t type, const char *s, ctf_membinfo_t *mp)
+{
+ while (ctf_type_kind(fp, type) == CTF_K_FORWARD) {
+ char n[DT_TYPE_NAMELEN];
+ dtrace_typeinfo_t dtt;
+
+ if (ctf_type_name(fp, type, n, sizeof (n)) == NULL ||
+ dt_type_lookup(n, &dtt) == -1 || (
+ dtt.dtt_ctfp == fp && dtt.dtt_type == type))
+ break; /* unable to improve our position */
+
+ fp = dtt.dtt_ctfp;
+ type = ctf_type_resolve(fp, dtt.dtt_type);
+ }
+
+ if (ctf_member_info(fp, type, s, mp) == CTF_ERR)
+ return (NULL); /* ctf_errno is set for us */
+
+ return (fp);
+}
+
+static void
+dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x)
+{
+ int flag = idp != NULL ? DT_INT_PRIVATE : DT_INT_SHARED;
+ int intoff = dt_inttab_insert(yypcb->pcb_inttab, x, flag);
+ dif_instr_t instr = DIF_INSTR_SETX((uint_t)intoff, reg);
+
+ if (intoff == -1)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ if (intoff > DIF_INTOFF_MAX)
+ longjmp(yypcb->pcb_jmpbuf, EDT_INT2BIG);
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl, instr));
+
+ if (idp != NULL)
+ dlp->dl_last->di_extern = idp;
+}
+
+static void
+dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x)
+{
+ dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x);
+}
+
+/*
+ * When loading bit-fields, we want to convert a byte count in the range
+ * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function
+ * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.
+ */
+static size_t
+clp2(size_t x)
+{
+ x--;
+
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+
+ return (x + 1);
+}
+
+/*
+ * Lookup the correct load opcode to use for the specified node and CTF type.
+ * We determine the size and convert it to a 3-bit index. Our lookup table
+ * is constructed to use a 5-bit index, consisting of the 3-bit size 0-7, a
+ * bit for the sign, and a bit for userland address. For example, a 4-byte
+ * signed load from userland would be at the following table index:
+ * user=1 sign=1 size=4 => binary index 11011 = decimal index 27
+ */
+static uint_t
+dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)
+{
+ static const uint_t ops[] = {
+ DIF_OP_LDUB, DIF_OP_LDUH, 0, DIF_OP_LDUW,
+ 0, 0, 0, DIF_OP_LDX,
+ DIF_OP_LDSB, DIF_OP_LDSH, 0, DIF_OP_LDSW,
+ 0, 0, 0, DIF_OP_LDX,
+ DIF_OP_ULDUB, DIF_OP_ULDUH, 0, DIF_OP_ULDUW,
+ 0, 0, 0, DIF_OP_ULDX,
+ DIF_OP_ULDSB, DIF_OP_ULDSH, 0, DIF_OP_ULDSW,
+ 0, 0, 0, DIF_OP_ULDX,
+ };
+
+ ctf_encoding_t e;
+ ssize_t size;
+
+ /*
+ * If we're loading a bit-field, the size of our load is found by
+ * rounding cte_bits up to a byte boundary and then finding the
+ * nearest power of two to this value (see clp2(), above).
+ */
+ if ((dnp->dn_flags & DT_NF_BITFIELD) &&
+ ctf_type_encoding(ctfp, type, &e) != CTF_ERR)
+ size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);
+ else
+ size = ctf_type_size(ctfp, type);
+
+ if (size < 1 || size > 8 || (size & (size - 1)) != 0) {
+ xyerror(D_UNKNOWN, "internal error -- cg cannot load "
+ "size %ld when passed by value\n", (long)size);
+ }
+
+ size--; /* convert size to 3-bit index */
+
+ if (dnp->dn_flags & DT_NF_SIGNED)
+ size |= 0x08;
+ if (dnp->dn_flags & DT_NF_USERLAND)
+ size |= 0x10;
+
+ return (ops[size]);
+}
+
+static void
+dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
+ uint_t op, int dreg)
+{
+ ctf_file_t *ctfp = dnp->dn_ctfp;
+ ctf_arinfo_t r;
+ dif_instr_t instr;
+ ctf_id_t type;
+ uint_t kind;
+ ssize_t size;
+ int sreg;
+
+ type = ctf_type_resolve(ctfp, dnp->dn_type);
+ kind = ctf_type_kind(ctfp, type);
+ assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY);
+
+ if (kind == CTF_K_ARRAY) {
+ if (ctf_array_info(ctfp, type, &r) != 0) {
+ yypcb->pcb_hdl->dt_ctferr = ctf_errno(ctfp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
+ }
+ type = r.ctr_contents;
+ } else
+ type = ctf_type_reference(ctfp, type);
+
+ if ((size = ctf_type_size(ctfp, type)) == 1)
+ return; /* multiply or divide by one can be omitted */
+
+ sreg = dt_regset_alloc(drp);
+ dt_cg_setx(dlp, sreg, size);
+ instr = DIF_INSTR_FMT(op, dreg, sreg, dreg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, sreg);
+}
+
+/*
+ * If the result of a "." or "->" operation is a bit-field, we use this routine
+ * to generate an epilogue to the load instruction that extracts the value. In
+ * the diagrams below the "ld??" is the load instruction that is generated to
+ * load the containing word that is generating prior to calling this function.
+ *
+ * Epilogue for unsigned fields: Epilogue for signed fields:
+ *
+ * ldu? [r1], r1 lds? [r1], r1
+ * setx USHIFT, r2 setx 64 - SSHIFT, r2
+ * srl r1, r2, r1 sll r1, r2, r1
+ * setx (1 << bits) - 1, r2 setx 64 - bits, r2
+ * and r1, r2, r1 sra r1, r2, r1
+ *
+ * The *SHIFT constants above changes value depending on the endian-ness of our
+ * target architecture. Refer to the comments below for more details.
+ */
+static void
+dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
+ ctf_file_t *fp, const ctf_membinfo_t *mp)
+{
+ ctf_encoding_t e;
+ dif_instr_t instr;
+ uint64_t shift;
+ int r1, r2;
+
+ if (ctf_type_encoding(fp, mp->ctm_type, &e) != 0 || e.cte_bits > 64) {
+ xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "
+ "bits %u\n", mp->ctm_offset, mp->ctm_type, e.cte_bits);
+ }
+
+ assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT);
+ r1 = dnp->dn_left->dn_reg;
+ r2 = dt_regset_alloc(drp);
+
+ /*
+ * On little-endian architectures, ctm_offset counts from the right so
+ * ctm_offset % NBBY itself is the amount we want to shift right to
+ * move the value bits to the little end of the register to mask them.
+ * On big-endian architectures, ctm_offset counts from the left so we
+ * must subtract (ctm_offset % NBBY + cte_bits) from the size in bits
+ * we used for the load. The size of our load in turn is found by
+ * rounding cte_bits up to a byte boundary and then finding the
+ * nearest power of two to this value (see clp2(), above). These
+ * properties are used to compute shift as USHIFT or SSHIFT, below.
+ */
+ if (dnp->dn_flags & DT_NF_SIGNED) {
+#if BYTE_ORDER == _BIG_ENDIAN
+ shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
+ mp->ctm_offset % NBBY;
+#else
+ shift = mp->ctm_offset % NBBY + e.cte_bits;
+#endif
+ dt_cg_setx(dlp, r2, 64 - shift);
+ instr = DIF_INSTR_FMT(DIF_OP_SLL, r1, r2, r1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_setx(dlp, r2, 64 - e.cte_bits);
+ instr = DIF_INSTR_FMT(DIF_OP_SRA, r1, r2, r1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ } else {
+#if BYTE_ORDER == _BIG_ENDIAN
+ shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
+ (mp->ctm_offset % NBBY + e.cte_bits);
+#else
+ shift = mp->ctm_offset % NBBY;
+#endif
+ dt_cg_setx(dlp, r2, shift);
+ instr = DIF_INSTR_FMT(DIF_OP_SRL, r1, r2, r1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_setx(dlp, r2, (1ULL << e.cte_bits) - 1);
+ instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ }
+
+ dt_regset_free(drp, r2);
+}
+
+/*
+ * If the destination of a store operation is a bit-field, we use this routine
+ * to generate a prologue to the store instruction that loads the surrounding
+ * bits, clears the destination field, and ORs in the new value of the field.
+ * In the diagram below the "st?" is the store instruction that is generated to
+ * store the containing word that is generating after calling this function.
+ *
+ * ld [dst->dn_reg], r1
+ * setx ~(((1 << cte_bits) - 1) << (ctm_offset % NBBY)), r2
+ * and r1, r2, r1
+ *
+ * setx (1 << cte_bits) - 1, r2
+ * and src->dn_reg, r2, r2
+ * setx ctm_offset % NBBY, r3
+ * sll r2, r3, r2
+ *
+ * or r1, r2, r1
+ * st? r1, [dst->dn_reg]
+ *
+ * This routine allocates a new register to hold the value to be stored and
+ * returns it. The caller is responsible for freeing this register later.
+ */
+static int
+dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp,
+ dt_regset_t *drp, dt_node_t *dst)
+{
+ uint64_t cmask, fmask, shift;
+ dif_instr_t instr;
+ int r1, r2, r3;
+
+ ctf_membinfo_t m;
+ ctf_encoding_t e;
+ ctf_file_t *fp, *ofp;
+ ctf_id_t type;
+
+ assert(dst->dn_op == DT_TOK_PTR || dst->dn_op == DT_TOK_DOT);
+ assert(dst->dn_right->dn_kind == DT_NODE_IDENT);
+
+ fp = dst->dn_left->dn_ctfp;
+ type = ctf_type_resolve(fp, dst->dn_left->dn_type);
+
+ if (dst->dn_op == DT_TOK_PTR) {
+ type = ctf_type_reference(fp, type);
+ type = ctf_type_resolve(fp, type);
+ }
+
+ if ((fp = dt_cg_membinfo(ofp = fp, type,
+ dst->dn_right->dn_string, &m)) == NULL) {
+ yypcb->pcb_hdl->dt_ctferr = ctf_errno(ofp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
+ }
+
+ if (ctf_type_encoding(fp, m.ctm_type, &e) != 0 || e.cte_bits > 64) {
+ xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> "
+ "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits);
+ }
+
+ r1 = dt_regset_alloc(drp);
+ r2 = dt_regset_alloc(drp);
+ r3 = dt_regset_alloc(drp);
+
+ /*
+ * Compute shifts and masks. We need to compute "shift" as the amount
+ * we need to shift left to position our field in the containing word.
+ * Refer to the comments in dt_cg_field_get(), above, for more info.
+ * We then compute fmask as the mask that truncates the value in the
+ * input register to width cte_bits, and cmask as the mask used to
+ * pass through the containing bits and zero the field bits.
+ */
+#if BYTE_ORDER == _BIG_ENDIAN
+ shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY -
+ (m.ctm_offset % NBBY + e.cte_bits);
+#else
+ shift = m.ctm_offset % NBBY;
+#endif
+ fmask = (1ULL << e.cte_bits) - 1;
+ cmask = ~(fmask << shift);
+
+ instr = DIF_INSTR_LOAD(
+ dt_cg_load(dst, fp, m.ctm_type), dst->dn_reg, r1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_setx(dlp, r2, cmask);
+ instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_setx(dlp, r2, fmask);
+ instr = DIF_INSTR_FMT(DIF_OP_AND, src->dn_reg, r2, r2);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_setx(dlp, r3, shift);
+ instr = DIF_INSTR_FMT(DIF_OP_SLL, r2, r3, r2);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_FMT(DIF_OP_OR, r1, r2, r1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_regset_free(drp, r3);
+ dt_regset_free(drp, r2);
+
+ return (r1);
+}
+
+static void
+dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
+{
+ ctf_encoding_t e;
+ dif_instr_t instr;
+ size_t size;
+ int reg;
+
+ /*
+ * If we're loading a bit-field, the size of our store is found by
+ * rounding dst's cte_bits up to a byte boundary and then finding the
+ * nearest power of two to this value (see clp2(), above).
+ */
+ if ((dst->dn_flags & DT_NF_BITFIELD) &&
+ ctf_type_encoding(dst->dn_ctfp, dst->dn_type, &e) != CTF_ERR)
+ size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);
+ else
+ size = dt_node_type_size(src);
+
+ if (src->dn_flags & DT_NF_REF) {
+ reg = dt_regset_alloc(drp);
+ dt_cg_setx(dlp, reg, size);
+ instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, reg);
+ } else {
+ if (dst->dn_flags & DT_NF_BITFIELD)
+ reg = dt_cg_field_set(src, dlp, drp, dst);
+ else
+ reg = src->dn_reg;
+
+ switch (size) {
+ case 1:
+ instr = DIF_INSTR_STORE(DIF_OP_STB, reg, dst->dn_reg);
+ break;
+ case 2:
+ instr = DIF_INSTR_STORE(DIF_OP_STH, reg, dst->dn_reg);
+ break;
+ case 4:
+ instr = DIF_INSTR_STORE(DIF_OP_STW, reg, dst->dn_reg);
+ break;
+ case 8:
+ instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg);
+ break;
+ default:
+ xyerror(D_UNKNOWN, "internal error -- cg cannot store "
+ "size %lu when passed by value\n", (ulong_t)size);
+ }
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ if (dst->dn_flags & DT_NF_BITFIELD)
+ dt_regset_free(drp, reg);
+ }
+}
+
+/*
+ * Generate code for a typecast or for argument promotion from the type of the
+ * actual to the type of the formal. We need to generate code for casts when
+ * a scalar type is being narrowed or changing signed-ness. We first shift the
+ * desired bits high (losing excess bits if narrowing) and then shift them down
+ * using logical shift (unsigned result) or arithmetic shift (signed result).
+ */
+static void
+dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
+ dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ size_t srcsize = dt_node_type_size(src);
+ size_t dstsize = dt_node_type_size(dst);
+
+ dif_instr_t instr;
+ int rg;
+
+ if (!dt_node_is_scalar(dst))
+ return; /* not a scalar */
+ if (dstsize == srcsize &&
+ ((src->dn_flags ^ dst->dn_flags) & DT_NF_SIGNED) != 0)
+ return; /* not narrowing or changing signed-ness */
+ if (dstsize > srcsize && (src->dn_flags & DT_NF_SIGNED) == 0)
+ return; /* nothing to do in this case */
+
+ rg = dt_regset_alloc(drp);
+
+ if (dstsize > srcsize) {
+ int n = sizeof (uint64_t) * NBBY - srcsize * NBBY;
+ int s = (dstsize - srcsize) * NBBY;
+
+ dt_cg_setx(dlp, rg, n);
+
+ instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ if ((dst->dn_flags & DT_NF_SIGNED) || n == s) {
+ instr = DIF_INSTR_FMT(DIF_OP_SRA,
+ dst->dn_reg, rg, dst->dn_reg);
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+ } else {
+ dt_cg_setx(dlp, rg, s);
+ instr = DIF_INSTR_FMT(DIF_OP_SRA,
+ dst->dn_reg, rg, dst->dn_reg);
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_cg_setx(dlp, rg, n - s);
+ instr = DIF_INSTR_FMT(DIF_OP_SRL,
+ dst->dn_reg, rg, dst->dn_reg);
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+ }
+ } else if (dstsize != sizeof (uint64_t)) {
+ int n = sizeof (uint64_t) * NBBY - dstsize * NBBY;
+
+ dt_cg_setx(dlp, rg, n);
+
+ instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ?
+ DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, rg, dst->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ }
+
+ dt_regset_free(drp, rg);
+}
+
+/*
+ * Generate code to push the specified argument list on to the tuple stack.
+ * We use this routine for handling subroutine calls and associative arrays.
+ * We must first generate code for all subexpressions before loading the stack
+ * because any subexpression could itself require the use of the tuple stack.
+ * This holds a number of registers equal to the number of arguments, but this
+ * is not a huge problem because the number of arguments can't exceed the
+ * number of tuple register stack elements anyway. At most one extra register
+ * is required (either by dt_cg_typecast() or for dtdt_size, below). This
+ * implies that a DIF implementation should offer a number of general purpose
+ * registers at least one greater than the number of tuple registers.
+ */
+static void
+dt_cg_arglist(dt_ident_t *idp, dt_node_t *args,
+ dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ const dt_idsig_t *isp = idp->di_data;
+ dt_node_t *dnp;
+ int i = 0;
+
+ for (dnp = args; dnp != NULL; dnp = dnp->dn_list)
+ dt_cg_node(dnp, dlp, drp);
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
+
+ for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) {
+ dtrace_diftype_t t;
+ dif_instr_t instr;
+ uint_t op;
+ int reg;
+
+ dt_node_diftype(yypcb->pcb_hdl, dnp, &t);
+
+ isp->dis_args[i].dn_reg = dnp->dn_reg; /* re-use register */
+ dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp);
+ isp->dis_args[i].dn_reg = -1;
+
+ if (t.dtdt_flags & DIF_TF_BYREF) {
+ op = DIF_OP_PUSHTR;
+ if (t.dtdt_size != 0) {
+ reg = dt_regset_alloc(drp);
+ dt_cg_setx(dlp, reg, t.dtdt_size);
+ } else {
+ reg = DIF_REG_R0;
+ }
+ } else {
+ op = DIF_OP_PUSHTV;
+ reg = DIF_REG_R0;
+ }
+
+ instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, dnp->dn_reg);
+
+ if (reg != DIF_REG_R0)
+ dt_regset_free(drp, reg);
+ }
+
+ if (i > yypcb->pcb_hdl->dt_conf.dtc_diftupregs)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG);
+}
+
+static void
+dt_cg_arithmetic_op(dt_node_t *dnp, dt_irlist_t *dlp,
+ dt_regset_t *drp, uint_t op)
+{
+ int is_ptr_op = (dnp->dn_op == DT_TOK_ADD || dnp->dn_op == DT_TOK_SUB ||
+ dnp->dn_op == DT_TOK_ADD_EQ || dnp->dn_op == DT_TOK_SUB_EQ);
+
+ int lp_is_ptr = dt_node_is_pointer(dnp->dn_left);
+ int rp_is_ptr = dt_node_is_pointer(dnp->dn_right);
+
+ dif_instr_t instr;
+
+ if (lp_is_ptr && rp_is_ptr) {
+ assert(dnp->dn_op == DT_TOK_SUB);
+ is_ptr_op = 0;
+ }
+
+ dt_cg_node(dnp->dn_left, dlp, drp);
+ if (is_ptr_op && rp_is_ptr)
+ dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_left->dn_reg);
+
+ dt_cg_node(dnp->dn_right, dlp, drp);
+ if (is_ptr_op && lp_is_ptr)
+ dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_right->dn_reg);
+
+ instr = DIF_INSTR_FMT(op, dnp->dn_left->dn_reg,
+ dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, dnp->dn_right->dn_reg);
+ dnp->dn_reg = dnp->dn_left->dn_reg;
+
+ if (lp_is_ptr && rp_is_ptr)
+ dt_cg_ptrsize(dnp->dn_right,
+ dlp, drp, DIF_OP_UDIV, dnp->dn_reg);
+}
+
+static uint_t
+dt_cg_stvar(const dt_ident_t *idp)
+{
+ static const uint_t aops[] = { DIF_OP_STGAA, DIF_OP_STTAA, DIF_OP_NOP };
+ static const uint_t sops[] = { DIF_OP_STGS, DIF_OP_STTS, DIF_OP_STLS };
+
+ uint_t i = (((idp->di_flags & DT_IDFLG_LOCAL) != 0) << 1) |
+ ((idp->di_flags & DT_IDFLG_TLS) != 0);
+
+ return (idp->di_kind == DT_IDENT_ARRAY ? aops[i] : sops[i]);
+}
+
+static void
+dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
+{
+ ctf_file_t *ctfp = dnp->dn_ctfp;
+ dif_instr_t instr;
+ ctf_id_t type;
+ ssize_t size = 1;
+ int reg;
+
+ if (dt_node_is_pointer(dnp)) {
+ type = ctf_type_resolve(ctfp, dnp->dn_type);
+ assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);
+ size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));
+ }
+
+ dt_cg_node(dnp->dn_child, dlp, drp);
+ dnp->dn_reg = dnp->dn_child->dn_reg;
+
+ reg = dt_regset_alloc(drp);
+ dt_cg_setx(dlp, reg, size);
+
+ instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, reg);
+
+ /*
+ * If we are modifying a variable, generate an stv instruction from
+ * the variable specified by the identifier. If we are storing to a
+ * memory address, generate code again for the left-hand side using
+ * DT_NF_REF to get the address, and then generate a store to it.
+ * In both paths, we store the value in dnp->dn_reg (the new value).
+ */
+ if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
+ dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
+
+ idp->di_flags |= DT_IDFLG_DIFW;
+ instr = DIF_INSTR_STV(dt_cg_stvar(idp),
+ idp->di_id, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ } else {
+ uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
+
+ assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
+ assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
+
+ dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
+ dt_cg_node(dnp->dn_child, dlp, drp);
+
+ dt_cg_store(dnp, dlp, drp, dnp->dn_child);
+ dt_regset_free(drp, dnp->dn_child->dn_reg);
+
+ dnp->dn_left->dn_flags &= ~DT_NF_REF;
+ dnp->dn_left->dn_flags |= rbit;
+ }
+}
+
+static void
+dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,
+ dt_regset_t *drp, uint_t op)
+{
+ ctf_file_t *ctfp = dnp->dn_ctfp;
+ dif_instr_t instr;
+ ctf_id_t type;
+ ssize_t size = 1;
+ int nreg;
+
+ if (dt_node_is_pointer(dnp)) {
+ type = ctf_type_resolve(ctfp, dnp->dn_type);
+ assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER);
+ size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type));
+ }
+
+ dt_cg_node(dnp->dn_child, dlp, drp);
+ dnp->dn_reg = dnp->dn_child->dn_reg;
+
+ nreg = dt_regset_alloc(drp);
+ dt_cg_setx(dlp, nreg, size);
+ instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ /*
+ * If we are modifying a variable, generate an stv instruction from
+ * the variable specified by the identifier. If we are storing to a
+ * memory address, generate code again for the left-hand side using
+ * DT_NF_REF to get the address, and then generate a store to it.
+ * In both paths, we store the value from 'nreg' (the new value).
+ */
+ if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
+ dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
+
+ idp->di_flags |= DT_IDFLG_DIFW;
+ instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, nreg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ } else {
+ uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
+ int oreg = dnp->dn_reg;
+
+ assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
+ assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
+
+ dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
+ dt_cg_node(dnp->dn_child, dlp, drp);
+
+ dnp->dn_reg = nreg;
+ dt_cg_store(dnp, dlp, drp, dnp->dn_child);
+ dnp->dn_reg = oreg;
+
+ dt_regset_free(drp, dnp->dn_child->dn_reg);
+ dnp->dn_left->dn_flags &= ~DT_NF_REF;
+ dnp->dn_left->dn_flags |= rbit;
+ }
+
+ dt_regset_free(drp, nreg);
+}
+
+/*
+ * Determine if we should perform signed or unsigned comparison for an OP2.
+ * If both operands are of arithmetic type, perform the usual arithmetic
+ * conversions to determine the common real type for comparison [ISOC 6.5.8.3].
+ */
+static int
+dt_cg_compare_signed(dt_node_t *dnp)
+{
+ dt_node_t dn;
+
+ if (dt_node_is_string(dnp->dn_left) ||
+ dt_node_is_string(dnp->dn_right))
+ return (1); /* strings always compare signed */
+ else if (!dt_node_is_arith(dnp->dn_left) ||
+ !dt_node_is_arith(dnp->dn_right))
+ return (0); /* non-arithmetic types always compare unsigned */
+
+ bzero(&dn, sizeof (dn));
+ dt_node_promote(dnp->dn_left, dnp->dn_right, &dn);
+ return (dn.dn_flags & DT_NF_SIGNED);
+}
+
+static void
+dt_cg_compare_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
+{
+ uint_t lbl_true = dt_irlist_label(dlp);
+ uint_t lbl_post = dt_irlist_label(dlp);
+
+ dif_instr_t instr;
+ uint_t opc;
+
+ dt_cg_node(dnp->dn_left, dlp, drp);
+ dt_cg_node(dnp->dn_right, dlp, drp);
+
+ if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right))
+ opc = DIF_OP_SCMP;
+ else
+ opc = DIF_OP_CMP;
+
+ instr = DIF_INSTR_CMP(opc, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, dnp->dn_right->dn_reg);
+ dnp->dn_reg = dnp->dn_left->dn_reg;
+
+ instr = DIF_INSTR_BRANCH(op, lbl_true);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
+}
+
+/*
+ * Code generation for the ternary op requires some trickery with the assembler
+ * in order to conserve registers. We generate code for dn_expr and dn_left
+ * and free their registers so they do not have be consumed across codegen for
+ * dn_right. We insert a dummy MOV at the end of dn_left into the destination
+ * register, which is not yet known because we haven't done dn_right yet, and
+ * save the pointer to this instruction node. We then generate code for
+ * dn_right and use its register as our output. Finally, we reach back and
+ * patch the instruction for dn_left to move its output into this register.
+ */
+static void
+dt_cg_ternary_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ uint_t lbl_false = dt_irlist_label(dlp);
+ uint_t lbl_post = dt_irlist_label(dlp);
+
+ dif_instr_t instr;
+ dt_irnode_t *dip;
+
+ dt_cg_node(dnp->dn_expr, dlp, drp);
+ instr = DIF_INSTR_TST(dnp->dn_expr->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, dnp->dn_expr->dn_reg);
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_node(dnp->dn_left, dlp, drp);
+ instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, DIF_REG_R0);
+ dip = dt_cg_node_alloc(DT_LBL_NONE, instr); /* save dip for below */
+ dt_irlist_append(dlp, dip);
+ dt_regset_free(drp, dnp->dn_left->dn_reg);
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, DIF_INSTR_NOP));
+ dt_cg_node(dnp->dn_right, dlp, drp);
+ dnp->dn_reg = dnp->dn_right->dn_reg;
+
+ /*
+ * Now that dn_reg is assigned, reach back and patch the correct MOV
+ * instruction into the tail of dn_left. We know dn_reg was unused
+ * at that point because otherwise dn_right couldn't have allocated it.
+ */
+ dip->di_instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
+}
+
+static void
+dt_cg_logical_and(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ uint_t lbl_false = dt_irlist_label(dlp);
+ uint_t lbl_post = dt_irlist_label(dlp);
+
+ dif_instr_t instr;
+
+ dt_cg_node(dnp->dn_left, dlp, drp);
+ instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, dnp->dn_left->dn_reg);
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_node(dnp->dn_right, dlp, drp);
+ instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dnp->dn_reg = dnp->dn_right->dn_reg;
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_setx(dlp, dnp->dn_reg, 1);
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
+}
+
+static void
+dt_cg_logical_xor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ uint_t lbl_next = dt_irlist_label(dlp);
+ uint_t lbl_tail = dt_irlist_label(dlp);
+
+ dif_instr_t instr;
+
+ dt_cg_node(dnp->dn_left, dlp, drp);
+ instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_next);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_cg_setx(dlp, dnp->dn_left->dn_reg, 1);
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_next, DIF_INSTR_NOP));
+ dt_cg_node(dnp->dn_right, dlp, drp);
+
+ instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_tail);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_cg_setx(dlp, dnp->dn_right->dn_reg, 1);
+
+ instr = DIF_INSTR_FMT(DIF_OP_XOR, dnp->dn_left->dn_reg,
+ dnp->dn_right->dn_reg, dnp->dn_left->dn_reg);
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_tail, instr));
+
+ dt_regset_free(drp, dnp->dn_right->dn_reg);
+ dnp->dn_reg = dnp->dn_left->dn_reg;
+}
+
+static void
+dt_cg_logical_or(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ uint_t lbl_true = dt_irlist_label(dlp);
+ uint_t lbl_false = dt_irlist_label(dlp);
+ uint_t lbl_post = dt_irlist_label(dlp);
+
+ dif_instr_t instr;
+
+ dt_cg_node(dnp->dn_left, dlp, drp);
+ instr = DIF_INSTR_TST(dnp->dn_left->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, dnp->dn_left->dn_reg);
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BNE, lbl_true);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_node(dnp->dn_right, dlp, drp);
+ instr = DIF_INSTR_TST(dnp->dn_right->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dnp->dn_reg = dnp->dn_right->dn_reg;
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1);
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr));
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
+}
+
+static void
+dt_cg_logical_neg(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ uint_t lbl_zero = dt_irlist_label(dlp);
+ uint_t lbl_post = dt_irlist_label(dlp);
+
+ dif_instr_t instr;
+
+ dt_cg_node(dnp->dn_child, dlp, drp);
+ dnp->dn_reg = dnp->dn_child->dn_reg;
+
+ instr = DIF_INSTR_TST(dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_zero);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_xsetx(dlp, NULL, lbl_zero, dnp->dn_reg, 1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));
+}
+
+static void
+dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ dif_instr_t instr;
+ dt_ident_t *idp;
+
+ /*
+ * If we are performing a structure assignment of a translated type,
+ * we must instantiate all members and create a snapshot of the object
+ * in scratch space. We allocs a chunk of memory, generate code for
+ * each member, and then set dnp->dn_reg to the scratch object address.
+ */
+ if ((idp = dt_node_resolve(dnp->dn_right, DT_IDENT_XLSOU)) != NULL) {
+ ctf_membinfo_t ctm;
+ dt_xlator_t *dxp = idp->di_data;
+ dt_node_t *mnp, dn, mn;
+ int r1, r2;
+
+ /*
+ * Create two fake dt_node_t's representing operator "." and a
+ * right-hand identifier child node. These will be repeatedly
+ * modified according to each instantiated member so that we
+ * can pass them to dt_cg_store() and effect a member store.
+ */
+ bzero(&dn, sizeof (dt_node_t));
+ dn.dn_kind = DT_NODE_OP2;
+ dn.dn_op = DT_TOK_DOT;
+ dn.dn_left = dnp;
+ dn.dn_right = &mn;
+
+ bzero(&mn, sizeof (dt_node_t));
+ mn.dn_kind = DT_NODE_IDENT;
+ mn.dn_op = DT_TOK_IDENT;
+
+ /*
+ * Allocate a register for our scratch data pointer. First we
+ * set it to the size of our data structure, and then replace
+ * it with the result of an allocs of the specified size.
+ */
+ r1 = dt_regset_alloc(drp);
+ dt_cg_setx(dlp, r1,
+ ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base));
+
+ instr = DIF_INSTR_ALLOCS(r1, r1);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ /*
+ * When dt_cg_asgn_op() is called, we have already generated
+ * code for dnp->dn_right, which is the translator input. We
+ * now associate this register with the translator's input
+ * identifier so it can be referenced during our member loop.
+ */
+ dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
+ dxp->dx_ident->di_id = dnp->dn_right->dn_reg;
+
+ for (mnp = dxp->dx_members; mnp != NULL; mnp = mnp->dn_list) {
+ /*
+ * Generate code for the translator member expression,
+ * and then cast the result to the member type.
+ */
+ dt_cg_node(mnp->dn_membexpr, dlp, drp);
+ mnp->dn_reg = mnp->dn_membexpr->dn_reg;
+ dt_cg_typecast(mnp->dn_membexpr, mnp, dlp, drp);
+
+ /*
+ * Ask CTF for the offset of the member so we can store
+ * to the appropriate offset. This call has already
+ * been done once by the parser, so it should succeed.
+ */
+ if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_base,
+ mnp->dn_membname, &ctm) == CTF_ERR) {
+ yypcb->pcb_hdl->dt_ctferr =
+ ctf_errno(dxp->dx_dst_ctfp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
+ }
+
+ /*
+ * If the destination member is at offset 0, store the
+ * result directly to r1 (the scratch buffer address).
+ * Otherwise allocate another temporary for the offset
+ * and add r1 to it before storing the result.
+ */
+ if (ctm.ctm_offset != 0) {
+ r2 = dt_regset_alloc(drp);
+
+ /*
+ * Add the member offset rounded down to the
+ * nearest byte. If the offset was not aligned
+ * on a byte boundary, this member is a bit-
+ * field and dt_cg_store() will handle masking.
+ */
+ dt_cg_setx(dlp, r2, ctm.ctm_offset / NBBY);
+ instr = DIF_INSTR_FMT(DIF_OP_ADD, r1, r2, r2);
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_node_type_propagate(mnp, &dn);
+ dn.dn_right->dn_string = mnp->dn_membname;
+ dn.dn_reg = r2;
+
+ dt_cg_store(mnp, dlp, drp, &dn);
+ dt_regset_free(drp, r2);
+
+ } else {
+ dt_node_type_propagate(mnp, &dn);
+ dn.dn_right->dn_string = mnp->dn_membname;
+ dn.dn_reg = r1;
+
+ dt_cg_store(mnp, dlp, drp, &dn);
+ }
+
+ dt_regset_free(drp, mnp->dn_reg);
+ }
+
+ dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
+ dxp->dx_ident->di_id = 0;
+
+ if (dnp->dn_right->dn_reg != -1)
+ dt_regset_free(drp, dnp->dn_right->dn_reg);
+
+ assert(dnp->dn_reg == dnp->dn_right->dn_reg);
+ dnp->dn_reg = r1;
+ }
+
+ /*
+ * If we are storing to a variable, generate an stv instruction from
+ * the variable specified by the identifier. If we are storing to a
+ * memory address, generate code again for the left-hand side using
+ * DT_NF_REF to get the address, and then generate a store to it.
+ * In both paths, we assume dnp->dn_reg already has the new value.
+ */
+ if (dnp->dn_left->dn_kind == DT_NODE_VAR) {
+ idp = dt_ident_resolve(dnp->dn_left->dn_ident);
+
+ if (idp->di_kind == DT_IDENT_ARRAY)
+ dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp);
+
+ idp->di_flags |= DT_IDFLG_DIFW;
+ instr = DIF_INSTR_STV(dt_cg_stvar(idp),
+ idp->di_id, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ } else {
+ uint_t rbit = dnp->dn_left->dn_flags & DT_NF_REF;
+
+ assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE);
+ assert(dnp->dn_left->dn_flags & DT_NF_LVALUE);
+
+ dnp->dn_left->dn_flags |= DT_NF_REF; /* force pass-by-ref */
+
+ dt_cg_node(dnp->dn_left, dlp, drp);
+ dt_cg_store(dnp, dlp, drp, dnp->dn_left);
+ dt_regset_free(drp, dnp->dn_left->dn_reg);
+
+ dnp->dn_left->dn_flags &= ~DT_NF_REF;
+ dnp->dn_left->dn_flags |= rbit;
+ }
+}
+
+static void
+dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ dif_instr_t instr;
+ uint_t op;
+
+ assert(dnp->dn_kind == DT_NODE_VAR);
+ assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL));
+ assert(dnp->dn_args != NULL);
+
+ dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
+
+ dnp->dn_reg = dt_regset_alloc(drp);
+
+ if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
+ op = DIF_OP_LDTAA;
+ else
+ op = DIF_OP_LDGAA;
+
+ dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;
+ instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ /*
+ * If the associative array is a pass-by-reference type, then we are
+ * loading its value as a pointer to either load or store through it.
+ * The array element in question may not have been faulted in yet, in
+ * which case DIF_OP_LD*AA will return zero. We append an epilogue
+ * of instructions similar to the following:
+ *
+ * ld?aa id, %r1 ! base ld?aa instruction above
+ * tst %r1 ! start of epilogue
+ * +--- bne label
+ * | setx size, %r1
+ * | allocs %r1, %r1
+ * | st?aa id, %r1
+ * | ld?aa id, %r1
+ * v
+ * label: < rest of code >
+ *
+ * The idea is that we allocs a zero-filled chunk of scratch space and
+ * do a DIF_OP_ST*AA to fault in and initialize the array element, and
+ * then reload it to get the faulted-in address of the new variable
+ * storage. This isn't cheap, but pass-by-ref associative array values
+ * are (thus far) uncommon and the allocs cost only occurs once. If
+ * this path becomes important to DTrace users, we can improve things
+ * by adding a new DIF opcode to fault in associative array elements.
+ */
+ if (dnp->dn_flags & DT_NF_REF) {
+ uint_t stvop = op == DIF_OP_LDTAA ? DIF_OP_STTAA : DIF_OP_STGAA;
+ uint_t label = dt_irlist_label(dlp);
+
+ instr = DIF_INSTR_TST(dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_BRANCH(DIF_OP_BNE, label);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_cg_setx(dlp, dnp->dn_reg, dt_node_type_size(dnp));
+ instr = DIF_INSTR_ALLOCS(dnp->dn_reg, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dnp->dn_ident->di_flags |= DT_IDFLG_DIFW;
+ instr = DIF_INSTR_STV(stvop, dnp->dn_ident->di_id, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(label, DIF_INSTR_NOP));
+ }
+}
+
+static void
+dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ dt_probe_t *prp = yypcb->pcb_probe;
+ uintmax_t saved = dnp->dn_args->dn_value;
+ dt_ident_t *idp = dnp->dn_ident;
+
+ dif_instr_t instr;
+ uint_t op;
+ size_t size;
+ int reg, n;
+
+ assert(dnp->dn_kind == DT_NODE_VAR);
+ assert(!(idp->di_flags & DT_IDFLG_LOCAL));
+
+ assert(dnp->dn_args->dn_kind == DT_NODE_INT);
+ assert(dnp->dn_args->dn_list == NULL);
+
+ /*
+ * If this is a reference in the args[] array, temporarily modify the
+ * array index according to the static argument mapping (if any),
+ * unless the argument reference is provided by a dynamic translator.
+ * If we're using a dynamic translator for args[], then just set dn_reg
+ * to an invalid reg and return: DIF_OP_XLARG will fetch the arg later.
+ */
+ if (idp->di_id == DIF_VAR_ARGS) {
+ if ((idp->di_kind == DT_IDENT_XLPTR ||
+ idp->di_kind == DT_IDENT_XLSOU) &&
+ dt_xlator_dynamic(idp->di_data)) {
+ dnp->dn_reg = -1;
+ return;
+ }
+ dnp->dn_args->dn_value = prp->pr_mapping[saved];
+ }
+
+ dt_cg_node(dnp->dn_args, dlp, drp);
+ dnp->dn_args->dn_value = saved;
+
+ dnp->dn_reg = dnp->dn_args->dn_reg;
+
+ if (idp->di_flags & DT_IDFLG_TLS)
+ op = DIF_OP_LDTA;
+ else
+ op = DIF_OP_LDGA;
+
+ idp->di_flags |= DT_IDFLG_DIFR;
+
+ instr = DIF_INSTR_LDA(op, idp->di_id,
+ dnp->dn_args->dn_reg, dnp->dn_reg);
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ /*
+ * If this is a reference to the args[] array, we need to take the
+ * additional step of explicitly eliminating any bits larger than the
+ * type size: the DIF interpreter in the kernel will always give us
+ * the raw (64-bit) argument value, and any bits larger than the type
+ * size may be junk. As a practical matter, this arises only on 64-bit
+ * architectures and only when the argument index is larger than the
+ * number of arguments passed directly to DTrace: if a 8-, 16- or
+ * 32-bit argument must be retrieved from the stack, it is possible
+ * (and it some cases, likely) that the upper bits will be garbage.
+ */
+ if (idp->di_id != DIF_VAR_ARGS || !dt_node_is_scalar(dnp))
+ return;
+
+ if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t))
+ return;
+
+ reg = dt_regset_alloc(drp);
+ assert(size < sizeof (uint64_t));
+ n = sizeof (uint64_t) * NBBY - size * NBBY;
+
+ dt_cg_setx(dlp, reg, n);
+
+ instr = DIF_INSTR_FMT(DIF_OP_SLL, dnp->dn_reg, reg, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_FMT((dnp->dn_flags & DT_NF_SIGNED) ?
+ DIF_OP_SRA : DIF_OP_SRL, dnp->dn_reg, reg, dnp->dn_reg);
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, reg);
+}
+
+/*
+ * Generate code for an inlined variable reference. Inlines can be used to
+ * define either scalar or associative array substitutions. For scalars, we
+ * simply generate code for the parse tree saved in the identifier's din_root,
+ * and then cast the resulting expression to the inline's declaration type.
+ * For arrays, we take the input parameter subtrees from dnp->dn_args and
+ * temporarily store them in the din_root of each din_argv[i] identifier,
+ * which are themselves inlines and were set up for us by the parser. The
+ * result is that any reference to the inlined parameter inside the top-level
+ * din_root will turn into a recursive call to dt_cg_inline() for a scalar
+ * inline whose din_root will refer to the subtree pointed to by the argument.
+ */
+static void
+dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ dt_ident_t *idp = dnp->dn_ident;
+ dt_idnode_t *inp = idp->di_iarg;
+
+ dt_idnode_t *pinp;
+ dt_node_t *pnp;
+ int i;
+
+ assert(idp->di_flags & DT_IDFLG_INLINE);
+ assert(idp->di_ops == &dt_idops_inline);
+
+ if (idp->di_kind == DT_IDENT_ARRAY) {
+ for (i = 0, pnp = dnp->dn_args;
+ pnp != NULL; pnp = pnp->dn_list, i++) {
+ if (inp->din_argv[i] != NULL) {
+ pinp = inp->din_argv[i]->di_iarg;
+ pinp->din_root = pnp;
+ }
+ }
+ }
+
+ dt_cg_node(inp->din_root, dlp, drp);
+ dnp->dn_reg = inp->din_root->dn_reg;
+ dt_cg_typecast(inp->din_root, dnp, dlp, drp);
+
+ if (idp->di_kind == DT_IDENT_ARRAY) {
+ for (i = 0; i < inp->din_argc; i++) {
+ pinp = inp->din_argv[i]->di_iarg;
+ pinp->din_root = NULL;
+ }
+ }
+}
+
+typedef struct dt_xlmemb {
+ dt_ident_t *dtxl_idp; /* translated ident */
+ dt_irlist_t *dtxl_dlp; /* instruction list */
+ dt_regset_t *dtxl_drp; /* register set */
+ int dtxl_sreg; /* location of the translation input */
+ int dtxl_dreg; /* location of our allocated buffer */
+} dt_xlmemb_t;
+
+/*ARGSUSED*/
+static int
+dt_cg_xlate_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
+{
+ dt_xlmemb_t *dx = arg;
+ dt_ident_t *idp = dx->dtxl_idp;
+ dt_irlist_t *dlp = dx->dtxl_dlp;
+ dt_regset_t *drp = dx->dtxl_drp;
+
+ dt_node_t *mnp;
+ dt_xlator_t *dxp;
+
+ int reg, treg;
+ uint32_t instr;
+ size_t size;
+
+ /* Generate code for the translation. */
+ dxp = idp->di_data;
+ mnp = dt_xlator_member(dxp, name);
+
+ /* If there's no translator for the given member, skip it. */
+ if (mnp == NULL)
+ return (0);
+
+ dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
+ dxp->dx_ident->di_id = dx->dtxl_sreg;
+
+ dt_cg_node(mnp->dn_membexpr, dlp, drp);
+
+ dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
+ dxp->dx_ident->di_id = 0;
+
+ treg = mnp->dn_membexpr->dn_reg;
+
+ /* Compute the offset into our buffer and store the result there. */
+ reg = dt_regset_alloc(drp);
+
+ dt_cg_setx(dlp, reg, off / NBBY);
+ instr = DIF_INSTR_FMT(DIF_OP_ADD, dx->dtxl_dreg, reg, reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ size = ctf_type_size(mnp->dn_membexpr->dn_ctfp,
+ mnp->dn_membexpr->dn_type);
+ if (dt_node_is_scalar(mnp->dn_membexpr)) {
+ /*
+ * Copying scalars is simple.
+ */
+ switch (size) {
+ case 1:
+ instr = DIF_INSTR_STORE(DIF_OP_STB, treg, reg);
+ break;
+ case 2:
+ instr = DIF_INSTR_STORE(DIF_OP_STH, treg, reg);
+ break;
+ case 4:
+ instr = DIF_INSTR_STORE(DIF_OP_STW, treg, reg);
+ break;
+ case 8:
+ instr = DIF_INSTR_STORE(DIF_OP_STX, treg, reg);
+ break;
+ default:
+ xyerror(D_UNKNOWN, "internal error -- unexpected "
+ "size: %lu\n", (ulong_t)size);
+ }
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ } else if (dt_node_is_string(mnp->dn_membexpr)) {
+ int szreg;
+
+ /*
+ * Use the copys instruction for strings.
+ */
+ szreg = dt_regset_alloc(drp);
+ dt_cg_setx(dlp, szreg, size);
+ instr = DIF_INSTR_COPYS(treg, szreg, reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, szreg);
+ } else {
+ int szreg;
+
+ /*
+ * If it's anything else then we'll just bcopy it.
+ */
+ szreg = dt_regset_alloc(drp);
+ dt_cg_setx(dlp, szreg, size);
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
+ instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
+ DIF_REG_R0, treg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
+ DIF_REG_R0, reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
+ DIF_REG_R0, szreg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ instr = DIF_INSTR_CALL(DIF_SUBR_BCOPY, szreg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, szreg);
+ }
+
+ dt_regset_free(drp, reg);
+ dt_regset_free(drp, treg);
+
+ return (0);
+}
+
+/*
+ * If we're expanding a translated type, we create an appropriately sized
+ * buffer with alloca() and then translate each member into it.
+ */
+static int
+dt_cg_xlate_expand(dt_node_t *dnp, dt_ident_t *idp, dt_irlist_t *dlp,
+ dt_regset_t *drp)
+{
+ dt_xlmemb_t dlm;
+ uint32_t instr;
+ int dreg;
+ size_t size;
+
+ dreg = dt_regset_alloc(drp);
+ size = ctf_type_size(dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type);
+
+ /* Call alloca() to create the buffer. */
+ dt_cg_setx(dlp, dreg, size);
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
+
+ instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, DIF_REG_R0, dreg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ instr = DIF_INSTR_CALL(DIF_SUBR_ALLOCA, dreg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ /* Generate the translation for each member. */
+ dlm.dtxl_idp = idp;
+ dlm.dtxl_dlp = dlp;
+ dlm.dtxl_drp = drp;
+ dlm.dtxl_sreg = dnp->dn_reg;
+ dlm.dtxl_dreg = dreg;
+ (void) ctf_member_iter(dnp->dn_ident->di_ctfp,
+ dnp->dn_ident->di_type, dt_cg_xlate_member,
+ &dlm);
+
+ return (dreg);
+}
+
+static void
+dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+ ctf_file_t *ctfp = dnp->dn_ctfp;
+ ctf_file_t *octfp;
+ ctf_membinfo_t m;
+ ctf_id_t type;
+
+ dif_instr_t instr;
+ dt_ident_t *idp;
+ ssize_t stroff;
+ uint_t op;
+
+ switch (dnp->dn_op) {
+ case DT_TOK_COMMA:
+ dt_cg_node(dnp->dn_left, dlp, drp);
+ dt_regset_free(drp, dnp->dn_left->dn_reg);
+ dt_cg_node(dnp->dn_right, dlp, drp);
+ dnp->dn_reg = dnp->dn_right->dn_reg;
+ break;
+
+ case DT_TOK_ASGN:
+ dt_cg_node(dnp->dn_right, dlp, drp);
+ dnp->dn_reg = dnp->dn_right->dn_reg;
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_ADD_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_SUB_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_MUL_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_DIV_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp,
+ (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_MOD_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp,
+ (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_AND_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_XOR_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_OR_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_LSH_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_RSH_EQ:
+ dt_cg_arithmetic_op(dnp, dlp, drp,
+ (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);
+ dt_cg_asgn_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_QUESTION:
+ dt_cg_ternary_op(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_LOR:
+ dt_cg_logical_or(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_LXOR:
+ dt_cg_logical_xor(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_LAND:
+ dt_cg_logical_and(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_BOR:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR);
+ break;
+
+ case DT_TOK_XOR:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR);
+ break;
+
+ case DT_TOK_BAND:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND);
+ break;
+
+ case DT_TOK_EQU:
+ dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BE);
+ break;
+
+ case DT_TOK_NEQ:
+ dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BNE);
+ break;
+
+ case DT_TOK_LT:
+ dt_cg_compare_op(dnp, dlp, drp,
+ dt_cg_compare_signed(dnp) ? DIF_OP_BL : DIF_OP_BLU);
+ break;
+
+ case DT_TOK_LE:
+ dt_cg_compare_op(dnp, dlp, drp,
+ dt_cg_compare_signed(dnp) ? DIF_OP_BLE : DIF_OP_BLEU);
+ break;
+
+ case DT_TOK_GT:
+ dt_cg_compare_op(dnp, dlp, drp,
+ dt_cg_compare_signed(dnp) ? DIF_OP_BG : DIF_OP_BGU);
+ break;
+
+ case DT_TOK_GE:
+ dt_cg_compare_op(dnp, dlp, drp,
+ dt_cg_compare_signed(dnp) ? DIF_OP_BGE : DIF_OP_BGEU);
+ break;
+
+ case DT_TOK_LSH:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL);
+ break;
+
+ case DT_TOK_RSH:
+ dt_cg_arithmetic_op(dnp, dlp, drp,
+ (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL);
+ break;
+
+ case DT_TOK_ADD:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD);
+ break;
+
+ case DT_TOK_SUB:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB);
+ break;
+
+ case DT_TOK_MUL:
+ dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL);
+ break;
+
+ case DT_TOK_DIV:
+ dt_cg_arithmetic_op(dnp, dlp, drp,
+ (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV);
+ break;
+
+ case DT_TOK_MOD:
+ dt_cg_arithmetic_op(dnp, dlp, drp,
+ (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM);
+ break;
+
+ case DT_TOK_LNEG:
+ dt_cg_logical_neg(dnp, dlp, drp);
+ break;
+
+ case DT_TOK_BNEG:
+ dt_cg_node(dnp->dn_child, dlp, drp);
+ dnp->dn_reg = dnp->dn_child->dn_reg;
+ instr = DIF_INSTR_NOT(dnp->dn_reg, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ break;
+
+ case DT_TOK_PREINC:
+ dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_ADD);
+ break;
+
+ case DT_TOK_POSTINC:
+ dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_ADD);
+ break;
+
+ case DT_TOK_PREDEC:
+ dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_SUB);
+ break;
+
+ case DT_TOK_POSTDEC:
+ dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_SUB);
+ break;
+
+ case DT_TOK_IPOS:
+ dt_cg_node(dnp->dn_child, dlp, drp);
+ dnp->dn_reg = dnp->dn_child->dn_reg;
+ break;
+
+ case DT_TOK_INEG:
+ dt_cg_node(dnp->dn_child, dlp, drp);
+ dnp->dn_reg = dnp->dn_child->dn_reg;
+
+ instr = DIF_INSTR_FMT(DIF_OP_SUB, DIF_REG_R0,
+ dnp->dn_reg, dnp->dn_reg);
+
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ break;
+
+ case DT_TOK_DEREF:
+ dt_cg_node(dnp->dn_child, dlp, drp);
+ dnp->dn_reg = dnp->dn_child->dn_reg;
+
+ if (dt_node_is_dynamic(dnp->dn_child)) {
+ int reg;
+ idp = dt_node_resolve(dnp->dn_child, DT_IDENT_XLPTR);
+ assert(idp != NULL);
+ reg = dt_cg_xlate_expand(dnp, idp, dlp, drp);
+
+ dt_regset_free(drp, dnp->dn_child->dn_reg);
+ dnp->dn_reg = reg;
+
+ } else if (!(dnp->dn_flags & DT_NF_REF)) {
+ uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
+
+ /*
+ * Save and restore DT_NF_USERLAND across dt_cg_load():
+ * we need the sign bit from dnp and the user bit from
+ * dnp->dn_child in order to get the proper opcode.
+ */
+ dnp->dn_flags |=
+ (dnp->dn_child->dn_flags & DT_NF_USERLAND);
+
+ instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,
+ dnp->dn_type), dnp->dn_reg, dnp->dn_reg);
+
+ dnp->dn_flags &= ~DT_NF_USERLAND;
+ dnp->dn_flags |= ubit;
+
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+ }
+ break;
+
+ case DT_TOK_ADDROF: {
+ uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
+
+ dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */
+ dt_cg_node(dnp->dn_child, dlp, drp);
+ dnp->dn_reg = dnp->dn_child->dn_reg;
+
+ dnp->dn_child->dn_flags &= ~DT_NF_REF;
+ dnp->dn_child->dn_flags |= rbit;
+ break;
+ }
+
+ case DT_TOK_SIZEOF: {
+ size_t size = dt_node_sizeof(dnp->dn_child);
+ dnp->dn_reg = dt_regset_alloc(drp);
+ assert(size != 0);
+ dt_cg_setx(dlp, dnp->dn_reg, size);
+ break;
+ }
+
+ case DT_TOK_STRINGOF:
+ dt_cg_node(dnp->dn_child, dlp, drp);
+ dnp->dn_reg = dnp->dn_child->dn_reg;
+ break;
+
+ case DT_TOK_XLATE:
+ /*
+ * An xlate operator appears in either an XLATOR, indicating a
+ * reference to a dynamic translator, or an OP2, indicating
+ * use of the xlate operator in the user's program. For the
+ * dynamic case, generate an xlate opcode with a reference to
+ * the corresponding member, pre-computed for us in dn_members.
+ */
+ if (dnp->dn_kind == DT_NODE_XLATOR) {
+ dt_xlator_t *dxp = dnp->dn_xlator;
+
+ assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG);
+ assert(dxp->dx_ident->di_id != 0);
+
+ dnp->dn_reg = dt_regset_alloc(drp);
+
+ if (dxp->dx_arg == -1) {
+ instr = DIF_INSTR_MOV(
+ dxp->dx_ident->di_id, dnp->dn_reg);
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+ op = DIF_OP_XLATE;
+ } else
+ op = DIF_OP_XLARG;
+
+ instr = DIF_INSTR_XLATE(op, 0, dnp->dn_reg);
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ dlp->dl_last->di_extern = dnp->dn_xmember;
+ break;
+ }
+
+ assert(dnp->dn_kind == DT_NODE_OP2);
+ dt_cg_node(dnp->dn_right, dlp, drp);
+ dnp->dn_reg = dnp->dn_right->dn_reg;
+ break;
+
+ case DT_TOK_LPAR:
+ dt_cg_node(dnp->dn_right, dlp, drp);
+ dnp->dn_reg = dnp->dn_right->dn_reg;
+ dt_cg_typecast(dnp->dn_right, dnp, dlp, drp);
+ break;
+
+ case DT_TOK_PTR:
+ case DT_TOK_DOT:
+ assert(dnp->dn_right->dn_kind == DT_NODE_IDENT);
+ dt_cg_node(dnp->dn_left, dlp, drp);
+
+ /*
+ * If the left-hand side of PTR or DOT is a dynamic variable,
+ * we expect it to be the output of a D translator. In this
+ * case, we look up the parse tree corresponding to the member
+ * that is being accessed and run the code generator over it.
+ * We then cast the result as if by the assignment operator.
+ */
+ if ((idp = dt_node_resolve(
+ dnp->dn_left, DT_IDENT_XLSOU)) != NULL ||
+ (idp = dt_node_resolve(
+ dnp->dn_left, DT_IDENT_XLPTR)) != NULL) {
+
+ dt_xlator_t *dxp;
+ dt_node_t *mnp;
+
+ dxp = idp->di_data;
+ mnp = dt_xlator_member(dxp, dnp->dn_right->dn_string);
+ assert(mnp != NULL);
+
+ dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
+ dxp->dx_ident->di_id = dnp->dn_left->dn_reg;
+
+ dt_cg_node(mnp->dn_membexpr, dlp, drp);
+ dnp->dn_reg = mnp->dn_membexpr->dn_reg;
+ dt_cg_typecast(mnp->dn_membexpr, dnp, dlp, drp);
+
+ dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
+ dxp->dx_ident->di_id = 0;
+
+ if (dnp->dn_left->dn_reg != -1)
+ dt_regset_free(drp, dnp->dn_left->dn_reg);
+ break;
+ }
+
+ ctfp = dnp->dn_left->dn_ctfp;
+ type = ctf_type_resolve(ctfp, dnp->dn_left->dn_type);
+
+ if (dnp->dn_op == DT_TOK_PTR) {
+ type = ctf_type_reference(ctfp, type);
+ type = ctf_type_resolve(ctfp, type);
+ }
+
+ if ((ctfp = dt_cg_membinfo(octfp = ctfp, type,
+ dnp->dn_right->dn_string, &m)) == NULL) {
+ yypcb->pcb_hdl->dt_ctferr = ctf_errno(octfp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
+ }
+
+ if (m.ctm_offset != 0) {
+ int reg;
+
+ reg = dt_regset_alloc(drp);
+
+ /*
+ * If the offset is not aligned on a byte boundary, it
+ * is a bit-field member and we will extract the value
+ * bits below after we generate the appropriate load.
+ */
+ dt_cg_setx(dlp, reg, m.ctm_offset / NBBY);
+
+ instr = DIF_INSTR_FMT(DIF_OP_ADD,
+ dnp->dn_left->dn_reg, reg, dnp->dn_left->dn_reg);
+
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, reg);
+ }
+
+ if (!(dnp->dn_flags & DT_NF_REF)) {
+ uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
+
+ /*
+ * Save and restore DT_NF_USERLAND across dt_cg_load():
+ * we need the sign bit from dnp and the user bit from
+ * dnp->dn_left in order to get the proper opcode.
+ */
+ dnp->dn_flags |=
+ (dnp->dn_left->dn_flags & DT_NF_USERLAND);
+
+ instr = DIF_INSTR_LOAD(dt_cg_load(dnp,
+ ctfp, m.ctm_type), dnp->dn_left->dn_reg,
+ dnp->dn_left->dn_reg);
+
+ dnp->dn_flags &= ~DT_NF_USERLAND;
+ dnp->dn_flags |= ubit;
+
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ if (dnp->dn_flags & DT_NF_BITFIELD)
+ dt_cg_field_get(dnp, dlp, drp, ctfp, &m);
+ }
+
+ dnp->dn_reg = dnp->dn_left->dn_reg;
+ break;
+
+ case DT_TOK_STRING:
+ dnp->dn_reg = dt_regset_alloc(drp);
+
+ assert(dnp->dn_kind == DT_NODE_STRING);
+ stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string);
+
+ if (stroff == -1L)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ if (stroff > DIF_STROFF_MAX)
+ longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG);
+
+ instr = DIF_INSTR_SETS((ulong_t)stroff, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ break;
+
+ case DT_TOK_IDENT:
+ /*
+ * If the specified identifier is a variable on which we have
+ * set the code generator register flag, then this variable
+ * has already had code generated for it and saved in di_id.
+ * Allocate a new register and copy the existing value to it.
+ */
+ if (dnp->dn_kind == DT_NODE_VAR &&
+ (dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) {
+ dnp->dn_reg = dt_regset_alloc(drp);
+ instr = DIF_INSTR_MOV(dnp->dn_ident->di_id,
+ dnp->dn_reg);
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+ break;
+ }
+
+ /*
+ * Identifiers can represent function calls, variable refs, or
+ * symbols. First we check for inlined variables, and handle
+ * them by generating code for the inline parse tree.
+ */
+ if (dnp->dn_kind == DT_NODE_VAR &&
+ (dnp->dn_ident->di_flags & DT_IDFLG_INLINE)) {
+ dt_cg_inline(dnp, dlp, drp);
+ break;
+ }
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_FUNC: {
+ if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) {
+ dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be "
+ "called from a D expression (D program "
+ "context required)\n",
+ dt_idkind_name(idp->di_kind), idp->di_name);
+ }
+
+ dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
+
+ dnp->dn_reg = dt_regset_alloc(drp);
+ instr = DIF_INSTR_CALL(dnp->dn_ident->di_id,
+ dnp->dn_reg);
+
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ break;
+ }
+
+ case DT_NODE_VAR:
+ if (dnp->dn_ident->di_kind == DT_IDENT_XLSOU ||
+ dnp->dn_ident->di_kind == DT_IDENT_XLPTR) {
+ /*
+ * This can only happen if we have translated
+ * args[]. See dt_idcook_args() for details.
+ */
+ assert(dnp->dn_ident->di_id == DIF_VAR_ARGS);
+ dt_cg_array_op(dnp, dlp, drp);
+ break;
+ }
+
+ if (dnp->dn_ident->di_kind == DT_IDENT_ARRAY) {
+ if (dnp->dn_ident->di_id > DIF_VAR_ARRAY_MAX)
+ dt_cg_assoc_op(dnp, dlp, drp);
+ else
+ dt_cg_array_op(dnp, dlp, drp);
+ break;
+ }
+
+ dnp->dn_reg = dt_regset_alloc(drp);
+
+ if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)
+ op = DIF_OP_LDLS;
+ else if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
+ op = DIF_OP_LDTS;
+ else
+ op = DIF_OP_LDGS;
+
+ dnp->dn_ident->di_flags |= DT_IDFLG_DIFR;
+
+ instr = DIF_INSTR_LDV(op,
+ dnp->dn_ident->di_id, dnp->dn_reg);
+
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+ break;
+
+ case DT_NODE_SYM: {
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dtrace_syminfo_t *sip = dnp->dn_ident->di_data;
+ GElf_Sym sym;
+
+ if (dtrace_lookup_by_name(dtp,
+ sip->dts_object, sip->dts_name, &sym, NULL) == -1) {
+ xyerror(D_UNKNOWN, "cg failed for symbol %s`%s:"
+ " %s\n", sip->dts_object, sip->dts_name,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ dnp->dn_reg = dt_regset_alloc(drp);
+ dt_cg_xsetx(dlp, dnp->dn_ident,
+ DT_LBL_NONE, dnp->dn_reg, sym.st_value);
+
+ if (!(dnp->dn_flags & DT_NF_REF)) {
+ instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp,
+ dnp->dn_type), dnp->dn_reg, dnp->dn_reg);
+ dt_irlist_append(dlp,
+ dt_cg_node_alloc(DT_LBL_NONE, instr));
+ }
+ break;
+ }
+
+ default:
+ xyerror(D_UNKNOWN, "internal error -- node type %u is "
+ "not valid for an identifier\n", dnp->dn_kind);
+ }
+ break;
+
+ case DT_TOK_INT:
+ dnp->dn_reg = dt_regset_alloc(drp);
+ dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value);
+ break;
+
+ default:
+ xyerror(D_UNKNOWN, "internal error -- token type %u is not a "
+ "valid D compilation token\n", dnp->dn_op);
+ }
+}
+
+void
+dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
+{
+ dif_instr_t instr;
+ dt_xlator_t *dxp;
+ dt_ident_t *idp;
+
+ if (pcb->pcb_regs == NULL && (pcb->pcb_regs =
+ dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dt_regset_reset(pcb->pcb_regs);
+ (void) dt_regset_alloc(pcb->pcb_regs); /* allocate %r0 */
+
+ if (pcb->pcb_inttab != NULL)
+ dt_inttab_destroy(pcb->pcb_inttab);
+
+ if ((pcb->pcb_inttab = dt_inttab_create(yypcb->pcb_hdl)) == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+
+ if (pcb->pcb_strtab != NULL)
+ dt_strtab_destroy(pcb->pcb_strtab);
+
+ if ((pcb->pcb_strtab = dt_strtab_create(BUFSIZ)) == NULL)
+ longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dt_irlist_destroy(&pcb->pcb_ir);
+ dt_irlist_create(&pcb->pcb_ir);
+
+ assert(pcb->pcb_dret == NULL);
+ pcb->pcb_dret = dnp;
+
+ if (dt_node_resolve(dnp, DT_IDENT_XLPTR) != NULL) {
+ dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result "
+ "of a translated pointer\n");
+ }
+
+ /*
+ * If we're generating code for a translator body, assign the input
+ * parameter to the first available register (i.e. caller passes %r1).
+ */
+ if (dnp->dn_kind == DT_NODE_MEMBER) {
+ dxp = dnp->dn_membxlator;
+ dnp = dnp->dn_membexpr;
+
+ dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
+ dxp->dx_ident->di_id = dt_regset_alloc(pcb->pcb_regs);
+ }
+
+ dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs);
+
+ if ((idp = dt_node_resolve(dnp, DT_IDENT_XLSOU)) != NULL) {
+ int reg = dt_cg_xlate_expand(dnp, idp,
+ &pcb->pcb_ir, pcb->pcb_regs);
+ dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
+ dnp->dn_reg = reg;
+ }
+
+ instr = DIF_INSTR_RET(dnp->dn_reg);
+ dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
+ dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+ if (dnp->dn_kind == DT_NODE_MEMBER) {
+ dt_regset_free(pcb->pcb_regs, dxp->dx_ident->di_id);
+ dxp->dx_ident->di_id = 0;
+ dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
+ }
+
+ dt_regset_free(pcb->pcb_regs, 0);
+ dt_regset_assert_free(pcb->pcb_regs);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
new file mode 100644
index 000000000000..811c88bbf0ad
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
@@ -0,0 +1,3084 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <assert.h>
+#include <ctype.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <dt_impl.h>
+#include <dt_pq.h>
+#ifndef illumos
+#include <libproc_compat.h>
+#endif
+
+#define DT_MASK_LO 0x00000000FFFFFFFFULL
+
+/*
+ * We declare this here because (1) we need it and (2) we want to avoid a
+ * dependency on libm in libdtrace.
+ */
+static long double
+dt_fabsl(long double x)
+{
+ if (x < 0)
+ return (-x);
+
+ return (x);
+}
+
+static int
+dt_ndigits(long long val)
+{
+ int rval = 1;
+ long long cmp = 10;
+
+ if (val < 0) {
+ val = val == INT64_MIN ? INT64_MAX : -val;
+ rval++;
+ }
+
+ while (val > cmp && cmp > 0) {
+ rval++;
+ cmp *= 10;
+ }
+
+ return (rval < 4 ? 4 : rval);
+}
+
+/*
+ * 128-bit arithmetic functions needed to support the stddev() aggregating
+ * action.
+ */
+static int
+dt_gt_128(uint64_t *a, uint64_t *b)
+{
+ return (a[1] > b[1] || (a[1] == b[1] && a[0] > b[0]));
+}
+
+static int
+dt_ge_128(uint64_t *a, uint64_t *b)
+{
+ return (a[1] > b[1] || (a[1] == b[1] && a[0] >= b[0]));
+}
+
+static int
+dt_le_128(uint64_t *a, uint64_t *b)
+{
+ return (a[1] < b[1] || (a[1] == b[1] && a[0] <= b[0]));
+}
+
+/*
+ * Shift the 128-bit value in a by b. If b is positive, shift left.
+ * If b is negative, shift right.
+ */
+static void
+dt_shift_128(uint64_t *a, int b)
+{
+ uint64_t mask;
+
+ if (b == 0)
+ return;
+
+ if (b < 0) {
+ b = -b;
+ if (b >= 64) {
+ a[0] = a[1] >> (b - 64);
+ a[1] = 0;
+ } else {
+ a[0] >>= b;
+ mask = 1LL << (64 - b);
+ mask -= 1;
+ a[0] |= ((a[1] & mask) << (64 - b));
+ a[1] >>= b;
+ }
+ } else {
+ if (b >= 64) {
+ a[1] = a[0] << (b - 64);
+ a[0] = 0;
+ } else {
+ a[1] <<= b;
+ mask = a[0] >> (64 - b);
+ a[1] |= mask;
+ a[0] <<= b;
+ }
+ }
+}
+
+static int
+dt_nbits_128(uint64_t *a)
+{
+ int nbits = 0;
+ uint64_t tmp[2];
+ uint64_t zero[2] = { 0, 0 };
+
+ tmp[0] = a[0];
+ tmp[1] = a[1];
+
+ dt_shift_128(tmp, -1);
+ while (dt_gt_128(tmp, zero)) {
+ dt_shift_128(tmp, -1);
+ nbits++;
+ }
+
+ return (nbits);
+}
+
+static void
+dt_subtract_128(uint64_t *minuend, uint64_t *subtrahend, uint64_t *difference)
+{
+ uint64_t result[2];
+
+ result[0] = minuend[0] - subtrahend[0];
+ result[1] = minuend[1] - subtrahend[1] -
+ (minuend[0] < subtrahend[0] ? 1 : 0);
+
+ difference[0] = result[0];
+ difference[1] = result[1];
+}
+
+static void
+dt_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum)
+{
+ uint64_t result[2];
+
+ result[0] = addend1[0] + addend2[0];
+ result[1] = addend1[1] + addend2[1] +
+ (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0);
+
+ sum[0] = result[0];
+ sum[1] = result[1];
+}
+
+/*
+ * The basic idea is to break the 2 64-bit values into 4 32-bit values,
+ * use native multiplication on those, and then re-combine into the
+ * resulting 128-bit value.
+ *
+ * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) =
+ * hi1 * hi2 << 64 +
+ * hi1 * lo2 << 32 +
+ * hi2 * lo1 << 32 +
+ * lo1 * lo2
+ */
+static void
+dt_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product)
+{
+ uint64_t hi1, hi2, lo1, lo2;
+ uint64_t tmp[2];
+
+ hi1 = factor1 >> 32;
+ hi2 = factor2 >> 32;
+
+ lo1 = factor1 & DT_MASK_LO;
+ lo2 = factor2 & DT_MASK_LO;
+
+ product[0] = lo1 * lo2;
+ product[1] = hi1 * hi2;
+
+ tmp[0] = hi1 * lo2;
+ tmp[1] = 0;
+ dt_shift_128(tmp, 32);
+ dt_add_128(product, tmp, product);
+
+ tmp[0] = hi2 * lo1;
+ tmp[1] = 0;
+ dt_shift_128(tmp, 32);
+ dt_add_128(product, tmp, product);
+}
+
+/*
+ * This is long-hand division.
+ *
+ * We initialize subtrahend by shifting divisor left as far as possible. We
+ * loop, comparing subtrahend to dividend: if subtrahend is smaller, we
+ * subtract and set the appropriate bit in the result. We then shift
+ * subtrahend right by one bit for the next comparison.
+ */
+static void
+dt_divide_128(uint64_t *dividend, uint64_t divisor, uint64_t *quotient)
+{
+ uint64_t result[2] = { 0, 0 };
+ uint64_t remainder[2];
+ uint64_t subtrahend[2];
+ uint64_t divisor_128[2];
+ uint64_t mask[2] = { 1, 0 };
+ int log = 0;
+
+ assert(divisor != 0);
+
+ divisor_128[0] = divisor;
+ divisor_128[1] = 0;
+
+ remainder[0] = dividend[0];
+ remainder[1] = dividend[1];
+
+ subtrahend[0] = divisor;
+ subtrahend[1] = 0;
+
+ while (divisor > 0) {
+ log++;
+ divisor >>= 1;
+ }
+
+ dt_shift_128(subtrahend, 128 - log);
+ dt_shift_128(mask, 128 - log);
+
+ while (dt_ge_128(remainder, divisor_128)) {
+ if (dt_ge_128(remainder, subtrahend)) {
+ dt_subtract_128(remainder, subtrahend, remainder);
+ result[0] |= mask[0];
+ result[1] |= mask[1];
+ }
+
+ dt_shift_128(subtrahend, -1);
+ dt_shift_128(mask, -1);
+ }
+
+ quotient[0] = result[0];
+ quotient[1] = result[1];
+}
+
+/*
+ * This is the long-hand method of calculating a square root.
+ * The algorithm is as follows:
+ *
+ * 1. Group the digits by 2 from the right.
+ * 2. Over the leftmost group, find the largest single-digit number
+ * whose square is less than that group.
+ * 3. Subtract the result of the previous step (2 or 4, depending) and
+ * bring down the next two-digit group.
+ * 4. For the result R we have so far, find the largest single-digit number
+ * x such that 2 * R * 10 * x + x^2 is less than the result from step 3.
+ * (Note that this is doubling R and performing a decimal left-shift by 1
+ * and searching for the appropriate decimal to fill the one's place.)
+ * The value x is the next digit in the square root.
+ * Repeat steps 3 and 4 until the desired precision is reached. (We're
+ * dealing with integers, so the above is sufficient.)
+ *
+ * In decimal, the square root of 582,734 would be calculated as so:
+ *
+ * __7__6__3
+ * | 58 27 34
+ * -49 (7^2 == 49 => 7 is the first digit in the square root)
+ * --
+ * 9 27 (Subtract and bring down the next group.)
+ * 146 8 76 (2 * 7 * 10 * 6 + 6^2 == 876 => 6 is the next digit in
+ * ----- the square root)
+ * 51 34 (Subtract and bring down the next group.)
+ * 1523 45 69 (2 * 76 * 10 * 3 + 3^2 == 4569 => 3 is the next digit in
+ * ----- the square root)
+ * 5 65 (remainder)
+ *
+ * The above algorithm applies similarly in binary, but note that the
+ * only possible non-zero value for x in step 4 is 1, so step 4 becomes a
+ * simple decision: is 2 * R * 2 * 1 + 1^2 (aka R << 2 + 1) less than the
+ * preceding difference?
+ *
+ * In binary, the square root of 11011011 would be calculated as so:
+ *
+ * __1__1__1__0
+ * | 11 01 10 11
+ * 01 (0 << 2 + 1 == 1 < 11 => this bit is 1)
+ * --
+ * 10 01 10 11
+ * 101 1 01 (1 << 2 + 1 == 101 < 1001 => next bit is 1)
+ * -----
+ * 1 00 10 11
+ * 1101 11 01 (11 << 2 + 1 == 1101 < 10010 => next bit is 1)
+ * -------
+ * 1 01 11
+ * 11101 1 11 01 (111 << 2 + 1 == 11101 > 10111 => last bit is 0)
+ *
+ */
+static uint64_t
+dt_sqrt_128(uint64_t *square)
+{
+ uint64_t result[2] = { 0, 0 };
+ uint64_t diff[2] = { 0, 0 };
+ uint64_t one[2] = { 1, 0 };
+ uint64_t next_pair[2];
+ uint64_t next_try[2];
+ uint64_t bit_pairs, pair_shift;
+ int i;
+
+ bit_pairs = dt_nbits_128(square) / 2;
+ pair_shift = bit_pairs * 2;
+
+ for (i = 0; i <= bit_pairs; i++) {
+ /*
+ * Bring down the next pair of bits.
+ */
+ next_pair[0] = square[0];
+ next_pair[1] = square[1];
+ dt_shift_128(next_pair, -pair_shift);
+ next_pair[0] &= 0x3;
+ next_pair[1] = 0;
+
+ dt_shift_128(diff, 2);
+ dt_add_128(diff, next_pair, diff);
+
+ /*
+ * next_try = R << 2 + 1
+ */
+ next_try[0] = result[0];
+ next_try[1] = result[1];
+ dt_shift_128(next_try, 2);
+ dt_add_128(next_try, one, next_try);
+
+ if (dt_le_128(next_try, diff)) {
+ dt_subtract_128(diff, next_try, diff);
+ dt_shift_128(result, 1);
+ dt_add_128(result, one, result);
+ } else {
+ dt_shift_128(result, 1);
+ }
+
+ pair_shift -= 2;
+ }
+
+ assert(result[1] == 0);
+
+ return (result[0]);
+}
+
+uint64_t
+dt_stddev(uint64_t *data, uint64_t normal)
+{
+ uint64_t avg_of_squares[2];
+ uint64_t square_of_avg[2];
+ int64_t norm_avg;
+ uint64_t diff[2];
+
+ if (data[0] == 0)
+ return (0);
+
+ /*
+ * The standard approximation for standard deviation is
+ * sqrt(average(x**2) - average(x)**2), i.e. the square root
+ * of the average of the squares minus the square of the average.
+ * When normalizing, we should divide the sum of x**2 by normal**2.
+ */
+ dt_divide_128(data + 2, normal, avg_of_squares);
+ dt_divide_128(avg_of_squares, normal, avg_of_squares);
+ dt_divide_128(avg_of_squares, data[0], avg_of_squares);
+
+ norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0];
+
+ if (norm_avg < 0)
+ norm_avg = -norm_avg;
+
+ dt_multiply_128((uint64_t)norm_avg, (uint64_t)norm_avg, square_of_avg);
+
+ dt_subtract_128(avg_of_squares, square_of_avg, diff);
+
+ return (dt_sqrt_128(diff));
+}
+
+static int
+dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last,
+ dtrace_bufdesc_t *buf, size_t offs)
+{
+ dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd;
+ dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd;
+ char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub;
+ dtrace_flowkind_t flow = DTRACEFLOW_NONE;
+ const char *str = NULL;
+ static const char *e_str[2] = { " -> ", " => " };
+ static const char *r_str[2] = { " <- ", " <= " };
+ static const char *ent = "entry", *ret = "return";
+ static int entlen = 0, retlen = 0;
+ dtrace_epid_t next, id = epd->dtepd_epid;
+ int rval;
+
+ if (entlen == 0) {
+ assert(retlen == 0);
+ entlen = strlen(ent);
+ retlen = strlen(ret);
+ }
+
+ /*
+ * If the name of the probe is "entry" or ends with "-entry", we
+ * treat it as an entry; if it is "return" or ends with "-return",
+ * we treat it as a return. (This allows application-provided probes
+ * like "method-entry" or "function-entry" to participate in flow
+ * indentation -- without accidentally misinterpreting popular probe
+ * names like "carpentry", "gentry" or "Coventry".)
+ */
+ if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' &&
+ (sub == n || sub[-1] == '-')) {
+ flow = DTRACEFLOW_ENTRY;
+ str = e_str[strcmp(p, "syscall") == 0];
+ } else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' &&
+ (sub == n || sub[-1] == '-')) {
+ flow = DTRACEFLOW_RETURN;
+ str = r_str[strcmp(p, "syscall") == 0];
+ }
+
+ /*
+ * If we're going to indent this, we need to check the ID of our last
+ * call. If we're looking at the same probe ID but a different EPID,
+ * we _don't_ want to indent. (Yes, there are some minor holes in
+ * this scheme -- it's a heuristic.)
+ */
+ if (flow == DTRACEFLOW_ENTRY) {
+ if ((last != DTRACE_EPIDNONE && id != last &&
+ pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id))
+ flow = DTRACEFLOW_NONE;
+ }
+
+ /*
+ * If we're going to unindent this, it's more difficult to see if
+ * we don't actually want to unindent it -- we need to look at the
+ * _next_ EPID.
+ */
+ if (flow == DTRACEFLOW_RETURN) {
+ offs += epd->dtepd_size;
+
+ do {
+ if (offs >= buf->dtbd_size)
+ goto out;
+
+ next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
+
+ if (next == DTRACE_EPIDNONE)
+ offs += sizeof (id);
+ } while (next == DTRACE_EPIDNONE);
+
+ if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0)
+ return (rval);
+
+ if (next != id && npd->dtpd_id == pd->dtpd_id)
+ flow = DTRACEFLOW_NONE;
+ }
+
+out:
+ if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) {
+ data->dtpda_prefix = str;
+ } else {
+ data->dtpda_prefix = "| ";
+ }
+
+ if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0)
+ data->dtpda_indent -= 2;
+
+ data->dtpda_flow = flow;
+
+ return (0);
+}
+
+static int
+dt_nullprobe()
+{
+ return (DTRACE_CONSUME_THIS);
+}
+
+static int
+dt_nullrec()
+{
+ return (DTRACE_CONSUME_NEXT);
+}
+
+static void
+dt_quantize_total(dtrace_hdl_t *dtp, int64_t datum, long double *total)
+{
+ long double val = dt_fabsl((long double)datum);
+
+ if (dtp->dt_options[DTRACEOPT_AGGZOOM] == DTRACEOPT_UNSET) {
+ *total += val;
+ return;
+ }
+
+ /*
+ * If we're zooming in on an aggregation, we want the height of the
+ * highest value to be approximately 95% of total bar height -- so we
+ * adjust up by the reciprocal of DTRACE_AGGZOOM_MAX when comparing to
+ * our highest value.
+ */
+ val *= 1 / DTRACE_AGGZOOM_MAX;
+
+ if (*total < val)
+ *total = val;
+}
+
+static int
+dt_print_quanthdr(dtrace_hdl_t *dtp, FILE *fp, int width)
+{
+ return (dt_printf(dtp, fp, "\n%*s %41s %-9s\n",
+ width ? width : 16, width ? "key" : "value",
+ "------------- Distribution -------------", "count"));
+}
+
+static int
+dt_print_quanthdr_packed(dtrace_hdl_t *dtp, FILE *fp, int width,
+ const dtrace_aggdata_t *aggdata, dtrace_actkind_t action)
+{
+ int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin;
+ int minwidth, maxwidth, i;
+
+ assert(action == DTRACEAGG_QUANTIZE || action == DTRACEAGG_LQUANTIZE);
+
+ if (action == DTRACEAGG_QUANTIZE) {
+ if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET)
+ min--;
+
+ if (max < DTRACE_QUANTIZE_NBUCKETS - 1)
+ max++;
+
+ minwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(min));
+ maxwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(max));
+ } else {
+ maxwidth = 8;
+ minwidth = maxwidth - 1;
+ max++;
+ }
+
+ if (dt_printf(dtp, fp, "\n%*s %*s .",
+ width, width > 0 ? "key" : "", minwidth, "min") < 0)
+ return (-1);
+
+ for (i = min; i <= max; i++) {
+ if (dt_printf(dtp, fp, "-") < 0)
+ return (-1);
+ }
+
+ return (dt_printf(dtp, fp, ". %*s | count\n", -maxwidth, "max"));
+}
+
+/*
+ * We use a subset of the Unicode Block Elements (U+2588 through U+258F,
+ * inclusive) to represent aggregations via UTF-8 -- which are expressed via
+ * 3-byte UTF-8 sequences.
+ */
+#define DTRACE_AGGUTF8_FULL 0x2588
+#define DTRACE_AGGUTF8_BASE 0x258f
+#define DTRACE_AGGUTF8_LEVELS 8
+
+#define DTRACE_AGGUTF8_BYTE0(val) (0xe0 | ((val) >> 12))
+#define DTRACE_AGGUTF8_BYTE1(val) (0x80 | (((val) >> 6) & 0x3f))
+#define DTRACE_AGGUTF8_BYTE2(val) (0x80 | ((val) & 0x3f))
+
+static int
+dt_print_quantline_utf8(dtrace_hdl_t *dtp, FILE *fp, int64_t val,
+ uint64_t normal, long double total)
+{
+ uint_t len = 40, i, whole, partial;
+ long double f = (dt_fabsl((long double)val) * len) / total;
+ const char *spaces = " ";
+
+ whole = (uint_t)f;
+ partial = (uint_t)((f - (long double)(uint_t)f) *
+ (long double)DTRACE_AGGUTF8_LEVELS);
+
+ if (dt_printf(dtp, fp, "|") < 0)
+ return (-1);
+
+ for (i = 0; i < whole; i++) {
+ if (dt_printf(dtp, fp, "%c%c%c",
+ DTRACE_AGGUTF8_BYTE0(DTRACE_AGGUTF8_FULL),
+ DTRACE_AGGUTF8_BYTE1(DTRACE_AGGUTF8_FULL),
+ DTRACE_AGGUTF8_BYTE2(DTRACE_AGGUTF8_FULL)) < 0)
+ return (-1);
+ }
+
+ if (partial != 0) {
+ partial = DTRACE_AGGUTF8_BASE - (partial - 1);
+
+ if (dt_printf(dtp, fp, "%c%c%c",
+ DTRACE_AGGUTF8_BYTE0(partial),
+ DTRACE_AGGUTF8_BYTE1(partial),
+ DTRACE_AGGUTF8_BYTE2(partial)) < 0)
+ return (-1);
+
+ i++;
+ }
+
+ return (dt_printf(dtp, fp, "%s %-9lld\n", spaces + i,
+ (long long)val / normal));
+}
+
+static int
+dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val,
+ uint64_t normal, long double total, char positives, char negatives)
+{
+ long double f;
+ uint_t depth, len = 40;
+
+ const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
+ const char *spaces = " ";
+
+ assert(strlen(ats) == len && strlen(spaces) == len);
+ assert(!(total == 0 && (positives || negatives)));
+ assert(!(val < 0 && !negatives));
+ assert(!(val > 0 && !positives));
+ assert(!(val != 0 && total == 0));
+
+ if (!negatives) {
+ if (positives) {
+ if (dtp->dt_encoding == DT_ENCODING_UTF8) {
+ return (dt_print_quantline_utf8(dtp, fp, val,
+ normal, total));
+ }
+
+ f = (dt_fabsl((long double)val) * len) / total;
+ depth = (uint_t)(f + 0.5);
+ } else {
+ depth = 0;
+ }
+
+ return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth,
+ spaces + depth, (long long)val / normal));
+ }
+
+ if (!positives) {
+ f = (dt_fabsl((long double)val) * len) / total;
+ depth = (uint_t)(f + 0.5);
+
+ return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth,
+ ats + len - depth, (long long)val / normal));
+ }
+
+ /*
+ * If we're here, we have both positive and negative bucket values.
+ * To express this graphically, we're going to generate both positive
+ * and negative bars separated by a centerline. These bars are half
+ * the size of normal quantize()/lquantize() bars, so we divide the
+ * length in half before calculating the bar length.
+ */
+ len /= 2;
+ ats = &ats[len];
+ spaces = &spaces[len];
+
+ f = (dt_fabsl((long double)val) * len) / total;
+ depth = (uint_t)(f + 0.5);
+
+ if (val <= 0) {
+ return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth,
+ ats + len - depth, len, "", (long long)val / normal));
+ } else {
+ return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "",
+ ats + len - depth, spaces + depth,
+ (long long)val / normal));
+ }
+}
+
+/*
+ * As with UTF-8 printing of aggregations, we use a subset of the Unicode
+ * Block Elements (U+2581 through U+2588, inclusive) to represent our packed
+ * aggregation.
+ */
+#define DTRACE_AGGPACK_BASE 0x2581
+#define DTRACE_AGGPACK_LEVELS 8
+
+static int
+dt_print_packed(dtrace_hdl_t *dtp, FILE *fp,
+ long double datum, long double total)
+{
+ static boolean_t utf8_checked = B_FALSE;
+ static boolean_t utf8;
+ char *ascii = "__xxxxXX";
+ char *neg = "vvvvVV";
+ unsigned int len;
+ long double val;
+
+ if (!utf8_checked) {
+ char *term;
+
+ /*
+ * We want to determine if we can reasonably emit UTF-8 for our
+ * packed aggregation. To do this, we will check for terminals
+ * that are known to be primitive to emit UTF-8 on these.
+ */
+ utf8_checked = B_TRUE;
+
+ if (dtp->dt_encoding == DT_ENCODING_ASCII) {
+ utf8 = B_FALSE;
+ } else if (dtp->dt_encoding == DT_ENCODING_UTF8) {
+ utf8 = B_TRUE;
+ } else if ((term = getenv("TERM")) != NULL &&
+ (strcmp(term, "sun") == 0 ||
+ strcmp(term, "sun-color") == 0 ||
+ strcmp(term, "dumb") == 0)) {
+ utf8 = B_FALSE;
+ } else {
+ utf8 = B_TRUE;
+ }
+ }
+
+ if (datum == 0)
+ return (dt_printf(dtp, fp, " "));
+
+ if (datum < 0) {
+ len = strlen(neg);
+ val = dt_fabsl(datum * (len - 1)) / total;
+ return (dt_printf(dtp, fp, "%c", neg[(uint_t)(val + 0.5)]));
+ }
+
+ if (utf8) {
+ int block = DTRACE_AGGPACK_BASE + (unsigned int)(((datum *
+ (DTRACE_AGGPACK_LEVELS - 1)) / total) + 0.5);
+
+ return (dt_printf(dtp, fp, "%c%c%c",
+ DTRACE_AGGUTF8_BYTE0(block),
+ DTRACE_AGGUTF8_BYTE1(block),
+ DTRACE_AGGUTF8_BYTE2(block)));
+ }
+
+ len = strlen(ascii);
+ val = (datum * (len - 1)) / total;
+ return (dt_printf(dtp, fp, "%c", ascii[(uint_t)(val + 0.5)]));
+}
+
+int
+dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+ size_t size, uint64_t normal)
+{
+ const int64_t *data = addr;
+ int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
+ long double total = 0;
+ char positives = 0, negatives = 0;
+
+ if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0)
+ first_bin++;
+
+ if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) {
+ /*
+ * There isn't any data. This is possible if the aggregation
+ * has been clear()'d or if negative increment values have been
+ * used. Regardless, we'll print the buckets around 0.
+ */
+ first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1;
+ last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1;
+ } else {
+ if (first_bin > 0)
+ first_bin--;
+
+ while (last_bin > 0 && data[last_bin] == 0)
+ last_bin--;
+
+ if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1)
+ last_bin++;
+ }
+
+ for (i = first_bin; i <= last_bin; i++) {
+ positives |= (data[i] > 0);
+ negatives |= (data[i] < 0);
+ dt_quantize_total(dtp, data[i], &total);
+ }
+
+ if (dt_print_quanthdr(dtp, fp, 0) < 0)
+ return (-1);
+
+ for (i = first_bin; i <= last_bin; i++) {
+ if (dt_printf(dtp, fp, "%16lld ",
+ (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0)
+ return (-1);
+
+ if (dt_print_quantline(dtp, fp, data[i], normal, total,
+ positives, negatives) < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+dt_print_quantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+ size_t size, const dtrace_aggdata_t *aggdata)
+{
+ const int64_t *data = addr;
+ long double total = 0, count = 0;
+ int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin, i;
+ int64_t minval, maxval;
+
+ if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET)
+ min--;
+
+ if (max < DTRACE_QUANTIZE_NBUCKETS - 1)
+ max++;
+
+ minval = DTRACE_QUANTIZE_BUCKETVAL(min);
+ maxval = DTRACE_QUANTIZE_BUCKETVAL(max);
+
+ if (dt_printf(dtp, fp, " %*lld :", dt_ndigits(minval),
+ (long long)minval) < 0)
+ return (-1);
+
+ for (i = min; i <= max; i++) {
+ dt_quantize_total(dtp, data[i], &total);
+ count += data[i];
+ }
+
+ for (i = min; i <= max; i++) {
+ if (dt_print_packed(dtp, fp, data[i], total) < 0)
+ return (-1);
+ }
+
+ if (dt_printf(dtp, fp, ": %*lld | %lld\n",
+ -dt_ndigits(maxval), (long long)maxval, (long long)count) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+ size_t size, uint64_t normal)
+{
+ const int64_t *data = addr;
+ int i, first_bin, last_bin, base;
+ uint64_t arg;
+ long double total = 0;
+ uint16_t step, levels;
+ char positives = 0, negatives = 0;
+
+ if (size < sizeof (uint64_t))
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ arg = *data++;
+ size -= sizeof (uint64_t);
+
+ base = DTRACE_LQUANTIZE_BASE(arg);
+ step = DTRACE_LQUANTIZE_STEP(arg);
+ levels = DTRACE_LQUANTIZE_LEVELS(arg);
+
+ first_bin = 0;
+ last_bin = levels + 1;
+
+ if (size != sizeof (uint64_t) * (levels + 2))
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ while (first_bin <= levels + 1 && data[first_bin] == 0)
+ first_bin++;
+
+ if (first_bin > levels + 1) {
+ first_bin = 0;
+ last_bin = 2;
+ } else {
+ if (first_bin > 0)
+ first_bin--;
+
+ while (last_bin > 0 && data[last_bin] == 0)
+ last_bin--;
+
+ if (last_bin < levels + 1)
+ last_bin++;
+ }
+
+ for (i = first_bin; i <= last_bin; i++) {
+ positives |= (data[i] > 0);
+ negatives |= (data[i] < 0);
+ dt_quantize_total(dtp, data[i], &total);
+ }
+
+ if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
+ "------------- Distribution -------------", "count") < 0)
+ return (-1);
+
+ for (i = first_bin; i <= last_bin; i++) {
+ char c[32];
+ int err;
+
+ if (i == 0) {
+ (void) snprintf(c, sizeof (c), "< %d", base);
+ err = dt_printf(dtp, fp, "%16s ", c);
+ } else if (i == levels + 1) {
+ (void) snprintf(c, sizeof (c), ">= %d",
+ base + (levels * step));
+ err = dt_printf(dtp, fp, "%16s ", c);
+ } else {
+ err = dt_printf(dtp, fp, "%16d ",
+ base + (i - 1) * step);
+ }
+
+ if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal,
+ total, positives, negatives) < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+dt_print_lquantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+ size_t size, const dtrace_aggdata_t *aggdata)
+{
+ const int64_t *data = addr;
+ long double total = 0, count = 0;
+ int min, max, base, err;
+ uint64_t arg;
+ uint16_t step, levels;
+ char c[32];
+ unsigned int i;
+
+ if (size < sizeof (uint64_t))
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ arg = *data++;
+ size -= sizeof (uint64_t);
+
+ base = DTRACE_LQUANTIZE_BASE(arg);
+ step = DTRACE_LQUANTIZE_STEP(arg);
+ levels = DTRACE_LQUANTIZE_LEVELS(arg);
+
+ if (size != sizeof (uint64_t) * (levels + 2))
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ min = 0;
+ max = levels + 1;
+
+ if (min == 0) {
+ (void) snprintf(c, sizeof (c), "< %d", base);
+ err = dt_printf(dtp, fp, "%8s :", c);
+ } else {
+ err = dt_printf(dtp, fp, "%8d :", base + (min - 1) * step);
+ }
+
+ if (err < 0)
+ return (-1);
+
+ for (i = min; i <= max; i++) {
+ dt_quantize_total(dtp, data[i], &total);
+ count += data[i];
+ }
+
+ for (i = min; i <= max; i++) {
+ if (dt_print_packed(dtp, fp, data[i], total) < 0)
+ return (-1);
+ }
+
+ (void) snprintf(c, sizeof (c), ">= %d", base + (levels * step));
+ return (dt_printf(dtp, fp, ": %-8s | %lld\n", c, (long long)count));
+}
+
+int
+dt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+ size_t size, uint64_t normal)
+{
+ int i, first_bin, last_bin, bin = 1, order, levels;
+ uint16_t factor, low, high, nsteps;
+ const int64_t *data = addr;
+ int64_t value = 1, next, step;
+ char positives = 0, negatives = 0;
+ long double total = 0;
+ uint64_t arg;
+ char c[32];
+
+ if (size < sizeof (uint64_t))
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ arg = *data++;
+ size -= sizeof (uint64_t);
+
+ factor = DTRACE_LLQUANTIZE_FACTOR(arg);
+ low = DTRACE_LLQUANTIZE_LOW(arg);
+ high = DTRACE_LLQUANTIZE_HIGH(arg);
+ nsteps = DTRACE_LLQUANTIZE_NSTEP(arg);
+
+ /*
+ * We don't expect to be handed invalid llquantize() parameters here,
+ * but sanity check them (to a degree) nonetheless.
+ */
+ if (size > INT32_MAX || factor < 2 || low >= high ||
+ nsteps == 0 || factor > nsteps)
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ levels = (int)size / sizeof (uint64_t);
+
+ first_bin = 0;
+ last_bin = levels - 1;
+
+ while (first_bin < levels && data[first_bin] == 0)
+ first_bin++;
+
+ if (first_bin == levels) {
+ first_bin = 0;
+ last_bin = 1;
+ } else {
+ if (first_bin > 0)
+ first_bin--;
+
+ while (last_bin > 0 && data[last_bin] == 0)
+ last_bin--;
+
+ if (last_bin < levels - 1)
+ last_bin++;
+ }
+
+ for (i = first_bin; i <= last_bin; i++) {
+ positives |= (data[i] > 0);
+ negatives |= (data[i] < 0);
+ dt_quantize_total(dtp, data[i], &total);
+ }
+
+ if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
+ "------------- Distribution -------------", "count") < 0)
+ return (-1);
+
+ for (order = 0; order < low; order++)
+ value *= factor;
+
+ next = value * factor;
+ step = next > nsteps ? next / nsteps : 1;
+
+ if (first_bin == 0) {
+ (void) snprintf(c, sizeof (c), "< %lld", (long long)value);
+
+ if (dt_printf(dtp, fp, "%16s ", c) < 0)
+ return (-1);
+
+ if (dt_print_quantline(dtp, fp, data[0], normal,
+ total, positives, negatives) < 0)
+ return (-1);
+ }
+
+ while (order <= high) {
+ if (bin >= first_bin && bin <= last_bin) {
+ if (dt_printf(dtp, fp, "%16lld ", (long long)value) < 0)
+ return (-1);
+
+ if (dt_print_quantline(dtp, fp, data[bin],
+ normal, total, positives, negatives) < 0)
+ return (-1);
+ }
+
+ assert(value < next);
+ bin++;
+
+ if ((value += step) != next)
+ continue;
+
+ next = value * factor;
+ step = next > nsteps ? next / nsteps : 1;
+ order++;
+ }
+
+ if (last_bin < bin)
+ return (0);
+
+ assert(last_bin == bin);
+ (void) snprintf(c, sizeof (c), ">= %lld", (long long)value);
+
+ if (dt_printf(dtp, fp, "%16s ", c) < 0)
+ return (-1);
+
+ return (dt_print_quantline(dtp, fp, data[bin], normal,
+ total, positives, negatives));
+}
+
+/*ARGSUSED*/
+static int
+dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
+ size_t size, uint64_t normal)
+{
+ /* LINTED - alignment */
+ int64_t *data = (int64_t *)addr;
+
+ return (dt_printf(dtp, fp, " %16lld", data[0] ?
+ (long long)(data[1] / (int64_t)normal / data[0]) : 0));
+}
+
+/*ARGSUSED*/
+static int
+dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
+ size_t size, uint64_t normal)
+{
+ /* LINTED - alignment */
+ uint64_t *data = (uint64_t *)addr;
+
+ return (dt_printf(dtp, fp, " %16llu", data[0] ?
+ (unsigned long long) dt_stddev(data, normal) : 0));
+}
+
+/*ARGSUSED*/
+static int
+dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
+ size_t nbytes, int width, int quiet, int forceraw)
+{
+ /*
+ * If the byte stream is a series of printable characters, followed by
+ * a terminating byte, we print it out as a string. Otherwise, we
+ * assume that it's something else and just print the bytes.
+ */
+ int i, j, margin = 5;
+ char *c = (char *)addr;
+
+ if (nbytes == 0)
+ return (0);
+
+ if (forceraw)
+ goto raw;
+
+ if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
+ goto raw;
+
+ for (i = 0; i < nbytes; i++) {
+ /*
+ * We define a "printable character" to be one for which
+ * isprint(3C) returns non-zero, isspace(3C) returns non-zero,
+ * or a character which is either backspace or the bell.
+ * Backspace and the bell are regrettably special because
+ * they fail the first two tests -- and yet they are entirely
+ * printable. These are the only two control characters that
+ * have meaning for the terminal and for which isprint(3C) and
+ * isspace(3C) return 0.
+ */
+ if (isprint(c[i]) || isspace(c[i]) ||
+ c[i] == '\b' || c[i] == '\a')
+ continue;
+
+ if (c[i] == '\0' && i > 0) {
+ /*
+ * This looks like it might be a string. Before we
+ * assume that it is indeed a string, check the
+ * remainder of the byte range; if it contains
+ * additional non-nul characters, we'll assume that
+ * it's a binary stream that just happens to look like
+ * a string, and we'll print out the individual bytes.
+ */
+ for (j = i + 1; j < nbytes; j++) {
+ if (c[j] != '\0')
+ break;
+ }
+
+ if (j != nbytes)
+ break;
+
+ if (quiet) {
+ return (dt_printf(dtp, fp, "%s", c));
+ } else {
+ return (dt_printf(dtp, fp, " %s%*s",
+ width < 0 ? " " : "", width, c));
+ }
+ }
+
+ break;
+ }
+
+ if (i == nbytes) {
+ /*
+ * The byte range is all printable characters, but there is
+ * no trailing nul byte. We'll assume that it's a string and
+ * print it as such.
+ */
+ char *s = alloca(nbytes + 1);
+ bcopy(c, s, nbytes);
+ s[nbytes] = '\0';
+ return (dt_printf(dtp, fp, " %-*s", width, s));
+ }
+
+raw:
+ if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0)
+ return (-1);
+
+ for (i = 0; i < 16; i++)
+ if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0)
+ return (-1);
+
+ if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0)
+ return (-1);
+
+
+ for (i = 0; i < nbytes; i += 16) {
+ if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0)
+ return (-1);
+
+ for (j = i; j < i + 16 && j < nbytes; j++) {
+ if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0)
+ return (-1);
+ }
+
+ while (j++ % 16) {
+ if (dt_printf(dtp, fp, " ") < 0)
+ return (-1);
+ }
+
+ if (dt_printf(dtp, fp, " ") < 0)
+ return (-1);
+
+ for (j = i; j < i + 16 && j < nbytes; j++) {
+ if (dt_printf(dtp, fp, "%c",
+ c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0)
+ return (-1);
+ }
+
+ if (dt_printf(dtp, fp, "\n") < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ caddr_t addr, int depth, int size)
+{
+ dtrace_syminfo_t dts;
+ GElf_Sym sym;
+ int i, indent;
+ char c[PATH_MAX * 2];
+ uint64_t pc;
+
+ if (dt_printf(dtp, fp, "\n") < 0)
+ return (-1);
+
+ if (format == NULL)
+ format = "%s";
+
+ if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
+ indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
+ else
+ indent = _dtrace_stkindent;
+
+ for (i = 0; i < depth; i++) {
+ switch (size) {
+ case sizeof (uint32_t):
+ /* LINTED - alignment */
+ pc = *((uint32_t *)addr);
+ break;
+
+ case sizeof (uint64_t):
+ /* LINTED - alignment */
+ pc = *((uint64_t *)addr);
+ break;
+
+ default:
+ return (dt_set_errno(dtp, EDT_BADSTACKPC));
+ }
+
+ if (pc == 0)
+ break;
+
+ addr += size;
+
+ if (dt_printf(dtp, fp, "%*s", indent, "") < 0)
+ return (-1);
+
+ if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
+ if (pc > sym.st_value) {
+ (void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
+ dts.dts_object, dts.dts_name,
+ (u_longlong_t)(pc - sym.st_value));
+ } else {
+ (void) snprintf(c, sizeof (c), "%s`%s",
+ dts.dts_object, dts.dts_name);
+ }
+ } else {
+ /*
+ * We'll repeat the lookup, but this time we'll specify
+ * a NULL GElf_Sym -- indicating that we're only
+ * interested in the containing module.
+ */
+ if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
+ (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ dts.dts_object, (u_longlong_t)pc);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx",
+ (u_longlong_t)pc);
+ }
+ }
+
+ if (dt_printf(dtp, fp, format, c) < 0)
+ return (-1);
+
+ if (dt_printf(dtp, fp, "\n") < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ caddr_t addr, uint64_t arg)
+{
+ /* LINTED - alignment */
+ uint64_t *pc = (uint64_t *)addr;
+ uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
+ uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
+ const char *strbase = addr + (depth + 1) * sizeof (uint64_t);
+ const char *str = strsize ? strbase : NULL;
+ int err = 0;
+
+ char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
+ struct ps_prochandle *P;
+ GElf_Sym sym;
+ int i, indent;
+ pid_t pid;
+
+ if (depth == 0)
+ return (0);
+
+ pid = (pid_t)*pc++;
+
+ if (dt_printf(dtp, fp, "\n") < 0)
+ return (-1);
+
+ if (format == NULL)
+ format = "%s";
+
+ if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
+ indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
+ else
+ indent = _dtrace_stkindent;
+
+ /*
+ * Ultimately, we need to add an entry point in the library vector for
+ * determining <symbol, offset> from <pid, address>. For now, if
+ * this is a vector open, we just print the raw address or string.
+ */
+ if (dtp->dt_vector == NULL)
+ P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
+ else
+ P = NULL;
+
+ if (P != NULL)
+ dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
+
+ for (i = 0; i < depth && pc[i] != 0; i++) {
+ const prmap_t *map;
+
+ if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
+ break;
+
+ if (P != NULL && Plookup_by_addr(P, pc[i],
+ name, sizeof (name), &sym) == 0) {
+ (void) Pobjname(P, pc[i], objname, sizeof (objname));
+
+ if (pc[i] > sym.st_value) {
+ (void) snprintf(c, sizeof (c),
+ "%s`%s+0x%llx", dt_basename(objname), name,
+ (u_longlong_t)(pc[i] - sym.st_value));
+ } else {
+ (void) snprintf(c, sizeof (c),
+ "%s`%s", dt_basename(objname), name);
+ }
+ } else if (str != NULL && str[0] != '\0' && str[0] != '@' &&
+ (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
+ (map->pr_mflags & MA_WRITE)))) {
+ /*
+ * If the current string pointer in the string table
+ * does not point to an empty string _and_ the program
+ * counter falls in a writable region, we'll use the
+ * string from the string table instead of the raw
+ * address. This last condition is necessary because
+ * some (broken) ustack helpers will return a string
+ * even for a program counter that they can't
+ * identify. If we have a string for a program
+ * counter that falls in a segment that isn't
+ * writable, we assume that we have fallen into this
+ * case and we refuse to use the string.
+ */
+ (void) snprintf(c, sizeof (c), "%s", str);
+ } else {
+ if (P != NULL && Pobjname(P, pc[i], objname,
+ sizeof (objname)) != 0) {
+ (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ dt_basename(objname), (u_longlong_t)pc[i]);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx",
+ (u_longlong_t)pc[i]);
+ }
+ }
+
+ if ((err = dt_printf(dtp, fp, format, c)) < 0)
+ break;
+
+ if ((err = dt_printf(dtp, fp, "\n")) < 0)
+ break;
+
+ if (str != NULL && str[0] == '@') {
+ /*
+ * If the first character of the string is an "at" sign,
+ * then the string is inferred to be an annotation --
+ * and it is printed out beneath the frame and offset
+ * with brackets.
+ */
+ if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
+ break;
+
+ (void) snprintf(c, sizeof (c), " [ %s ]", &str[1]);
+
+ if ((err = dt_printf(dtp, fp, format, c)) < 0)
+ break;
+
+ if ((err = dt_printf(dtp, fp, "\n")) < 0)
+ break;
+ }
+
+ if (str != NULL) {
+ str += strlen(str) + 1;
+ if (str - strbase >= strsize)
+ str = NULL;
+ }
+ }
+
+ if (P != NULL) {
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+ }
+
+ return (err);
+}
+
+static int
+dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act)
+{
+ /* LINTED - alignment */
+ uint64_t pid = ((uint64_t *)addr)[0];
+ /* LINTED - alignment */
+ uint64_t pc = ((uint64_t *)addr)[1];
+ const char *format = " %-50s";
+ char *s;
+ int n, len = 256;
+
+ if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) {
+ struct ps_prochandle *P;
+
+ if ((P = dt_proc_grab(dtp, pid,
+ PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) {
+ GElf_Sym sym;
+
+ dt_proc_lock(dtp, P);
+
+ if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0)
+ pc = sym.st_value;
+
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+ }
+ }
+
+ do {
+ n = len;
+ s = alloca(n);
+ } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) > n);
+
+ return (dt_printf(dtp, fp, format, s));
+}
+
+int
+dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
+{
+ /* LINTED - alignment */
+ uint64_t pid = ((uint64_t *)addr)[0];
+ /* LINTED - alignment */
+ uint64_t pc = ((uint64_t *)addr)[1];
+ int err = 0;
+
+ char objname[PATH_MAX], c[PATH_MAX * 2];
+ struct ps_prochandle *P;
+
+ if (format == NULL)
+ format = " %-50s";
+
+ /*
+ * See the comment in dt_print_ustack() for the rationale for
+ * printing raw addresses in the vectored case.
+ */
+ if (dtp->dt_vector == NULL)
+ P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
+ else
+ P = NULL;
+
+ if (P != NULL)
+ dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
+
+ if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != 0) {
+ (void) snprintf(c, sizeof (c), "%s", dt_basename(objname));
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
+ }
+
+ err = dt_printf(dtp, fp, format, c);
+
+ if (P != NULL) {
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+ }
+
+ return (err);
+}
+
+static int
+dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
+{
+ /* LINTED - alignment */
+ uint64_t pc = *((uint64_t *)addr);
+ dtrace_syminfo_t dts;
+ GElf_Sym sym;
+ char c[PATH_MAX * 2];
+
+ if (format == NULL)
+ format = " %-50s";
+
+ if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
+ (void) snprintf(c, sizeof (c), "%s`%s",
+ dts.dts_object, dts.dts_name);
+ } else {
+ /*
+ * We'll repeat the lookup, but this time we'll specify a
+ * NULL GElf_Sym -- indicating that we're only interested in
+ * the containing module.
+ */
+ if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
+ (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ dts.dts_object, (u_longlong_t)pc);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx",
+ (u_longlong_t)pc);
+ }
+ }
+
+ if (dt_printf(dtp, fp, format, c) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
+{
+ /* LINTED - alignment */
+ uint64_t pc = *((uint64_t *)addr);
+ dtrace_syminfo_t dts;
+ char c[PATH_MAX * 2];
+
+ if (format == NULL)
+ format = " %-50s";
+
+ if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
+ (void) snprintf(c, sizeof (c), "%s", dts.dts_object);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
+ }
+
+ if (dt_printf(dtp, fp, format, c) < 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+dt_print_memory(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr)
+{
+ int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
+ size_t nbytes = *((uintptr_t *) addr);
+
+ return (dt_print_bytes(dtp, fp, addr + sizeof(uintptr_t),
+ nbytes, 50, quiet, 1));
+}
+
+typedef struct dt_normal {
+ dtrace_aggvarid_t dtnd_id;
+ uint64_t dtnd_normal;
+} dt_normal_t;
+
+static int
+dt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
+{
+ dt_normal_t *normal = arg;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ dtrace_aggvarid_t id = normal->dtnd_id;
+
+ if (agg->dtagd_nrecs == 0)
+ return (DTRACE_AGGWALK_NEXT);
+
+ if (agg->dtagd_varid != id)
+ return (DTRACE_AGGWALK_NEXT);
+
+ ((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal;
+ return (DTRACE_AGGWALK_NORMALIZE);
+}
+
+static int
+dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
+{
+ dt_normal_t normal;
+ caddr_t addr;
+
+ /*
+ * We (should) have two records: the aggregation ID followed by the
+ * normalization value.
+ */
+ addr = base + rec->dtrd_offset;
+
+ if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
+ return (dt_set_errno(dtp, EDT_BADNORMAL));
+
+ /* LINTED - alignment */
+ normal.dtnd_id = *((dtrace_aggvarid_t *)addr);
+ rec++;
+
+ if (rec->dtrd_action != DTRACEACT_LIBACT)
+ return (dt_set_errno(dtp, EDT_BADNORMAL));
+
+ if (rec->dtrd_arg != DT_ACT_NORMALIZE)
+ return (dt_set_errno(dtp, EDT_BADNORMAL));
+
+ addr = base + rec->dtrd_offset;
+
+ switch (rec->dtrd_size) {
+ case sizeof (uint64_t):
+ /* LINTED - alignment */
+ normal.dtnd_normal = *((uint64_t *)addr);
+ break;
+ case sizeof (uint32_t):
+ /* LINTED - alignment */
+ normal.dtnd_normal = *((uint32_t *)addr);
+ break;
+ case sizeof (uint16_t):
+ /* LINTED - alignment */
+ normal.dtnd_normal = *((uint16_t *)addr);
+ break;
+ case sizeof (uint8_t):
+ normal.dtnd_normal = *((uint8_t *)addr);
+ break;
+ default:
+ return (dt_set_errno(dtp, EDT_BADNORMAL));
+ }
+
+ (void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal);
+
+ return (0);
+}
+
+static int
+dt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
+{
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
+
+ if (agg->dtagd_nrecs == 0)
+ return (DTRACE_AGGWALK_NEXT);
+
+ if (agg->dtagd_varid != id)
+ return (DTRACE_AGGWALK_NEXT);
+
+ return (DTRACE_AGGWALK_DENORMALIZE);
+}
+
+static int
+dt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg)
+{
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
+
+ if (agg->dtagd_nrecs == 0)
+ return (DTRACE_AGGWALK_NEXT);
+
+ if (agg->dtagd_varid != id)
+ return (DTRACE_AGGWALK_NEXT);
+
+ return (DTRACE_AGGWALK_CLEAR);
+}
+
+typedef struct dt_trunc {
+ dtrace_aggvarid_t dttd_id;
+ uint64_t dttd_remaining;
+} dt_trunc_t;
+
+static int
+dt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg)
+{
+ dt_trunc_t *trunc = arg;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ dtrace_aggvarid_t id = trunc->dttd_id;
+
+ if (agg->dtagd_nrecs == 0)
+ return (DTRACE_AGGWALK_NEXT);
+
+ if (agg->dtagd_varid != id)
+ return (DTRACE_AGGWALK_NEXT);
+
+ if (trunc->dttd_remaining == 0)
+ return (DTRACE_AGGWALK_REMOVE);
+
+ trunc->dttd_remaining--;
+ return (DTRACE_AGGWALK_NEXT);
+}
+
+static int
+dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
+{
+ dt_trunc_t trunc;
+ caddr_t addr;
+ int64_t remaining;
+ int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *);
+
+ /*
+ * We (should) have two records: the aggregation ID followed by the
+ * number of aggregation entries after which the aggregation is to be
+ * truncated.
+ */
+ addr = base + rec->dtrd_offset;
+
+ if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
+ return (dt_set_errno(dtp, EDT_BADTRUNC));
+
+ /* LINTED - alignment */
+ trunc.dttd_id = *((dtrace_aggvarid_t *)addr);
+ rec++;
+
+ if (rec->dtrd_action != DTRACEACT_LIBACT)
+ return (dt_set_errno(dtp, EDT_BADTRUNC));
+
+ if (rec->dtrd_arg != DT_ACT_TRUNC)
+ return (dt_set_errno(dtp, EDT_BADTRUNC));
+
+ addr = base + rec->dtrd_offset;
+
+ switch (rec->dtrd_size) {
+ case sizeof (uint64_t):
+ /* LINTED - alignment */
+ remaining = *((int64_t *)addr);
+ break;
+ case sizeof (uint32_t):
+ /* LINTED - alignment */
+ remaining = *((int32_t *)addr);
+ break;
+ case sizeof (uint16_t):
+ /* LINTED - alignment */
+ remaining = *((int16_t *)addr);
+ break;
+ case sizeof (uint8_t):
+ remaining = *((int8_t *)addr);
+ break;
+ default:
+ return (dt_set_errno(dtp, EDT_BADNORMAL));
+ }
+
+ if (remaining < 0) {
+ func = dtrace_aggregate_walk_valsorted;
+ remaining = -remaining;
+ } else {
+ func = dtrace_aggregate_walk_valrevsorted;
+ }
+
+ assert(remaining >= 0);
+ trunc.dttd_remaining = remaining;
+
+ (void) func(dtp, dt_trunc_agg, &trunc);
+
+ return (0);
+}
+
+static int
+dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec,
+ caddr_t addr, size_t size, const dtrace_aggdata_t *aggdata,
+ uint64_t normal, dt_print_aggdata_t *pd)
+{
+ int err, width;
+ dtrace_actkind_t act = rec->dtrd_action;
+ boolean_t packed = pd->dtpa_agghist || pd->dtpa_aggpack;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+
+ static struct {
+ size_t size;
+ int width;
+ int packedwidth;
+ } *fmt, fmttab[] = {
+ { sizeof (uint8_t), 3, 3 },
+ { sizeof (uint16_t), 5, 5 },
+ { sizeof (uint32_t), 8, 8 },
+ { sizeof (uint64_t), 16, 16 },
+ { 0, -50, 16 }
+ };
+
+ if (packed && pd->dtpa_agghisthdr != agg->dtagd_varid) {
+ dtrace_recdesc_t *r;
+
+ width = 0;
+
+ /*
+ * To print our quantization header for either an agghist or
+ * aggpack aggregation, we need to iterate through all of our
+ * of our records to determine their width.
+ */
+ for (r = rec; !DTRACEACT_ISAGG(r->dtrd_action); r++) {
+ for (fmt = fmttab; fmt->size &&
+ fmt->size != r->dtrd_size; fmt++)
+ continue;
+
+ width += fmt->packedwidth + 1;
+ }
+
+ if (pd->dtpa_agghist) {
+ if (dt_print_quanthdr(dtp, fp, width) < 0)
+ return (-1);
+ } else {
+ if (dt_print_quanthdr_packed(dtp, fp,
+ width, aggdata, r->dtrd_action) < 0)
+ return (-1);
+ }
+
+ pd->dtpa_agghisthdr = agg->dtagd_varid;
+ }
+
+ if (pd->dtpa_agghist && DTRACEACT_ISAGG(act)) {
+ char positives = aggdata->dtada_flags & DTRACE_A_HASPOSITIVES;
+ char negatives = aggdata->dtada_flags & DTRACE_A_HASNEGATIVES;
+ int64_t val;
+
+ assert(act == DTRACEAGG_SUM || act == DTRACEAGG_COUNT);
+ val = (long long)*((uint64_t *)addr);
+
+ if (dt_printf(dtp, fp, " ") < 0)
+ return (-1);
+
+ return (dt_print_quantline(dtp, fp, val, normal,
+ aggdata->dtada_total, positives, negatives));
+ }
+
+ if (pd->dtpa_aggpack && DTRACEACT_ISAGG(act)) {
+ switch (act) {
+ case DTRACEAGG_QUANTIZE:
+ return (dt_print_quantize_packed(dtp,
+ fp, addr, size, aggdata));
+ case DTRACEAGG_LQUANTIZE:
+ return (dt_print_lquantize_packed(dtp,
+ fp, addr, size, aggdata));
+ default:
+ break;
+ }
+ }
+
+ switch (act) {
+ case DTRACEACT_STACK:
+ return (dt_print_stack(dtp, fp, NULL, addr,
+ rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg));
+
+ case DTRACEACT_USTACK:
+ case DTRACEACT_JSTACK:
+ return (dt_print_ustack(dtp, fp, NULL, addr, rec->dtrd_arg));
+
+ case DTRACEACT_USYM:
+ case DTRACEACT_UADDR:
+ return (dt_print_usym(dtp, fp, addr, act));
+
+ case DTRACEACT_UMOD:
+ return (dt_print_umod(dtp, fp, NULL, addr));
+
+ case DTRACEACT_SYM:
+ return (dt_print_sym(dtp, fp, NULL, addr));
+
+ case DTRACEACT_MOD:
+ return (dt_print_mod(dtp, fp, NULL, addr));
+
+ case DTRACEAGG_QUANTIZE:
+ return (dt_print_quantize(dtp, fp, addr, size, normal));
+
+ case DTRACEAGG_LQUANTIZE:
+ return (dt_print_lquantize(dtp, fp, addr, size, normal));
+
+ case DTRACEAGG_LLQUANTIZE:
+ return (dt_print_llquantize(dtp, fp, addr, size, normal));
+
+ case DTRACEAGG_AVG:
+ return (dt_print_average(dtp, fp, addr, size, normal));
+
+ case DTRACEAGG_STDDEV:
+ return (dt_print_stddev(dtp, fp, addr, size, normal));
+
+ default:
+ break;
+ }
+
+ for (fmt = fmttab; fmt->size && fmt->size != size; fmt++)
+ continue;
+
+ width = packed ? fmt->packedwidth : fmt->width;
+
+ switch (size) {
+ case sizeof (uint64_t):
+ err = dt_printf(dtp, fp, " %*lld", width,
+ /* LINTED - alignment */
+ (long long)*((uint64_t *)addr) / normal);
+ break;
+ case sizeof (uint32_t):
+ /* LINTED - alignment */
+ err = dt_printf(dtp, fp, " %*d", width, *((uint32_t *)addr) /
+ (uint32_t)normal);
+ break;
+ case sizeof (uint16_t):
+ /* LINTED - alignment */
+ err = dt_printf(dtp, fp, " %*d", width, *((uint16_t *)addr) /
+ (uint32_t)normal);
+ break;
+ case sizeof (uint8_t):
+ err = dt_printf(dtp, fp, " %*d", width, *((uint8_t *)addr) /
+ (uint32_t)normal);
+ break;
+ default:
+ err = dt_print_bytes(dtp, fp, addr, size, width, 0, 0);
+ break;
+ }
+
+ return (err);
+}
+
+int
+dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
+{
+ int i, aggact = 0;
+ dt_print_aggdata_t *pd = arg;
+ const dtrace_aggdata_t *aggdata = aggsdata[0];
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ FILE *fp = pd->dtpa_fp;
+ dtrace_hdl_t *dtp = pd->dtpa_dtp;
+ dtrace_recdesc_t *rec;
+ dtrace_actkind_t act;
+ caddr_t addr;
+ size_t size;
+
+ pd->dtpa_agghist = (aggdata->dtada_flags & DTRACE_A_TOTAL);
+ pd->dtpa_aggpack = (aggdata->dtada_flags & DTRACE_A_MINMAXBIN);
+
+ /*
+ * Iterate over each record description in the key, printing the traced
+ * data, skipping the first datum (the tuple member created by the
+ * compiler).
+ */
+ for (i = 1; i < agg->dtagd_nrecs; i++) {
+ rec = &agg->dtagd_rec[i];
+ act = rec->dtrd_action;
+ addr = aggdata->dtada_data + rec->dtrd_offset;
+ size = rec->dtrd_size;
+
+ if (DTRACEACT_ISAGG(act)) {
+ aggact = i;
+ break;
+ }
+
+ if (dt_print_datum(dtp, fp, rec, addr,
+ size, aggdata, 1, pd) < 0)
+ return (-1);
+
+ if (dt_buffered_flush(dtp, NULL, rec, aggdata,
+ DTRACE_BUFDATA_AGGKEY) < 0)
+ return (-1);
+ }
+
+ assert(aggact != 0);
+
+ for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) {
+ uint64_t normal;
+
+ aggdata = aggsdata[i];
+ agg = aggdata->dtada_desc;
+ rec = &agg->dtagd_rec[aggact];
+ act = rec->dtrd_action;
+ addr = aggdata->dtada_data + rec->dtrd_offset;
+ size = rec->dtrd_size;
+
+ assert(DTRACEACT_ISAGG(act));
+ normal = aggdata->dtada_normal;
+
+ if (dt_print_datum(dtp, fp, rec, addr,
+ size, aggdata, normal, pd) < 0)
+ return (-1);
+
+ if (dt_buffered_flush(dtp, NULL, rec, aggdata,
+ DTRACE_BUFDATA_AGGVAL) < 0)
+ return (-1);
+
+ if (!pd->dtpa_allunprint)
+ agg->dtagd_flags |= DTRACE_AGD_PRINTED;
+ }
+
+ if (!pd->dtpa_agghist && !pd->dtpa_aggpack) {
+ if (dt_printf(dtp, fp, "\n") < 0)
+ return (-1);
+ }
+
+ if (dt_buffered_flush(dtp, NULL, NULL, aggdata,
+ DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg)
+{
+ dt_print_aggdata_t *pd = arg;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ dtrace_aggvarid_t aggvarid = pd->dtpa_id;
+
+ if (pd->dtpa_allunprint) {
+ if (agg->dtagd_flags & DTRACE_AGD_PRINTED)
+ return (0);
+ } else {
+ /*
+ * If we're not printing all unprinted aggregations, then the
+ * aggregation variable ID denotes a specific aggregation
+ * variable that we should print -- skip any other aggregations
+ * that we encounter.
+ */
+ if (agg->dtagd_nrecs == 0)
+ return (0);
+
+ if (aggvarid != agg->dtagd_varid)
+ return (0);
+ }
+
+ return (dt_print_aggs(&aggdata, 1, arg));
+}
+
+int
+dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
+ const char *option, const char *value)
+{
+ int len, rval;
+ char *msg;
+ const char *errstr;
+ dtrace_setoptdata_t optdata;
+
+ bzero(&optdata, sizeof (optdata));
+ (void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval);
+
+ if (dtrace_setopt(dtp, option, value) == 0) {
+ (void) dtrace_getopt(dtp, option, &optdata.dtsda_newval);
+ optdata.dtsda_probe = data;
+ optdata.dtsda_option = option;
+ optdata.dtsda_handle = dtp;
+
+ if ((rval = dt_handle_setopt(dtp, &optdata)) != 0)
+ return (rval);
+
+ return (0);
+ }
+
+ errstr = dtrace_errmsg(dtp, dtrace_errno(dtp));
+ len = strlen(option) + strlen(value) + strlen(errstr) + 80;
+ msg = alloca(len);
+
+ (void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n",
+ option, value, errstr);
+
+ if ((rval = dt_handle_liberr(dtp, data, msg)) == 0)
+ return (0);
+
+ return (rval);
+}
+
+static int
+dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu,
+ dtrace_bufdesc_t *buf, boolean_t just_one,
+ dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg)
+{
+ dtrace_epid_t id;
+ size_t offs;
+ int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET);
+ int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
+ int rval, i, n;
+ uint64_t tracememsize = 0;
+ dtrace_probedata_t data;
+ uint64_t drops;
+
+ bzero(&data, sizeof (data));
+ data.dtpda_handle = dtp;
+ data.dtpda_cpu = cpu;
+ data.dtpda_flow = dtp->dt_flow;
+ data.dtpda_indent = dtp->dt_indent;
+ data.dtpda_prefix = dtp->dt_prefix;
+
+ for (offs = buf->dtbd_oldest; offs < buf->dtbd_size; ) {
+ dtrace_eprobedesc_t *epd;
+
+ /*
+ * We're guaranteed to have an ID.
+ */
+ id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
+
+ if (id == DTRACE_EPIDNONE) {
+ /*
+ * This is filler to assure proper alignment of the
+ * next record; we simply ignore it.
+ */
+ offs += sizeof (id);
+ continue;
+ }
+
+ if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc,
+ &data.dtpda_pdesc)) != 0)
+ return (rval);
+
+ epd = data.dtpda_edesc;
+ data.dtpda_data = buf->dtbd_data + offs;
+
+ if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) {
+ rval = dt_handle(dtp, &data);
+
+ if (rval == DTRACE_CONSUME_NEXT)
+ goto nextepid;
+
+ if (rval == DTRACE_CONSUME_ERROR)
+ return (-1);
+ }
+
+ if (flow)
+ (void) dt_flowindent(dtp, &data, dtp->dt_last_epid,
+ buf, offs);
+
+ rval = (*efunc)(&data, arg);
+
+ if (flow) {
+ if (data.dtpda_flow == DTRACEFLOW_ENTRY)
+ data.dtpda_indent += 2;
+ }
+
+ if (rval == DTRACE_CONSUME_NEXT)
+ goto nextepid;
+
+ if (rval == DTRACE_CONSUME_ABORT)
+ return (dt_set_errno(dtp, EDT_DIRABORT));
+
+ if (rval != DTRACE_CONSUME_THIS)
+ return (dt_set_errno(dtp, EDT_BADRVAL));
+
+ for (i = 0; i < epd->dtepd_nrecs; i++) {
+ caddr_t addr;
+ dtrace_recdesc_t *rec = &epd->dtepd_rec[i];
+ dtrace_actkind_t act = rec->dtrd_action;
+
+ data.dtpda_data = buf->dtbd_data + offs +
+ rec->dtrd_offset;
+ addr = data.dtpda_data;
+
+ if (act == DTRACEACT_LIBACT) {
+ uint64_t arg = rec->dtrd_arg;
+ dtrace_aggvarid_t id;
+
+ switch (arg) {
+ case DT_ACT_CLEAR:
+ /* LINTED - alignment */
+ id = *((dtrace_aggvarid_t *)addr);
+ (void) dtrace_aggregate_walk(dtp,
+ dt_clear_agg, &id);
+ continue;
+
+ case DT_ACT_DENORMALIZE:
+ /* LINTED - alignment */
+ id = *((dtrace_aggvarid_t *)addr);
+ (void) dtrace_aggregate_walk(dtp,
+ dt_denormalize_agg, &id);
+ continue;
+
+ case DT_ACT_FTRUNCATE:
+ if (fp == NULL)
+ continue;
+
+ (void) fflush(fp);
+ (void) ftruncate(fileno(fp), 0);
+ (void) fseeko(fp, 0, SEEK_SET);
+ continue;
+
+ case DT_ACT_NORMALIZE:
+ if (i == epd->dtepd_nrecs - 1)
+ return (dt_set_errno(dtp,
+ EDT_BADNORMAL));
+
+ if (dt_normalize(dtp,
+ buf->dtbd_data + offs, rec) != 0)
+ return (-1);
+
+ i++;
+ continue;
+
+ case DT_ACT_SETOPT: {
+ uint64_t *opts = dtp->dt_options;
+ dtrace_recdesc_t *valrec;
+ uint32_t valsize;
+ caddr_t val;
+ int rv;
+
+ if (i == epd->dtepd_nrecs - 1) {
+ return (dt_set_errno(dtp,
+ EDT_BADSETOPT));
+ }
+
+ valrec = &epd->dtepd_rec[++i];
+ valsize = valrec->dtrd_size;
+
+ if (valrec->dtrd_action != act ||
+ valrec->dtrd_arg != arg) {
+ return (dt_set_errno(dtp,
+ EDT_BADSETOPT));
+ }
+
+ if (valsize > sizeof (uint64_t)) {
+ val = buf->dtbd_data + offs +
+ valrec->dtrd_offset;
+ } else {
+ val = "1";
+ }
+
+ rv = dt_setopt(dtp, &data, addr, val);
+
+ if (rv != 0)
+ return (-1);
+
+ flow = (opts[DTRACEOPT_FLOWINDENT] !=
+ DTRACEOPT_UNSET);
+ quiet = (opts[DTRACEOPT_QUIET] !=
+ DTRACEOPT_UNSET);
+
+ continue;
+ }
+
+ case DT_ACT_TRUNC:
+ if (i == epd->dtepd_nrecs - 1)
+ return (dt_set_errno(dtp,
+ EDT_BADTRUNC));
+
+ if (dt_trunc(dtp,
+ buf->dtbd_data + offs, rec) != 0)
+ return (-1);
+
+ i++;
+ continue;
+
+ default:
+ continue;
+ }
+ }
+
+ if (act == DTRACEACT_TRACEMEM_DYNSIZE &&
+ rec->dtrd_size == sizeof (uint64_t)) {
+ /* LINTED - alignment */
+ tracememsize = *((unsigned long long *)addr);
+ continue;
+ }
+
+ rval = (*rfunc)(&data, rec, arg);
+
+ if (rval == DTRACE_CONSUME_NEXT)
+ continue;
+
+ if (rval == DTRACE_CONSUME_ABORT)
+ return (dt_set_errno(dtp, EDT_DIRABORT));
+
+ if (rval != DTRACE_CONSUME_THIS)
+ return (dt_set_errno(dtp, EDT_BADRVAL));
+
+ if (act == DTRACEACT_STACK) {
+ int depth = rec->dtrd_arg;
+
+ if (dt_print_stack(dtp, fp, NULL, addr, depth,
+ rec->dtrd_size / depth) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_USTACK ||
+ act == DTRACEACT_JSTACK) {
+ if (dt_print_ustack(dtp, fp, NULL,
+ addr, rec->dtrd_arg) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_SYM) {
+ if (dt_print_sym(dtp, fp, NULL, addr) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_MOD) {
+ if (dt_print_mod(dtp, fp, NULL, addr) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) {
+ if (dt_print_usym(dtp, fp, addr, act) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_UMOD) {
+ if (dt_print_umod(dtp, fp, NULL, addr) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_PRINTM) {
+ if (dt_print_memory(dtp, fp, addr) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (DTRACEACT_ISPRINTFLIKE(act)) {
+ void *fmtdata;
+ int (*func)(dtrace_hdl_t *, FILE *, void *,
+ const dtrace_probedata_t *,
+ const dtrace_recdesc_t *, uint_t,
+ const void *buf, size_t);
+
+ if ((fmtdata = dt_format_lookup(dtp,
+ rec->dtrd_format)) == NULL)
+ goto nofmt;
+
+ switch (act) {
+ case DTRACEACT_PRINTF:
+ func = dtrace_fprintf;
+ break;
+ case DTRACEACT_PRINTA:
+ func = dtrace_fprinta;
+ break;
+ case DTRACEACT_SYSTEM:
+ func = dtrace_system;
+ break;
+ case DTRACEACT_FREOPEN:
+ func = dtrace_freopen;
+ break;
+ }
+
+ n = (*func)(dtp, fp, fmtdata, &data,
+ rec, epd->dtepd_nrecs - i,
+ (uchar_t *)buf->dtbd_data + offs,
+ buf->dtbd_size - offs);
+
+ if (n < 0)
+ return (-1); /* errno is set for us */
+
+ if (n > 0)
+ i += n - 1;
+ goto nextrec;
+ }
+
+ /*
+ * If this is a DIF expression, and the record has a
+ * format set, this indicates we have a CTF type name
+ * associated with the data and we should try to print
+ * it out by type.
+ */
+ if (act == DTRACEACT_DIFEXPR) {
+ const char *strdata = dt_strdata_lookup(dtp,
+ rec->dtrd_format);
+ if (strdata != NULL) {
+ n = dtrace_print(dtp, fp, strdata,
+ addr, rec->dtrd_size);
+
+ /*
+ * dtrace_print() will return -1 on
+ * error, or return the number of bytes
+ * consumed. It will return 0 if the
+ * type couldn't be determined, and we
+ * should fall through to the normal
+ * trace method.
+ */
+ if (n < 0)
+ return (-1);
+
+ if (n > 0)
+ goto nextrec;
+ }
+ }
+
+nofmt:
+ if (act == DTRACEACT_PRINTA) {
+ dt_print_aggdata_t pd;
+ dtrace_aggvarid_t *aggvars;
+ int j, naggvars = 0;
+ size_t size = ((epd->dtepd_nrecs - i) *
+ sizeof (dtrace_aggvarid_t));
+
+ if ((aggvars = dt_alloc(dtp, size)) == NULL)
+ return (-1);
+
+ /*
+ * This might be a printa() with multiple
+ * aggregation variables. We need to scan
+ * forward through the records until we find
+ * a record from a different statement.
+ */
+ for (j = i; j < epd->dtepd_nrecs; j++) {
+ dtrace_recdesc_t *nrec;
+ caddr_t naddr;
+
+ nrec = &epd->dtepd_rec[j];
+
+ if (nrec->dtrd_uarg != rec->dtrd_uarg)
+ break;
+
+ if (nrec->dtrd_action != act) {
+ return (dt_set_errno(dtp,
+ EDT_BADAGG));
+ }
+
+ naddr = buf->dtbd_data + offs +
+ nrec->dtrd_offset;
+
+ aggvars[naggvars++] =
+ /* LINTED - alignment */
+ *((dtrace_aggvarid_t *)naddr);
+ }
+
+ i = j - 1;
+ bzero(&pd, sizeof (pd));
+ pd.dtpa_dtp = dtp;
+ pd.dtpa_fp = fp;
+
+ assert(naggvars >= 1);
+
+ if (naggvars == 1) {
+ pd.dtpa_id = aggvars[0];
+ dt_free(dtp, aggvars);
+
+ if (dt_printf(dtp, fp, "\n") < 0 ||
+ dtrace_aggregate_walk_sorted(dtp,
+ dt_print_agg, &pd) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (dt_printf(dtp, fp, "\n") < 0 ||
+ dtrace_aggregate_walk_joined(dtp, aggvars,
+ naggvars, dt_print_aggs, &pd) < 0) {
+ dt_free(dtp, aggvars);
+ return (-1);
+ }
+
+ dt_free(dtp, aggvars);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_TRACEMEM) {
+ if (tracememsize == 0 ||
+ tracememsize > rec->dtrd_size) {
+ tracememsize = rec->dtrd_size;
+ }
+
+ n = dt_print_bytes(dtp, fp, addr,
+ tracememsize, -33, quiet, 1);
+
+ tracememsize = 0;
+
+ if (n < 0)
+ return (-1);
+
+ goto nextrec;
+ }
+
+ switch (rec->dtrd_size) {
+ case sizeof (uint64_t):
+ n = dt_printf(dtp, fp,
+ quiet ? "%lld" : " %16lld",
+ /* LINTED - alignment */
+ *((unsigned long long *)addr));
+ break;
+ case sizeof (uint32_t):
+ n = dt_printf(dtp, fp, quiet ? "%d" : " %8d",
+ /* LINTED - alignment */
+ *((uint32_t *)addr));
+ break;
+ case sizeof (uint16_t):
+ n = dt_printf(dtp, fp, quiet ? "%d" : " %5d",
+ /* LINTED - alignment */
+ *((uint16_t *)addr));
+ break;
+ case sizeof (uint8_t):
+ n = dt_printf(dtp, fp, quiet ? "%d" : " %3d",
+ *((uint8_t *)addr));
+ break;
+ default:
+ n = dt_print_bytes(dtp, fp, addr,
+ rec->dtrd_size, -33, quiet, 0);
+ break;
+ }
+
+ if (n < 0)
+ return (-1); /* errno is set for us */
+
+nextrec:
+ if (dt_buffered_flush(dtp, &data, rec, NULL, 0) < 0)
+ return (-1); /* errno is set for us */
+ }
+
+ /*
+ * Call the record callback with a NULL record to indicate
+ * that we're done processing this EPID.
+ */
+ rval = (*rfunc)(&data, NULL, arg);
+nextepid:
+ offs += epd->dtepd_size;
+ dtp->dt_last_epid = id;
+ if (just_one) {
+ buf->dtbd_oldest = offs;
+ break;
+ }
+ }
+
+ dtp->dt_flow = data.dtpda_flow;
+ dtp->dt_indent = data.dtpda_indent;
+ dtp->dt_prefix = data.dtpda_prefix;
+
+ if ((drops = buf->dtbd_drops) == 0)
+ return (0);
+
+ /*
+ * Explicitly zero the drops to prevent us from processing them again.
+ */
+ buf->dtbd_drops = 0;
+
+ return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops));
+}
+
+/*
+ * Reduce memory usage by shrinking the buffer if it's no more than half full.
+ * Note, we need to preserve the alignment of the data at dtbd_oldest, which is
+ * only 4-byte aligned.
+ */
+static void
+dt_realloc_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf, int cursize)
+{
+ uint64_t used = buf->dtbd_size - buf->dtbd_oldest;
+ if (used < cursize / 2) {
+ int misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1);
+ char *newdata = dt_alloc(dtp, used + misalign);
+ if (newdata == NULL)
+ return;
+ bzero(newdata, misalign);
+ bcopy(buf->dtbd_data + buf->dtbd_oldest,
+ newdata + misalign, used);
+ dt_free(dtp, buf->dtbd_data);
+ buf->dtbd_oldest = misalign;
+ buf->dtbd_size = used + misalign;
+ buf->dtbd_data = newdata;
+ }
+}
+
+/*
+ * If the ring buffer has wrapped, the data is not in order. Rearrange it
+ * so that it is. Note, we need to preserve the alignment of the data at
+ * dtbd_oldest, which is only 4-byte aligned.
+ */
+static int
+dt_unring_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf)
+{
+ int misalign;
+ char *newdata, *ndp;
+
+ if (buf->dtbd_oldest == 0)
+ return (0);
+
+ misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1);
+ newdata = ndp = dt_alloc(dtp, buf->dtbd_size + misalign);
+
+ if (newdata == NULL)
+ return (-1);
+
+ assert(0 == (buf->dtbd_size & (sizeof (uint64_t) - 1)));
+
+ bzero(ndp, misalign);
+ ndp += misalign;
+
+ bcopy(buf->dtbd_data + buf->dtbd_oldest, ndp,
+ buf->dtbd_size - buf->dtbd_oldest);
+ ndp += buf->dtbd_size - buf->dtbd_oldest;
+
+ bcopy(buf->dtbd_data, ndp, buf->dtbd_oldest);
+
+ dt_free(dtp, buf->dtbd_data);
+ buf->dtbd_oldest = 0;
+ buf->dtbd_data = newdata;
+ buf->dtbd_size += misalign;
+
+ return (0);
+}
+
+static void
+dt_put_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf)
+{
+ dt_free(dtp, buf->dtbd_data);
+ dt_free(dtp, buf);
+}
+
+/*
+ * Returns 0 on success, in which case *cbp will be filled in if we retrieved
+ * data, or NULL if there is no data for this CPU.
+ * Returns -1 on failure and sets dt_errno.
+ */
+static int
+dt_get_buf(dtrace_hdl_t *dtp, int cpu, dtrace_bufdesc_t **bufp)
+{
+ dtrace_optval_t size;
+ dtrace_bufdesc_t *buf = dt_zalloc(dtp, sizeof (*buf));
+ int error, rval;
+
+ if (buf == NULL)
+ return (-1);
+
+ (void) dtrace_getopt(dtp, "bufsize", &size);
+ buf->dtbd_data = dt_alloc(dtp, size);
+ if (buf->dtbd_data == NULL) {
+ dt_free(dtp, buf);
+ return (-1);
+ }
+ buf->dtbd_size = size;
+ buf->dtbd_cpu = cpu;
+
+#ifdef illumos
+ if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
+#else
+ if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &buf) == -1) {
+#endif
+ /*
+ * If we failed with ENOENT, it may be because the
+ * CPU was unconfigured -- this is okay. Any other
+ * error, however, is unexpected.
+ */
+ if (errno == ENOENT) {
+ *bufp = NULL;
+ rval = 0;
+ } else
+ rval = dt_set_errno(dtp, errno);
+
+ dt_put_buf(dtp, buf);
+ return (rval);
+ }
+
+ error = dt_unring_buf(dtp, buf);
+ if (error != 0) {
+ dt_put_buf(dtp, buf);
+ return (error);
+ }
+ dt_realloc_buf(dtp, buf, size);
+
+ *bufp = buf;
+ return (0);
+}
+
+typedef struct dt_begin {
+ dtrace_consume_probe_f *dtbgn_probefunc;
+ dtrace_consume_rec_f *dtbgn_recfunc;
+ void *dtbgn_arg;
+ dtrace_handle_err_f *dtbgn_errhdlr;
+ void *dtbgn_errarg;
+ int dtbgn_beginonly;
+} dt_begin_t;
+
+static int
+dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg)
+{
+ dt_begin_t *begin = arg;
+ dtrace_probedesc_t *pd = data->dtpda_pdesc;
+
+ int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
+ int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
+
+ if (begin->dtbgn_beginonly) {
+ if (!(r1 && r2))
+ return (DTRACE_CONSUME_NEXT);
+ } else {
+ if (r1 && r2)
+ return (DTRACE_CONSUME_NEXT);
+ }
+
+ /*
+ * We have a record that we're interested in. Now call the underlying
+ * probe function...
+ */
+ return (begin->dtbgn_probefunc(data, begin->dtbgn_arg));
+}
+
+static int
+dt_consume_begin_record(const dtrace_probedata_t *data,
+ const dtrace_recdesc_t *rec, void *arg)
+{
+ dt_begin_t *begin = arg;
+
+ return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg));
+}
+
+static int
+dt_consume_begin_error(const dtrace_errdata_t *data, void *arg)
+{
+ dt_begin_t *begin = (dt_begin_t *)arg;
+ dtrace_probedesc_t *pd = data->dteda_pdesc;
+
+ int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
+ int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
+
+ if (begin->dtbgn_beginonly) {
+ if (!(r1 && r2))
+ return (DTRACE_HANDLE_OK);
+ } else {
+ if (r1 && r2)
+ return (DTRACE_HANDLE_OK);
+ }
+
+ return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg));
+}
+
+static int
+dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp,
+ dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
+{
+ /*
+ * There's this idea that the BEGIN probe should be processed before
+ * everything else, and that the END probe should be processed after
+ * anything else. In the common case, this is pretty easy to deal
+ * with. However, a situation may arise where the BEGIN enabling and
+ * END enabling are on the same CPU, and some enabling in the middle
+ * occurred on a different CPU. To deal with this (blech!) we need to
+ * consume the BEGIN buffer up until the end of the BEGIN probe, and
+ * then set it aside. We will then process every other CPU, and then
+ * we'll return to the BEGIN CPU and process the rest of the data
+ * (which will inevitably include the END probe, if any). Making this
+ * even more complicated (!) is the library's ERROR enabling. Because
+ * this enabling is processed before we even get into the consume call
+ * back, any ERROR firing would result in the library's ERROR enabling
+ * being processed twice -- once in our first pass (for BEGIN probes),
+ * and again in our second pass (for everything but BEGIN probes). To
+ * deal with this, we interpose on the ERROR handler to assure that we
+ * only process ERROR enablings induced by BEGIN enablings in the
+ * first pass, and that we only process ERROR enablings _not_ induced
+ * by BEGIN enablings in the second pass.
+ */
+
+ dt_begin_t begin;
+ processorid_t cpu = dtp->dt_beganon;
+ int rval, i;
+ static int max_ncpus;
+ dtrace_bufdesc_t *buf;
+
+ dtp->dt_beganon = -1;
+
+ if (dt_get_buf(dtp, cpu, &buf) != 0)
+ return (-1);
+ if (buf == NULL)
+ return (0);
+
+ if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) {
+ /*
+ * This is the simple case. We're either not stopped, or if
+ * we are, we actually processed any END probes on another
+ * CPU. We can simply consume this buffer and return.
+ */
+ rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE,
+ pf, rf, arg);
+ dt_put_buf(dtp, buf);
+ return (rval);
+ }
+
+ begin.dtbgn_probefunc = pf;
+ begin.dtbgn_recfunc = rf;
+ begin.dtbgn_arg = arg;
+ begin.dtbgn_beginonly = 1;
+
+ /*
+ * We need to interpose on the ERROR handler to be sure that we
+ * only process ERRORs induced by BEGIN.
+ */
+ begin.dtbgn_errhdlr = dtp->dt_errhdlr;
+ begin.dtbgn_errarg = dtp->dt_errarg;
+ dtp->dt_errhdlr = dt_consume_begin_error;
+ dtp->dt_errarg = &begin;
+
+ rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE,
+ dt_consume_begin_probe, dt_consume_begin_record, &begin);
+
+ dtp->dt_errhdlr = begin.dtbgn_errhdlr;
+ dtp->dt_errarg = begin.dtbgn_errarg;
+
+ if (rval != 0) {
+ dt_put_buf(dtp, buf);
+ return (rval);
+ }
+
+ if (max_ncpus == 0)
+ max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
+
+ for (i = 0; i < max_ncpus; i++) {
+ dtrace_bufdesc_t *nbuf;
+ if (i == cpu)
+ continue;
+
+ if (dt_get_buf(dtp, i, &nbuf) != 0) {
+ dt_put_buf(dtp, buf);
+ return (-1);
+ }
+ if (nbuf == NULL)
+ continue;
+
+ rval = dt_consume_cpu(dtp, fp, i, nbuf, B_FALSE,
+ pf, rf, arg);
+ dt_put_buf(dtp, nbuf);
+ if (rval != 0) {
+ dt_put_buf(dtp, buf);
+ return (rval);
+ }
+ }
+
+ /*
+ * Okay -- we're done with the other buffers. Now we want to
+ * reconsume the first buffer -- but this time we're looking for
+ * everything _but_ BEGIN. And of course, in order to only consume
+ * those ERRORs _not_ associated with BEGIN, we need to reinstall our
+ * ERROR interposition function...
+ */
+ begin.dtbgn_beginonly = 0;
+
+ assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr);
+ assert(begin.dtbgn_errarg == dtp->dt_errarg);
+ dtp->dt_errhdlr = dt_consume_begin_error;
+ dtp->dt_errarg = &begin;
+
+ rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE,
+ dt_consume_begin_probe, dt_consume_begin_record, &begin);
+
+ dtp->dt_errhdlr = begin.dtbgn_errhdlr;
+ dtp->dt_errarg = begin.dtbgn_errarg;
+
+ return (rval);
+}
+
+/* ARGSUSED */
+static uint64_t
+dt_buf_oldest(void *elem, void *arg)
+{
+ dtrace_bufdesc_t *buf = elem;
+ size_t offs = buf->dtbd_oldest;
+
+ while (offs < buf->dtbd_size) {
+ dtrace_rechdr_t *dtrh =
+ /* LINTED - alignment */
+ (dtrace_rechdr_t *)(buf->dtbd_data + offs);
+ if (dtrh->dtrh_epid == DTRACE_EPIDNONE) {
+ offs += sizeof (dtrace_epid_t);
+ } else {
+ return (DTRACE_RECORD_LOAD_TIMESTAMP(dtrh));
+ }
+ }
+
+ /* There are no records left; use the time the buffer was retrieved. */
+ return (buf->dtbd_timestamp);
+}
+
+int
+dtrace_consume(dtrace_hdl_t *dtp, FILE *fp,
+ dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
+{
+ dtrace_optval_t size;
+ static int max_ncpus;
+ int i, rval;
+ dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE];
+ hrtime_t now = gethrtime();
+
+ if (dtp->dt_lastswitch != 0) {
+ if (now - dtp->dt_lastswitch < interval)
+ return (0);
+
+ dtp->dt_lastswitch += interval;
+ } else {
+ dtp->dt_lastswitch = now;
+ }
+
+ if (!dtp->dt_active)
+ return (dt_set_errno(dtp, EINVAL));
+
+ if (max_ncpus == 0)
+ max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
+
+ if (pf == NULL)
+ pf = (dtrace_consume_probe_f *)dt_nullprobe;
+
+ if (rf == NULL)
+ rf = (dtrace_consume_rec_f *)dt_nullrec;
+
+ if (dtp->dt_options[DTRACEOPT_TEMPORAL] == DTRACEOPT_UNSET) {
+ /*
+ * The output will not be in the order it was traced. Rather,
+ * we will consume all of the data from each CPU's buffer in
+ * turn. We apply special handling for the records from BEGIN
+ * and END probes so that they are consumed first and last,
+ * respectively.
+ *
+ * If we have just begun, we want to first process the CPU that
+ * executed the BEGIN probe (if any).
+ */
+ if (dtp->dt_active && dtp->dt_beganon != -1 &&
+ (rval = dt_consume_begin(dtp, fp, pf, rf, arg)) != 0)
+ return (rval);
+
+ for (i = 0; i < max_ncpus; i++) {
+ dtrace_bufdesc_t *buf;
+
+ /*
+ * If we have stopped, we want to process the CPU on
+ * which the END probe was processed only _after_ we
+ * have processed everything else.
+ */
+ if (dtp->dt_stopped && (i == dtp->dt_endedon))
+ continue;
+
+ if (dt_get_buf(dtp, i, &buf) != 0)
+ return (-1);
+ if (buf == NULL)
+ continue;
+
+ dtp->dt_flow = 0;
+ dtp->dt_indent = 0;
+ dtp->dt_prefix = NULL;
+ rval = dt_consume_cpu(dtp, fp, i,
+ buf, B_FALSE, pf, rf, arg);
+ dt_put_buf(dtp, buf);
+ if (rval != 0)
+ return (rval);
+ }
+ if (dtp->dt_stopped) {
+ dtrace_bufdesc_t *buf;
+
+ if (dt_get_buf(dtp, dtp->dt_endedon, &buf) != 0)
+ return (-1);
+ if (buf == NULL)
+ return (0);
+
+ rval = dt_consume_cpu(dtp, fp, dtp->dt_endedon,
+ buf, B_FALSE, pf, rf, arg);
+ dt_put_buf(dtp, buf);
+ return (rval);
+ }
+ } else {
+ /*
+ * The output will be in the order it was traced (or for
+ * speculations, when it was committed). We retrieve a buffer
+ * from each CPU and put it into a priority queue, which sorts
+ * based on the first entry in the buffer. This is sufficient
+ * because entries within a buffer are already sorted.
+ *
+ * We then consume records one at a time, always consuming the
+ * oldest record, as determined by the priority queue. When
+ * we reach the end of the time covered by these buffers,
+ * we need to stop and retrieve more records on the next pass.
+ * The kernel tells us the time covered by each buffer, in
+ * dtbd_timestamp. The first buffer's timestamp tells us the
+ * time covered by all buffers, as subsequently retrieved
+ * buffers will cover to a more recent time.
+ */
+
+ uint64_t *drops = alloca(max_ncpus * sizeof (uint64_t));
+ uint64_t first_timestamp = 0;
+ uint_t cookie = 0;
+ dtrace_bufdesc_t *buf;
+
+ bzero(drops, max_ncpus * sizeof (uint64_t));
+
+ if (dtp->dt_bufq == NULL) {
+ dtp->dt_bufq = dt_pq_init(dtp, max_ncpus * 2,
+ dt_buf_oldest, NULL);
+ if (dtp->dt_bufq == NULL) /* ENOMEM */
+ return (-1);
+ }
+
+ /* Retrieve data from each CPU. */
+ (void) dtrace_getopt(dtp, "bufsize", &size);
+ for (i = 0; i < max_ncpus; i++) {
+ dtrace_bufdesc_t *buf;
+
+ if (dt_get_buf(dtp, i, &buf) != 0)
+ return (-1);
+ if (buf != NULL) {
+ if (first_timestamp == 0)
+ first_timestamp = buf->dtbd_timestamp;
+ assert(buf->dtbd_timestamp >= first_timestamp);
+
+ dt_pq_insert(dtp->dt_bufq, buf);
+ drops[i] = buf->dtbd_drops;
+ buf->dtbd_drops = 0;
+ }
+ }
+
+ /* Consume records. */
+ for (;;) {
+ dtrace_bufdesc_t *buf = dt_pq_pop(dtp->dt_bufq);
+ uint64_t timestamp;
+
+ if (buf == NULL)
+ break;
+
+ timestamp = dt_buf_oldest(buf, dtp);
+ if (timestamp == buf->dtbd_timestamp) {
+ /*
+ * We've reached the end of the time covered
+ * by this buffer. If this is the oldest
+ * buffer, we must do another pass
+ * to retrieve more data.
+ */
+ dt_put_buf(dtp, buf);
+ if (timestamp == first_timestamp &&
+ !dtp->dt_stopped)
+ break;
+ continue;
+ }
+ assert(timestamp >= dtp->dt_last_timestamp);
+ dtp->dt_last_timestamp = timestamp;
+
+ if ((rval = dt_consume_cpu(dtp, fp,
+ buf->dtbd_cpu, buf, B_TRUE, pf, rf, arg)) != 0)
+ return (rval);
+ dt_pq_insert(dtp->dt_bufq, buf);
+ }
+
+ /* Consume drops. */
+ for (i = 0; i < max_ncpus; i++) {
+ if (drops[i] != 0) {
+ int error = dt_handle_cpudrop(dtp, i,
+ DTRACEDROP_PRINCIPAL, drops[i]);
+ if (error != 0)
+ return (error);
+ }
+ }
+
+ /*
+ * Reduce memory usage by re-allocating smaller buffers
+ * for the "remnants".
+ */
+ while (buf = dt_pq_walk(dtp->dt_bufq, &cookie))
+ dt_realloc_buf(dtp, buf, buf->dtbd_size);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c
new file mode 100644
index 000000000000..d717d569629d
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c
@@ -0,0 +1,1129 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <strings.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <alloca.h>
+#include <assert.h>
+
+#include <dt_decl.h>
+#include <dt_parser.h>
+#include <dt_module.h>
+#include <dt_impl.h>
+
+static dt_decl_t *
+dt_decl_check(dt_decl_t *ddp)
+{
+ if (ddp->dd_kind == CTF_K_UNKNOWN)
+ return (ddp); /* nothing to check if the type is not yet set */
+
+ if (ddp->dd_name != NULL && strcmp(ddp->dd_name, "char") == 0 &&
+ (ddp->dd_attr & (DT_DA_SHORT | DT_DA_LONG | DT_DA_LONGLONG))) {
+ xyerror(D_DECL_CHARATTR, "invalid type declaration: short and "
+ "long may not be used with char type\n");
+ }
+
+ if (ddp->dd_name != NULL && strcmp(ddp->dd_name, "void") == 0 &&
+ (ddp->dd_attr & (DT_DA_SHORT | DT_DA_LONG | DT_DA_LONGLONG |
+ (DT_DA_SIGNED | DT_DA_UNSIGNED)))) {
+ xyerror(D_DECL_VOIDATTR, "invalid type declaration: attributes "
+ "may not be used with void type\n");
+ }
+
+ if (ddp->dd_kind != CTF_K_INTEGER &&
+ (ddp->dd_attr & (DT_DA_SIGNED | DT_DA_UNSIGNED))) {
+ xyerror(D_DECL_SIGNINT, "invalid type declaration: signed and "
+ "unsigned may only be used with integer type\n");
+ }
+
+ if (ddp->dd_kind != CTF_K_INTEGER && ddp->dd_kind != CTF_K_FLOAT &&
+ (ddp->dd_attr & (DT_DA_LONG | DT_DA_LONGLONG))) {
+ xyerror(D_DECL_LONGINT, "invalid type declaration: long and "
+ "long long may only be used with integer or "
+ "floating-point type\n");
+ }
+
+ return (ddp);
+}
+
+dt_decl_t *
+dt_decl_alloc(ushort_t kind, char *name)
+{
+ dt_decl_t *ddp = malloc(sizeof (dt_decl_t));
+
+ if (ddp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ ddp->dd_kind = kind;
+ ddp->dd_attr = 0;
+ ddp->dd_ctfp = NULL;
+ ddp->dd_type = CTF_ERR;
+ ddp->dd_name = name;
+ ddp->dd_node = NULL;
+ ddp->dd_next = NULL;
+
+ return (ddp);
+}
+
+void
+dt_decl_free(dt_decl_t *ddp)
+{
+ dt_decl_t *ndp;
+
+ for (; ddp != NULL; ddp = ndp) {
+ ndp = ddp->dd_next;
+ free(ddp->dd_name);
+ dt_node_list_free(&ddp->dd_node);
+ free(ddp);
+ }
+}
+
+void
+dt_decl_reset(void)
+{
+ dt_scope_t *dsp = &yypcb->pcb_dstack;
+ dt_decl_t *ddp = dsp->ds_decl;
+
+ while (ddp->dd_next != NULL) {
+ dsp->ds_decl = ddp->dd_next;
+ ddp->dd_next = NULL;
+ dt_decl_free(ddp);
+ ddp = dsp->ds_decl;
+ }
+}
+
+dt_decl_t *
+dt_decl_push(dt_decl_t *ddp)
+{
+ dt_scope_t *dsp = &yypcb->pcb_dstack;
+ dt_decl_t *top = dsp->ds_decl;
+
+ if (top != NULL &&
+ top->dd_kind == CTF_K_UNKNOWN && top->dd_name == NULL) {
+ top->dd_kind = CTF_K_INTEGER;
+ (void) dt_decl_check(top);
+ }
+
+ assert(ddp->dd_next == NULL);
+ ddp->dd_next = top;
+ dsp->ds_decl = ddp;
+
+ return (ddp);
+}
+
+dt_decl_t *
+dt_decl_pop(void)
+{
+ dt_scope_t *dsp = &yypcb->pcb_dstack;
+ dt_decl_t *ddp = dt_decl_top();
+
+ dsp->ds_decl = NULL;
+ free(dsp->ds_ident);
+ dsp->ds_ident = NULL;
+ dsp->ds_ctfp = NULL;
+ dsp->ds_type = CTF_ERR;
+ dsp->ds_class = DT_DC_DEFAULT;
+ dsp->ds_enumval = -1;
+
+ return (ddp);
+}
+
+dt_decl_t *
+dt_decl_pop_param(char **idp)
+{
+ dt_scope_t *dsp = &yypcb->pcb_dstack;
+
+ if (dsp->ds_class != DT_DC_DEFAULT && dsp->ds_class != DT_DC_REGISTER) {
+ xyerror(D_DECL_PARMCLASS, "inappropriate storage class "
+ "for function or associative array parameter\n");
+ }
+
+ if (idp != NULL && dt_decl_top() != NULL) {
+ *idp = dsp->ds_ident;
+ dsp->ds_ident = NULL;
+ }
+
+ return (dt_decl_pop());
+}
+
+dt_decl_t *
+dt_decl_top(void)
+{
+ dt_decl_t *ddp = yypcb->pcb_dstack.ds_decl;
+
+ if (ddp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NODECL);
+
+ if (ddp->dd_kind == CTF_K_UNKNOWN && ddp->dd_name == NULL) {
+ ddp->dd_kind = CTF_K_INTEGER;
+ (void) dt_decl_check(ddp);
+ }
+
+ return (ddp);
+}
+
+dt_decl_t *
+dt_decl_ident(char *name)
+{
+ dt_scope_t *dsp = &yypcb->pcb_dstack;
+ dt_decl_t *ddp = dsp->ds_decl;
+
+ if (dsp->ds_ident != NULL) {
+ free(name);
+ xyerror(D_DECL_IDENT, "old-style declaration or "
+ "incorrect type specified\n");
+ }
+
+ dsp->ds_ident = name;
+
+ if (ddp == NULL)
+ ddp = dt_decl_push(dt_decl_alloc(CTF_K_UNKNOWN, NULL));
+
+ return (ddp);
+}
+
+void
+dt_decl_class(dt_dclass_t class)
+{
+ dt_scope_t *dsp = &yypcb->pcb_dstack;
+
+ if (dsp->ds_class != DT_DC_DEFAULT) {
+ xyerror(D_DECL_CLASS, "only one storage class allowed "
+ "in a declaration\n");
+ }
+
+ dsp->ds_class = class;
+}
+
+/*
+ * Set the kind and name of the current declaration. If none is allocated,
+ * make a new decl and push it on to the top of our stack. If the name or kind
+ * is already set for the current decl, then we need to fail this declaration.
+ * This can occur because too many types were given (e.g. "int int"), etc.
+ */
+dt_decl_t *
+dt_decl_spec(ushort_t kind, char *name)
+{
+ dt_decl_t *ddp = yypcb->pcb_dstack.ds_decl;
+
+ if (ddp == NULL)
+ return (dt_decl_push(dt_decl_alloc(kind, name)));
+
+ /*
+ * If we already have a type name specified and we see another type
+ * name, this is an error if the declaration is a typedef. If the
+ * declaration is not a typedef, then the user may be trying to declare
+ * a variable whose name has been returned by lex as a TNAME token:
+ * call dt_decl_ident() as if the grammar's IDENT rule was matched.
+ */
+ if (ddp->dd_name != NULL && kind == CTF_K_TYPEDEF) {
+ if (yypcb->pcb_dstack.ds_class != DT_DC_TYPEDEF)
+ return (dt_decl_ident(name));
+ xyerror(D_DECL_IDRED, "identifier redeclared: %s\n", name);
+ }
+
+ if (ddp->dd_name != NULL || ddp->dd_kind != CTF_K_UNKNOWN)
+ xyerror(D_DECL_COMBO, "invalid type combination\n");
+
+ ddp->dd_kind = kind;
+ ddp->dd_name = name;
+
+ return (dt_decl_check(ddp));
+}
+
+dt_decl_t *
+dt_decl_attr(ushort_t attr)
+{
+ dt_decl_t *ddp = yypcb->pcb_dstack.ds_decl;
+
+ if (ddp == NULL) {
+ ddp = dt_decl_push(dt_decl_alloc(CTF_K_UNKNOWN, NULL));
+ ddp->dd_attr = attr;
+ return (ddp);
+ }
+
+ if (attr == DT_DA_LONG && (ddp->dd_attr & DT_DA_LONG)) {
+ ddp->dd_attr &= ~DT_DA_LONG;
+ attr = DT_DA_LONGLONG;
+ }
+
+ ddp->dd_attr |= attr;
+ return (dt_decl_check(ddp));
+}
+
+/*
+ * Examine the list of formal parameters 'flist' and determine if the formal
+ * name fnp->dn_string is defined in this list (B_TRUE) or not (B_FALSE).
+ * If 'fnp' is in 'flist', do not search beyond 'fnp' itself in 'flist'.
+ */
+static int
+dt_decl_protoform(dt_node_t *fnp, dt_node_t *flist)
+{
+ dt_node_t *dnp;
+
+ for (dnp = flist; dnp != fnp && dnp != NULL; dnp = dnp->dn_list) {
+ if (dnp->dn_string != NULL &&
+ strcmp(dnp->dn_string, fnp->dn_string) == 0)
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Common code for parsing array, function, and probe definition prototypes.
+ * The prototype node list is specified as 'plist'. The formal prototype
+ * against which to compare the prototype is specified as 'flist'. If plist
+ * and flist are the same, we require that named parameters are unique. If
+ * plist and flist are different, we require that named parameters in plist
+ * match a name that is present in flist.
+ */
+int
+dt_decl_prototype(dt_node_t *plist,
+ dt_node_t *flist, const char *kind, uint_t flags)
+{
+ char n[DT_TYPE_NAMELEN];
+ int is_void, v = 0, i = 1;
+ int form = plist != flist;
+ dt_node_t *dnp;
+
+ for (dnp = plist; dnp != NULL; dnp = dnp->dn_list, i++) {
+
+ if (dnp->dn_type == CTF_ERR && !(flags & DT_DP_VARARGS)) {
+ dnerror(dnp, D_DECL_PROTO_VARARGS, "%s prototype may "
+ "not use a variable-length argument list\n", kind);
+ }
+
+ if (dt_node_is_dynamic(dnp) && !(flags & DT_DP_DYNAMIC)) {
+ dnerror(dnp, D_DECL_PROTO_TYPE, "%s prototype may not "
+ "use parameter of type %s: %s, parameter #%d\n",
+ kind, dt_node_type_name(dnp, n, sizeof (n)),
+ dnp->dn_string ? dnp->dn_string : "(anonymous)", i);
+ }
+
+ is_void = dt_node_is_void(dnp);
+ v += is_void;
+
+ if (is_void && !(flags & DT_DP_VOID)) {
+ dnerror(dnp, D_DECL_PROTO_TYPE, "%s prototype may not "
+ "use parameter of type %s: %s, parameter #%d\n",
+ kind, dt_node_type_name(dnp, n, sizeof (n)),
+ dnp->dn_string ? dnp->dn_string : "(anonymous)", i);
+ }
+
+ if (is_void && dnp->dn_string != NULL) {
+ dnerror(dnp, D_DECL_PROTO_NAME, "void parameter may "
+ "not have a name: %s\n", dnp->dn_string);
+ }
+
+ if (dnp->dn_string != NULL &&
+ dt_decl_protoform(dnp, flist) != form) {
+ dnerror(dnp, D_DECL_PROTO_FORM, "parameter is "
+ "%s declared in %s prototype: %s, parameter #%d\n",
+ form ? "not" : "already", kind, dnp->dn_string, i);
+ }
+
+ if (dnp->dn_string == NULL &&
+ !is_void && !(flags & DT_DP_ANON)) {
+ dnerror(dnp, D_DECL_PROTO_NAME, "parameter declaration "
+ "requires a name: parameter #%d\n", i);
+ }
+ }
+
+ if (v != 0 && plist->dn_list != NULL)
+ xyerror(D_DECL_PROTO_VOID, "void must be sole parameter\n");
+
+ return (v ? 0 : i - 1); /* return zero if sole parameter is 'void' */
+}
+
+dt_decl_t *
+dt_decl_array(dt_node_t *dnp)
+{
+ dt_decl_t *ddp = dt_decl_push(dt_decl_alloc(CTF_K_ARRAY, NULL));
+ dt_scope_t *dsp = &yypcb->pcb_dstack;
+ dt_decl_t *ndp = ddp;
+
+ /*
+ * After pushing the array on to the decl stack, scan ahead for multi-
+ * dimensional array declarations and push the current decl to the
+ * bottom to match the resulting CTF type tree and data layout. Refer
+ * to the comments in dt_decl_type() and ISO C 6.5.2.1 for more info.
+ */
+ while (ndp->dd_next != NULL && ndp->dd_next->dd_kind == CTF_K_ARRAY)
+ ndp = ndp->dd_next; /* skip to bottom-most array declaration */
+
+ if (ndp != ddp) {
+ if (dnp != NULL && dnp->dn_kind == DT_NODE_TYPE) {
+ xyerror(D_DECL_DYNOBJ,
+ "cannot declare array of associative arrays\n");
+ }
+ dsp->ds_decl = ddp->dd_next;
+ ddp->dd_next = ndp->dd_next;
+ ndp->dd_next = ddp;
+ }
+
+ if (ddp->dd_next->dd_name != NULL &&
+ strcmp(ddp->dd_next->dd_name, "void") == 0)
+ xyerror(D_DECL_VOIDOBJ, "cannot declare array of void\n");
+
+ if (dnp != NULL && dnp->dn_kind != DT_NODE_TYPE) {
+ dnp = ddp->dd_node = dt_node_cook(dnp, DT_IDFLG_REF);
+
+ if (dt_node_is_posconst(dnp) == 0) {
+ xyerror(D_DECL_ARRSUB, "positive integral constant "
+ "expression or tuple signature expected as "
+ "array declaration subscript\n");
+ }
+
+ if (dnp->dn_value > UINT_MAX)
+ xyerror(D_DECL_ARRBIG, "array dimension too big\n");
+
+ } else if (dnp != NULL) {
+ ddp->dd_node = dnp;
+ (void) dt_decl_prototype(dnp, dnp, "array", DT_DP_ANON);
+ }
+
+ return (ddp);
+}
+
+/*
+ * When a function is declared, we need to fudge the decl stack a bit if the
+ * declaration uses the function pointer (*)() syntax. In this case, the
+ * dt_decl_func() call occurs *after* the dt_decl_ptr() call, even though the
+ * resulting type is "pointer to function". To make the pointer land on top,
+ * we check to see if 'pdp' is non-NULL and a pointer. If it is, we search
+ * backward for a decl tagged with DT_DA_PAREN, and if one is found, the func
+ * decl is inserted behind this node in the decl list instead of at the top.
+ * In all cases, the func decl's dd_next pointer is set to the decl chain
+ * for the function's return type and the function parameter list is discarded.
+ */
+dt_decl_t *
+dt_decl_func(dt_decl_t *pdp, dt_node_t *dnp)
+{
+ dt_decl_t *ddp = dt_decl_alloc(CTF_K_FUNCTION, NULL);
+
+ ddp->dd_node = dnp;
+
+ (void) dt_decl_prototype(dnp, dnp, "function",
+ DT_DP_VARARGS | DT_DP_VOID | DT_DP_ANON);
+
+ if (pdp == NULL || pdp->dd_kind != CTF_K_POINTER)
+ return (dt_decl_push(ddp));
+
+ while (pdp->dd_next != NULL && !(pdp->dd_next->dd_attr & DT_DA_PAREN))
+ pdp = pdp->dd_next;
+
+ if (pdp->dd_next == NULL)
+ return (dt_decl_push(ddp));
+
+ ddp->dd_next = pdp->dd_next;
+ pdp->dd_next = ddp;
+
+ return (pdp);
+}
+
+dt_decl_t *
+dt_decl_ptr(void)
+{
+ return (dt_decl_push(dt_decl_alloc(CTF_K_POINTER, NULL)));
+}
+
+dt_decl_t *
+dt_decl_sou(uint_t kind, char *name)
+{
+ dt_decl_t *ddp = dt_decl_spec(kind, name);
+ char n[DT_TYPE_NAMELEN];
+ ctf_file_t *ctfp;
+ ctf_id_t type;
+ uint_t flag;
+
+ if (yypcb->pcb_idepth != 0)
+ ctfp = yypcb->pcb_hdl->dt_cdefs->dm_ctfp;
+ else
+ ctfp = yypcb->pcb_hdl->dt_ddefs->dm_ctfp;
+
+ if (yypcb->pcb_dstack.ds_next != NULL)
+ flag = CTF_ADD_NONROOT;
+ else
+ flag = CTF_ADD_ROOT;
+
+ (void) snprintf(n, sizeof (n), "%s %s",
+ kind == CTF_K_STRUCT ? "struct" : "union",
+ name == NULL ? "(anon)" : name);
+
+ if (name != NULL && (type = ctf_lookup_by_name(ctfp, n)) != CTF_ERR &&
+ ctf_type_kind(ctfp, type) != CTF_K_FORWARD)
+ xyerror(D_DECL_TYPERED, "type redeclared: %s\n", n);
+
+ if (kind == CTF_K_STRUCT)
+ type = ctf_add_struct(ctfp, flag, name);
+ else
+ type = ctf_add_union(ctfp, flag, name);
+
+ if (type == CTF_ERR || ctf_update(ctfp) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to define %s: %s\n",
+ n, ctf_errmsg(ctf_errno(ctfp)));
+ }
+
+ ddp->dd_ctfp = ctfp;
+ ddp->dd_type = type;
+
+ dt_scope_push(ctfp, type);
+ return (ddp);
+}
+
+void
+dt_decl_member(dt_node_t *dnp)
+{
+ dt_scope_t *dsp = yypcb->pcb_dstack.ds_next;
+ dt_decl_t *ddp = yypcb->pcb_dstack.ds_decl;
+ char *ident = yypcb->pcb_dstack.ds_ident;
+
+ const char *idname = ident ? ident : "(anon)";
+ char n[DT_TYPE_NAMELEN];
+
+ dtrace_typeinfo_t dtt;
+ ctf_encoding_t cte;
+ ctf_id_t base;
+ uint_t kind;
+ ssize_t size;
+
+ if (dsp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOSCOPE);
+
+ if (ddp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NODECL);
+
+ if (dnp == NULL && ident == NULL)
+ xyerror(D_DECL_MNAME, "member declaration requires a name\n");
+
+ if (ddp->dd_kind == CTF_K_UNKNOWN && ddp->dd_name == NULL) {
+ ddp->dd_kind = CTF_K_INTEGER;
+ (void) dt_decl_check(ddp);
+ }
+
+ if (dt_decl_type(ddp, &dtt) != 0)
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+
+ if (ident != NULL && strchr(ident, '`') != NULL) {
+ xyerror(D_DECL_SCOPE, "D scoping operator may not be used "
+ "in a member name (%s)\n", ident);
+ }
+
+ if (dtt.dtt_ctfp == DT_DYN_CTFP(yypcb->pcb_hdl) &&
+ dtt.dtt_type == DT_DYN_TYPE(yypcb->pcb_hdl)) {
+ xyerror(D_DECL_DYNOBJ,
+ "cannot have dynamic member: %s\n", ident);
+ }
+
+ base = ctf_type_resolve(dtt.dtt_ctfp, dtt.dtt_type);
+ kind = ctf_type_kind(dtt.dtt_ctfp, base);
+ size = ctf_type_size(dtt.dtt_ctfp, base);
+
+ if (kind == CTF_K_FORWARD || ((kind == CTF_K_STRUCT ||
+ kind == CTF_K_UNION) && size == 0)) {
+ xyerror(D_DECL_INCOMPLETE, "incomplete struct/union/enum %s: "
+ "%s\n", dt_type_name(dtt.dtt_ctfp, dtt.dtt_type,
+ n, sizeof (n)), ident);
+ }
+
+ if (size == 0)
+ xyerror(D_DECL_VOIDOBJ, "cannot have void member: %s\n", ident);
+
+ /*
+ * If a bit-field qualifier was part of the member declaration, create
+ * a new integer type of the same name and attributes as the base type
+ * and size equal to the specified number of bits. We reset 'dtt' to
+ * refer to this new bit-field type and continue on to add the member.
+ */
+ if (dnp != NULL) {
+ dnp = dt_node_cook(dnp, DT_IDFLG_REF);
+
+ /*
+ * A bit-field member with no declarator is permitted to have
+ * size zero and indicates that no more fields are to be packed
+ * into the current storage unit. We ignore these directives
+ * as the underlying ctf code currently does so for all fields.
+ */
+ if (ident == NULL && dnp->dn_kind == DT_NODE_INT &&
+ dnp->dn_value == 0) {
+ dt_node_free(dnp);
+ goto done;
+ }
+
+ if (dt_node_is_posconst(dnp) == 0) {
+ xyerror(D_DECL_BFCONST, "positive integral constant "
+ "expression expected as bit-field size\n");
+ }
+
+ if (ctf_type_kind(dtt.dtt_ctfp, base) != CTF_K_INTEGER ||
+ ctf_type_encoding(dtt.dtt_ctfp, base, &cte) == CTF_ERR ||
+ IS_VOID(cte)) {
+ xyerror(D_DECL_BFTYPE, "invalid type for "
+ "bit-field: %s\n", idname);
+ }
+
+ if (dnp->dn_value > cte.cte_bits) {
+ xyerror(D_DECL_BFSIZE, "bit-field too big "
+ "for type: %s\n", idname);
+ }
+
+ cte.cte_offset = 0;
+ cte.cte_bits = (uint_t)dnp->dn_value;
+
+ dtt.dtt_type = ctf_add_integer(dsp->ds_ctfp,
+ CTF_ADD_NONROOT, ctf_type_name(dtt.dtt_ctfp,
+ dtt.dtt_type, n, sizeof (n)), &cte);
+
+ if (dtt.dtt_type == CTF_ERR ||
+ ctf_update(dsp->ds_ctfp) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to create type for "
+ "member '%s': %s\n", idname,
+ ctf_errmsg(ctf_errno(dsp->ds_ctfp)));
+ }
+
+ dtt.dtt_ctfp = dsp->ds_ctfp;
+ dt_node_free(dnp);
+ }
+
+ /*
+ * If the member type is not defined in the same CTF container as the
+ * one associated with the current scope (i.e. the container for the
+ * struct or union itself) or its parent, copy the member type into
+ * this container and reset dtt to refer to the copied type.
+ */
+ if (dtt.dtt_ctfp != dsp->ds_ctfp &&
+ dtt.dtt_ctfp != ctf_parent_file(dsp->ds_ctfp)) {
+
+ dtt.dtt_type = ctf_add_type(dsp->ds_ctfp,
+ dtt.dtt_ctfp, dtt.dtt_type);
+ dtt.dtt_ctfp = dsp->ds_ctfp;
+
+ if (dtt.dtt_type == CTF_ERR ||
+ ctf_update(dtt.dtt_ctfp) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to copy type of '%s': %s\n",
+ idname, ctf_errmsg(ctf_errno(dtt.dtt_ctfp)));
+ }
+ }
+
+ if (ctf_add_member(dsp->ds_ctfp, dsp->ds_type,
+ ident, dtt.dtt_type) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to define member '%s': %s\n",
+ idname, ctf_errmsg(ctf_errno(dsp->ds_ctfp)));
+ }
+
+done:
+ free(ident);
+ yypcb->pcb_dstack.ds_ident = NULL;
+ dt_decl_reset();
+}
+
+/*ARGSUSED*/
+static int
+dt_decl_hasmembers(const char *name, int value, void *private)
+{
+ return (1); /* abort search and return true if a member exists */
+}
+
+dt_decl_t *
+dt_decl_enum(char *name)
+{
+ dt_decl_t *ddp = dt_decl_spec(CTF_K_ENUM, name);
+ char n[DT_TYPE_NAMELEN];
+ ctf_file_t *ctfp;
+ ctf_id_t type;
+ uint_t flag;
+
+ if (yypcb->pcb_idepth != 0)
+ ctfp = yypcb->pcb_hdl->dt_cdefs->dm_ctfp;
+ else
+ ctfp = yypcb->pcb_hdl->dt_ddefs->dm_ctfp;
+
+ if (yypcb->pcb_dstack.ds_next != NULL)
+ flag = CTF_ADD_NONROOT;
+ else
+ flag = CTF_ADD_ROOT;
+
+ (void) snprintf(n, sizeof (n), "enum %s", name ? name : "(anon)");
+
+ if (name != NULL && (type = ctf_lookup_by_name(ctfp, n)) != CTF_ERR) {
+ if (ctf_enum_iter(ctfp, type, dt_decl_hasmembers, NULL))
+ xyerror(D_DECL_TYPERED, "type redeclared: %s\n", n);
+ } else if ((type = ctf_add_enum(ctfp, flag, name)) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to define %s: %s\n",
+ n, ctf_errmsg(ctf_errno(ctfp)));
+ }
+
+ ddp->dd_ctfp = ctfp;
+ ddp->dd_type = type;
+
+ dt_scope_push(ctfp, type);
+ return (ddp);
+}
+
+void
+dt_decl_enumerator(char *s, dt_node_t *dnp)
+{
+ dt_scope_t *dsp = yypcb->pcb_dstack.ds_next;
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+
+ dt_idnode_t *inp;
+ dt_ident_t *idp;
+ char *name;
+ int value;
+
+ name = alloca(strlen(s) + 1);
+ (void) strcpy(name, s);
+ free(s);
+
+ if (dsp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOSCOPE);
+
+ assert(dsp->ds_decl->dd_kind == CTF_K_ENUM);
+ value = dsp->ds_enumval + 1; /* default is previous value plus one */
+
+ if (strchr(name, '`') != NULL) {
+ xyerror(D_DECL_SCOPE, "D scoping operator may not be used in "
+ "an enumerator name (%s)\n", name);
+ }
+
+ /*
+ * If the enumerator is being assigned a value, cook and check the node
+ * and then free it after we get the value. We also permit references
+ * to identifiers which are previously defined enumerators in the type.
+ */
+ if (dnp != NULL) {
+ if (dnp->dn_kind != DT_NODE_IDENT || ctf_enum_value(
+ dsp->ds_ctfp, dsp->ds_type, dnp->dn_string, &value) != 0) {
+ dnp = dt_node_cook(dnp, DT_IDFLG_REF);
+
+ if (dnp->dn_kind != DT_NODE_INT) {
+ xyerror(D_DECL_ENCONST, "enumerator '%s' must "
+ "be assigned to an integral constant "
+ "expression\n", name);
+ }
+
+ if ((intmax_t)dnp->dn_value > INT_MAX ||
+ (intmax_t)dnp->dn_value < INT_MIN) {
+ xyerror(D_DECL_ENOFLOW, "enumerator '%s' value "
+ "overflows INT_MAX (%d)\n", name, INT_MAX);
+ }
+
+ value = (int)dnp->dn_value;
+ }
+ dt_node_free(dnp);
+ }
+
+ if (ctf_add_enumerator(dsp->ds_ctfp, dsp->ds_type,
+ name, value) == CTF_ERR || ctf_update(dsp->ds_ctfp) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to define enumerator '%s': %s\n",
+ name, ctf_errmsg(ctf_errno(dsp->ds_ctfp)));
+ }
+
+ dsp->ds_enumval = value; /* save most recent value */
+
+ /*
+ * If the enumerator name matches an identifier in the global scope,
+ * flag this as an error. We only do this for "D" enumerators to
+ * prevent "C" header file enumerators from conflicting with the ever-
+ * growing list of D built-in global variables and inlines. If a "C"
+ * enumerator conflicts with a global identifier, we add the enumerator
+ * but do not insert a corresponding inline (i.e. the D variable wins).
+ */
+ if (dt_idstack_lookup(&yypcb->pcb_globals, name) != NULL) {
+ if (dsp->ds_ctfp == dtp->dt_ddefs->dm_ctfp) {
+ xyerror(D_DECL_IDRED,
+ "identifier redeclared: %s\n", name);
+ } else
+ return;
+ }
+
+ dt_dprintf("add global enumerator %s = %d\n", name, value);
+
+ idp = dt_idhash_insert(dtp->dt_globals, name, DT_IDENT_ENUM,
+ DT_IDFLG_INLINE | DT_IDFLG_REF, 0, _dtrace_defattr, 0,
+ &dt_idops_inline, NULL, dtp->dt_gen);
+
+ if (idp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ yyintprefix = 0;
+ yyintsuffix[0] = '\0';
+ yyintdecimal = 0;
+
+ dnp = dt_node_int(value);
+ dt_node_type_assign(dnp, dsp->ds_ctfp, dsp->ds_type, B_FALSE);
+
+ if ((inp = malloc(sizeof (dt_idnode_t))) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ /*
+ * Remove the INT node from the node allocation list and store it in
+ * din_list and din_root so it persists with and is freed by the ident.
+ */
+ assert(yypcb->pcb_list == dnp);
+ yypcb->pcb_list = dnp->dn_link;
+ dnp->dn_link = NULL;
+
+ bzero(inp, sizeof (dt_idnode_t));
+ inp->din_list = dnp;
+ inp->din_root = dnp;
+
+ idp->di_iarg = inp;
+ idp->di_ctfp = dsp->ds_ctfp;
+ idp->di_type = dsp->ds_type;
+}
+
+/*
+ * Look up the type corresponding to the specified decl stack. The scoping of
+ * the underlying type names is handled by dt_type_lookup(). We build up the
+ * name from the specified string and prefixes and then lookup the type. If
+ * we fail, an errmsg is saved and the caller must abort with EDT_COMPILER.
+ */
+int
+dt_decl_type(dt_decl_t *ddp, dtrace_typeinfo_t *tip)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+
+ dt_module_t *dmp;
+ ctf_arinfo_t r;
+ ctf_id_t type;
+
+ char n[DT_TYPE_NAMELEN];
+ uint_t flag;
+ char *name;
+ int rv;
+
+ tip->dtt_flags = 0;
+
+ /*
+ * Based on our current #include depth and decl stack depth, determine
+ * which dynamic CTF module and scope to use when adding any new types.
+ */
+ dmp = yypcb->pcb_idepth ? dtp->dt_cdefs : dtp->dt_ddefs;
+ flag = yypcb->pcb_dstack.ds_next ? CTF_ADD_NONROOT : CTF_ADD_ROOT;
+
+ if (ddp->dd_attr & DT_DA_USER)
+ tip->dtt_flags = DTT_FL_USER;
+
+ /*
+ * If we have already cached a CTF type for this decl, then we just
+ * return the type information for the cached type.
+ */
+ if (ddp->dd_ctfp != NULL &&
+ (dmp = dt_module_lookup_by_ctf(dtp, ddp->dd_ctfp)) != NULL) {
+ tip->dtt_object = dmp->dm_name;
+ tip->dtt_ctfp = ddp->dd_ctfp;
+ tip->dtt_type = ddp->dd_type;
+ return (0);
+ }
+
+ /*
+ * Currently CTF treats all function pointers identically. We cache a
+ * representative ID of kind CTF_K_FUNCTION and just return that type.
+ * If we want to support full function declarations, dd_next refers to
+ * the declaration of the function return type, and the parameter list
+ * should be parsed and hung off a new pointer inside of this decl.
+ */
+ if (ddp->dd_kind == CTF_K_FUNCTION) {
+ tip->dtt_object = dtp->dt_ddefs->dm_name;
+ tip->dtt_ctfp = DT_FUNC_CTFP(dtp);
+ tip->dtt_type = DT_FUNC_TYPE(dtp);
+ return (0);
+ }
+
+ /*
+ * If the decl is a pointer, resolve the rest of the stack by calling
+ * dt_decl_type() recursively and then compute a pointer to the result.
+ * Similar to the code above, we return a cached id for function ptrs.
+ */
+ if (ddp->dd_kind == CTF_K_POINTER) {
+ if (ddp->dd_next->dd_kind == CTF_K_FUNCTION) {
+ tip->dtt_object = dtp->dt_ddefs->dm_name;
+ tip->dtt_ctfp = DT_FPTR_CTFP(dtp);
+ tip->dtt_type = DT_FPTR_TYPE(dtp);
+ return (0);
+ }
+
+ if ((rv = dt_decl_type(ddp->dd_next, tip)) == 0 &&
+ (rv = dt_type_pointer(tip)) != 0) {
+ xywarn(D_UNKNOWN, "cannot find type: %s*: %s\n",
+ dt_type_name(tip->dtt_ctfp, tip->dtt_type,
+ n, sizeof (n)), ctf_errmsg(dtp->dt_ctferr));
+ }
+
+ return (rv);
+ }
+
+ /*
+ * If the decl is an array, we must find the base type and then call
+ * dt_decl_type() recursively and then build an array of the result.
+ * The C and D multi-dimensional array syntax requires that consecutive
+ * array declarations be processed from right-to-left (i.e. top-down
+ * from the perspective of the declaration stack). For example, an
+ * array declaration such as int x[3][5] is stored on the stack as:
+ *
+ * (bottom) NULL <- ( INT "int" ) <- ( ARR [3] ) <- ( ARR [5] ) (top)
+ *
+ * but means that x is declared to be an array of 3 objects each of
+ * which is an array of 5 integers, or in CTF representation:
+ *
+ * type T1:( content=int, nelems=5 ) type T2:( content=T1, nelems=3 )
+ *
+ * For more details, refer to K&R[5.7] and ISO C 6.5.2.1. Rather than
+ * overcomplicate the implementation of dt_decl_type(), we push array
+ * declarations down into the stack in dt_decl_array(), above, so that
+ * by the time dt_decl_type() is called, the decl stack looks like:
+ *
+ * (bottom) NULL <- ( INT "int" ) <- ( ARR [5] ) <- ( ARR [3] ) (top)
+ *
+ * which permits a straightforward recursive descent of the decl stack
+ * to build the corresponding CTF type tree in the appropriate order.
+ */
+ if (ddp->dd_kind == CTF_K_ARRAY) {
+ /*
+ * If the array decl has a parameter list associated with it,
+ * this is an associative array declaration: return <DYN>.
+ */
+ if (ddp->dd_node != NULL &&
+ ddp->dd_node->dn_kind == DT_NODE_TYPE) {
+ tip->dtt_object = dtp->dt_ddefs->dm_name;
+ tip->dtt_ctfp = DT_DYN_CTFP(dtp);
+ tip->dtt_type = DT_DYN_TYPE(dtp);
+ return (0);
+ }
+
+ if ((rv = dt_decl_type(ddp->dd_next, tip)) != 0)
+ return (rv);
+
+ /*
+ * If the array base type is not defined in the target
+ * container or its parent, copy the type to the target
+ * container and reset dtt_ctfp and dtt_type to the copy.
+ */
+ if (tip->dtt_ctfp != dmp->dm_ctfp &&
+ tip->dtt_ctfp != ctf_parent_file(dmp->dm_ctfp)) {
+
+ tip->dtt_type = ctf_add_type(dmp->dm_ctfp,
+ tip->dtt_ctfp, tip->dtt_type);
+ tip->dtt_ctfp = dmp->dm_ctfp;
+
+ if (tip->dtt_type == CTF_ERR ||
+ ctf_update(tip->dtt_ctfp) == CTF_ERR) {
+ xywarn(D_UNKNOWN, "failed to copy type: %s\n",
+ ctf_errmsg(ctf_errno(tip->dtt_ctfp)));
+ return (-1);
+ }
+ }
+
+ /*
+ * The array index type is irrelevant in C and D: just set it
+ * to "long" for all array types that we create on-the-fly.
+ */
+ r.ctr_contents = tip->dtt_type;
+ r.ctr_index = ctf_lookup_by_name(tip->dtt_ctfp, "long");
+ r.ctr_nelems = ddp->dd_node ?
+ (uint_t)ddp->dd_node->dn_value : 0;
+
+ tip->dtt_object = dmp->dm_name;
+ tip->dtt_ctfp = dmp->dm_ctfp;
+ tip->dtt_type = ctf_add_array(dmp->dm_ctfp, CTF_ADD_ROOT, &r);
+
+ if (tip->dtt_type == CTF_ERR ||
+ ctf_update(tip->dtt_ctfp) == CTF_ERR) {
+ xywarn(D_UNKNOWN, "failed to create array type: %s\n",
+ ctf_errmsg(ctf_errno(tip->dtt_ctfp)));
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ /*
+ * Allocate space for the type name and enough space for the maximum
+ * additional text ("unsigned long long \0" requires 20 more bytes).
+ */
+ name = alloca(ddp->dd_name ? strlen(ddp->dd_name) + 20 : 20);
+ name[0] = '\0';
+
+ switch (ddp->dd_kind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ if (ddp->dd_attr & DT_DA_SIGNED)
+ (void) strcat(name, "signed ");
+ if (ddp->dd_attr & DT_DA_UNSIGNED)
+ (void) strcat(name, "unsigned ");
+ if (ddp->dd_attr & DT_DA_SHORT)
+ (void) strcat(name, "short ");
+ if (ddp->dd_attr & DT_DA_LONG)
+ (void) strcat(name, "long ");
+ if (ddp->dd_attr & DT_DA_LONGLONG)
+ (void) strcat(name, "long long ");
+ if (ddp->dd_attr == 0 && ddp->dd_name == NULL)
+ (void) strcat(name, "int");
+ break;
+ case CTF_K_STRUCT:
+ (void) strcpy(name, "struct ");
+ break;
+ case CTF_K_UNION:
+ (void) strcpy(name, "union ");
+ break;
+ case CTF_K_ENUM:
+ (void) strcpy(name, "enum ");
+ break;
+ case CTF_K_TYPEDEF:
+ break;
+ default:
+ xywarn(D_UNKNOWN, "internal error -- "
+ "bad decl kind %u\n", ddp->dd_kind);
+ return (-1);
+ }
+
+ /*
+ * Add dd_name unless a short, long, or long long is explicitly
+ * suffixed by int. We use the C/CTF canonical names for integers.
+ */
+ if (ddp->dd_name != NULL && (ddp->dd_kind != CTF_K_INTEGER ||
+ (ddp->dd_attr & (DT_DA_SHORT | DT_DA_LONG | DT_DA_LONGLONG)) == 0))
+ (void) strcat(name, ddp->dd_name);
+
+ /*
+ * Lookup the type. If we find it, we're done. Otherwise create a
+ * forward tag for the type if it is a struct, union, or enum. If
+ * we can't find it and we can't create a tag, return failure.
+ */
+ if ((rv = dt_type_lookup(name, tip)) == 0)
+ return (rv);
+
+ switch (ddp->dd_kind) {
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ case CTF_K_ENUM:
+ type = ctf_add_forward(dmp->dm_ctfp, flag,
+ ddp->dd_name, ddp->dd_kind);
+ break;
+ default:
+ xywarn(D_UNKNOWN, "failed to resolve type %s: %s\n", name,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ return (rv);
+ }
+
+ if (type == CTF_ERR || ctf_update(dmp->dm_ctfp) == CTF_ERR) {
+ xywarn(D_UNKNOWN, "failed to add forward tag for %s: %s\n",
+ name, ctf_errmsg(ctf_errno(dmp->dm_ctfp)));
+ return (-1);
+ }
+
+ ddp->dd_ctfp = dmp->dm_ctfp;
+ ddp->dd_type = type;
+
+ tip->dtt_object = dmp->dm_name;
+ tip->dtt_ctfp = dmp->dm_ctfp;
+ tip->dtt_type = type;
+
+ return (0);
+}
+
+void
+dt_scope_create(dt_scope_t *dsp)
+{
+ dsp->ds_decl = NULL;
+ dsp->ds_next = NULL;
+ dsp->ds_ident = NULL;
+ dsp->ds_ctfp = NULL;
+ dsp->ds_type = CTF_ERR;
+ dsp->ds_class = DT_DC_DEFAULT;
+ dsp->ds_enumval = -1;
+}
+
+void
+dt_scope_destroy(dt_scope_t *dsp)
+{
+ dt_scope_t *nsp;
+
+ for (; dsp != NULL; dsp = nsp) {
+ dt_decl_free(dsp->ds_decl);
+ free(dsp->ds_ident);
+ nsp = dsp->ds_next;
+ if (dsp != &yypcb->pcb_dstack)
+ free(dsp);
+ }
+}
+
+void
+dt_scope_push(ctf_file_t *ctfp, ctf_id_t type)
+{
+ dt_scope_t *rsp = &yypcb->pcb_dstack;
+ dt_scope_t *dsp = malloc(sizeof (dt_scope_t));
+
+ if (dsp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dsp->ds_decl = rsp->ds_decl;
+ dsp->ds_next = rsp->ds_next;
+ dsp->ds_ident = rsp->ds_ident;
+ dsp->ds_ctfp = ctfp;
+ dsp->ds_type = type;
+ dsp->ds_class = rsp->ds_class;
+ dsp->ds_enumval = rsp->ds_enumval;
+
+ dt_scope_create(rsp);
+ rsp->ds_next = dsp;
+}
+
+dt_decl_t *
+dt_scope_pop(void)
+{
+ dt_scope_t *rsp = &yypcb->pcb_dstack;
+ dt_scope_t *dsp = rsp->ds_next;
+
+ if (dsp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOSCOPE);
+
+ if (dsp->ds_ctfp != NULL && ctf_update(dsp->ds_ctfp) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to update type definitions: %s\n",
+ ctf_errmsg(ctf_errno(dsp->ds_ctfp)));
+ }
+
+ dt_decl_free(rsp->ds_decl);
+ free(rsp->ds_ident);
+
+ rsp->ds_decl = dsp->ds_decl;
+ rsp->ds_next = dsp->ds_next;
+ rsp->ds_ident = dsp->ds_ident;
+ rsp->ds_ctfp = dsp->ds_ctfp;
+ rsp->ds_type = dsp->ds_type;
+ rsp->ds_class = dsp->ds_class;
+ rsp->ds_enumval = dsp->ds_enumval;
+
+ free(dsp);
+ return (rsp->ds_decl);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h
new file mode 100644
index 000000000000..d32287578219
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _DT_DECL_H
+#define _DT_DECL_H
+
+#include <sys/types.h>
+#include <libctf.h>
+#include <dtrace.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dt_node; /* forward declaration of dt_node_t */
+
+typedef struct dt_decl {
+ ushort_t dd_kind; /* declaration kind (CTF_K_* kind) */
+ ushort_t dd_attr; /* attributes (DT_DA_* flags) */
+ ctf_file_t *dd_ctfp; /* CTF container for decl's type */
+ ctf_id_t dd_type; /* CTF identifier for decl's type */
+ char *dd_name; /* string name of this decl (or NULL) */
+ struct dt_node *dd_node; /* node for array size or parm list */
+ struct dt_decl *dd_next; /* next declaration in list */
+} dt_decl_t;
+
+#define DT_DA_SIGNED 0x0001 /* signed integer value */
+#define DT_DA_UNSIGNED 0x0002 /* unsigned integer value */
+#define DT_DA_SHORT 0x0004 /* short integer value */
+#define DT_DA_LONG 0x0008 /* long integer or double */
+#define DT_DA_LONGLONG 0x0010 /* long long integer value */
+#define DT_DA_CONST 0x0020 /* qualify type as const */
+#define DT_DA_RESTRICT 0x0040 /* qualify type as restrict */
+#define DT_DA_VOLATILE 0x0080 /* qualify type as volatile */
+#define DT_DA_PAREN 0x0100 /* parenthesis tag */
+#define DT_DA_USER 0x0200 /* user-land type specifier */
+
+typedef enum dt_dclass {
+ DT_DC_DEFAULT, /* no storage class specified */
+ DT_DC_AUTO, /* automatic storage */
+ DT_DC_REGISTER, /* register storage */
+ DT_DC_STATIC, /* static storage */
+ DT_DC_EXTERN, /* extern storage */
+ DT_DC_TYPEDEF, /* type definition */
+ DT_DC_SELF, /* thread-local storage */
+ DT_DC_THIS /* clause-local storage */
+} dt_dclass_t;
+
+typedef struct dt_scope {
+ dt_decl_t *ds_decl; /* pointer to top of decl stack */
+ struct dt_scope *ds_next; /* pointer to next scope */
+ char *ds_ident; /* identifier for this scope (if any) */
+ ctf_file_t *ds_ctfp; /* CTF container for this scope */
+ ctf_id_t ds_type; /* CTF id of enclosing type */
+ dt_dclass_t ds_class; /* declaration class for this scope */
+ int ds_enumval; /* most recent enumerator value */
+} dt_scope_t;
+
+extern dt_decl_t *dt_decl_alloc(ushort_t, char *);
+extern void dt_decl_free(dt_decl_t *);
+extern void dt_decl_reset(void);
+extern dt_decl_t *dt_decl_push(dt_decl_t *);
+extern dt_decl_t *dt_decl_pop(void);
+extern dt_decl_t *dt_decl_pop_param(char **);
+extern dt_decl_t *dt_decl_top(void);
+
+extern dt_decl_t *dt_decl_ident(char *);
+extern void dt_decl_class(dt_dclass_t);
+
+#define DT_DP_VARARGS 0x1 /* permit varargs in prototype */
+#define DT_DP_DYNAMIC 0x2 /* permit dynamic type in prototype */
+#define DT_DP_VOID 0x4 /* permit void type in prototype */
+#define DT_DP_ANON 0x8 /* permit anonymous parameters */
+
+extern int dt_decl_prototype(struct dt_node *, struct dt_node *,
+ const char *, uint_t);
+
+extern dt_decl_t *dt_decl_spec(ushort_t, char *);
+extern dt_decl_t *dt_decl_attr(ushort_t);
+extern dt_decl_t *dt_decl_array(struct dt_node *);
+extern dt_decl_t *dt_decl_func(dt_decl_t *, struct dt_node *);
+extern dt_decl_t *dt_decl_ptr(void);
+
+extern dt_decl_t *dt_decl_sou(uint_t, char *);
+extern void dt_decl_member(struct dt_node *);
+
+extern dt_decl_t *dt_decl_enum(char *);
+extern void dt_decl_enumerator(char *, struct dt_node *);
+
+extern int dt_decl_type(dt_decl_t *, dtrace_typeinfo_t *);
+
+extern void dt_scope_create(dt_scope_t *);
+extern void dt_scope_destroy(dt_scope_t *);
+extern void dt_scope_push(ctf_file_t *, ctf_id_t);
+extern dt_decl_t *dt_scope_pop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_DECL_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c
new file mode 100644
index 000000000000..d1335180ec97
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c
@@ -0,0 +1,526 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#include <strings.h>
+#include <stdio.h>
+
+#include <dt_impl.h>
+#include <dt_ident.h>
+
+/*ARGSUSED*/
+static void
+dt_dis_log(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ (void) fprintf(fp, "%-4s %%r%u, %%r%u, %%r%u", name,
+ DIF_INSTR_R1(in), DIF_INSTR_R2(in), DIF_INSTR_RD(in));
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_branch(const dtrace_difo_t *dp, const char *name,
+ dif_instr_t in, FILE *fp)
+{
+ (void) fprintf(fp, "%-4s %u", name, DIF_INSTR_LABEL(in));
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_load(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ (void) fprintf(fp, "%-4s [%%r%u], %%r%u", name,
+ DIF_INSTR_R1(in), DIF_INSTR_RD(in));
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_store(const dtrace_difo_t *dp, const char *name,
+ dif_instr_t in, FILE *fp)
+{
+ (void) fprintf(fp, "%-4s %%r%u, [%%r%u]", name,
+ DIF_INSTR_R1(in), DIF_INSTR_RD(in));
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_str(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ (void) fprintf(fp, "%s", name);
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_r1rd(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ (void) fprintf(fp, "%-4s %%r%u, %%r%u", name,
+ DIF_INSTR_R1(in), DIF_INSTR_RD(in));
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_cmp(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ (void) fprintf(fp, "%-4s %%r%u, %%r%u", name,
+ DIF_INSTR_R1(in), DIF_INSTR_R2(in));
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_tst(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ (void) fprintf(fp, "%-4s %%r%u", name, DIF_INSTR_R1(in));
+}
+
+static const char *
+dt_dis_varname(const dtrace_difo_t *dp, uint_t id, uint_t scope)
+{
+ const dtrace_difv_t *dvp = dp->dtdo_vartab;
+ uint_t i;
+
+ for (i = 0; i < dp->dtdo_varlen; i++, dvp++) {
+ if (dvp->dtdv_id == id && dvp->dtdv_scope == scope) {
+ if (dvp->dtdv_name < dp->dtdo_strlen)
+ return (dp->dtdo_strtab + dvp->dtdv_name);
+ break;
+ }
+ }
+
+ return (NULL);
+}
+
+static uint_t
+dt_dis_scope(const char *name)
+{
+ switch (name[2]) {
+ case 'l': return (DIFV_SCOPE_LOCAL);
+ case 't': return (DIFV_SCOPE_THREAD);
+ case 'g': return (DIFV_SCOPE_GLOBAL);
+ default: return (-1u);
+ }
+}
+
+static void
+dt_dis_lda(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ uint_t var = DIF_INSTR_R1(in);
+ const char *vname;
+
+ (void) fprintf(fp, "%-4s DT_VAR(%u), %%r%u, %%r%u", name,
+ var, DIF_INSTR_R2(in), DIF_INSTR_RD(in));
+
+ if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL)
+ (void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname);
+}
+
+static void
+dt_dis_ldv(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ uint_t var = DIF_INSTR_VAR(in);
+ const char *vname;
+
+ (void) fprintf(fp, "%-4s DT_VAR(%u), %%r%u",
+ name, var, DIF_INSTR_RD(in));
+
+ if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL)
+ (void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname);
+}
+
+static void
+dt_dis_stv(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ uint_t var = DIF_INSTR_VAR(in);
+ const char *vname;
+
+ (void) fprintf(fp, "%-4s %%r%u, DT_VAR(%u)",
+ name, DIF_INSTR_RS(in), var);
+
+ if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL)
+ (void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname);
+}
+
+static void
+dt_dis_setx(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ uint_t intptr = DIF_INSTR_INTEGER(in);
+
+ (void) fprintf(fp, "%-4s DT_INTEGER[%u], %%r%u", name,
+ intptr, DIF_INSTR_RD(in));
+
+ if (intptr < dp->dtdo_intlen) {
+ (void) fprintf(fp, "\t\t! 0x%llx",
+ (u_longlong_t)dp->dtdo_inttab[intptr]);
+ }
+}
+
+static void
+dt_dis_sets(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ uint_t strptr = DIF_INSTR_STRING(in);
+
+ (void) fprintf(fp, "%-4s DT_STRING[%u], %%r%u", name,
+ strptr, DIF_INSTR_RD(in));
+
+ if (strptr < dp->dtdo_strlen)
+ (void) fprintf(fp, "\t\t! \"%s\"", dp->dtdo_strtab + strptr);
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_ret(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ (void) fprintf(fp, "%-4s %%r%u", name, DIF_INSTR_RD(in));
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_call(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ uint_t subr = DIF_INSTR_SUBR(in);
+
+ (void) fprintf(fp, "%-4s DIF_SUBR(%u), %%r%u\t\t! %s",
+ name, subr, DIF_INSTR_RD(in), dtrace_subrstr(NULL, subr));
+}
+
+/*ARGSUSED*/
+static void
+dt_dis_pushts(const dtrace_difo_t *dp,
+ const char *name, dif_instr_t in, FILE *fp)
+{
+ static const char *const tnames[] = { "D type", "string" };
+ uint_t type = DIF_INSTR_TYPE(in);
+ const char *pad;
+
+ if (DIF_INSTR_OP(in) == DIF_OP_PUSHTV) {
+ (void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u",
+ name, type, DIF_INSTR_RS(in));
+ pad = "\t\t";
+ } else {
+ (void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u, %%r%u",
+ name, type, DIF_INSTR_R2(in), DIF_INSTR_RS(in));
+ pad = "\t";
+ }
+
+ if (type < sizeof (tnames) / sizeof (tnames[0])) {
+ (void) fprintf(fp, "%s! DT_TYPE(%u) = %s", pad,
+ type, tnames[type]);
+ }
+}
+
+static void
+dt_dis_xlate(const dtrace_difo_t *dp,
+ const char *name, dif_instr_t in, FILE *fp)
+{
+ uint_t xlr = DIF_INSTR_XLREF(in);
+
+ (void) fprintf(fp, "%-4s DT_XLREF[%u], %%r%u",
+ name, xlr, DIF_INSTR_RD(in));
+
+ if (xlr < dp->dtdo_xlmlen) {
+ (void) fprintf(fp, "\t\t! DT_XLREF[%u] = %u.%s", xlr,
+ (uint_t)dp->dtdo_xlmtab[xlr]->dn_membexpr->dn_xlator->dx_id,
+ dp->dtdo_xlmtab[xlr]->dn_membname);
+ }
+}
+
+static char *
+dt_dis_typestr(const dtrace_diftype_t *t, char *buf, size_t len)
+{
+ char kind[16], ckind[16];
+
+ switch (t->dtdt_kind) {
+ case DIF_TYPE_CTF:
+ (void) strcpy(kind, "D type");
+ break;
+ case DIF_TYPE_STRING:
+ (void) strcpy(kind, "string");
+ break;
+ default:
+ (void) snprintf(kind, sizeof (kind), "0x%x", t->dtdt_kind);
+ }
+
+ switch (t->dtdt_ckind) {
+ case CTF_K_UNKNOWN:
+ (void) strcpy(ckind, "unknown");
+ break;
+ case CTF_K_INTEGER:
+ (void) strcpy(ckind, "integer");
+ break;
+ case CTF_K_FLOAT:
+ (void) strcpy(ckind, "float");
+ break;
+ case CTF_K_POINTER:
+ (void) strcpy(ckind, "pointer");
+ break;
+ case CTF_K_ARRAY:
+ (void) strcpy(ckind, "array");
+ break;
+ case CTF_K_FUNCTION:
+ (void) strcpy(ckind, "function");
+ break;
+ case CTF_K_STRUCT:
+ (void) strcpy(ckind, "struct");
+ break;
+ case CTF_K_UNION:
+ (void) strcpy(ckind, "union");
+ break;
+ case CTF_K_ENUM:
+ (void) strcpy(ckind, "enum");
+ break;
+ case CTF_K_FORWARD:
+ (void) strcpy(ckind, "forward");
+ break;
+ case CTF_K_TYPEDEF:
+ (void) strcpy(ckind, "typedef");
+ break;
+ case CTF_K_VOLATILE:
+ (void) strcpy(ckind, "volatile");
+ break;
+ case CTF_K_CONST:
+ (void) strcpy(ckind, "const");
+ break;
+ case CTF_K_RESTRICT:
+ (void) strcpy(ckind, "restrict");
+ break;
+ default:
+ (void) snprintf(ckind, sizeof (ckind), "0x%x", t->dtdt_ckind);
+ }
+
+ if (t->dtdt_flags & (DIF_TF_BYREF | DIF_TF_BYUREF)) {
+ (void) snprintf(buf, len, "%s (%s) by %sref (size %lu)",
+ kind, ckind, (t->dtdt_flags & DIF_TF_BYUREF) ? "user " : "",
+ (ulong_t)t->dtdt_size);
+ } else {
+ (void) snprintf(buf, len, "%s (%s) (size %lu)",
+ kind, ckind, (ulong_t)t->dtdt_size);
+ }
+
+ return (buf);
+}
+
+static void
+dt_dis_rtab(const char *rtag, const dtrace_difo_t *dp, FILE *fp,
+ const dof_relodesc_t *rp, uint32_t len)
+{
+ (void) fprintf(fp, "\n%-4s %-8s %-8s %s\n",
+ rtag, "OFFSET", "DATA", "NAME");
+
+ for (; len != 0; len--, rp++) {
+ (void) fprintf(fp, "%-4u %-8llu %-8llu %s\n",
+ rp->dofr_type, (u_longlong_t)rp->dofr_offset,
+ (u_longlong_t)rp->dofr_data,
+ &dp->dtdo_strtab[rp->dofr_name]);
+ }
+}
+
+void
+dt_dis(const dtrace_difo_t *dp, FILE *fp)
+{
+ static const struct opent {
+ const char *op_name;
+ void (*op_func)(const dtrace_difo_t *, const char *,
+ dif_instr_t, FILE *);
+ } optab[] = {
+ { "(illegal opcode)", dt_dis_str },
+ { "or", dt_dis_log }, /* DIF_OP_OR */
+ { "xor", dt_dis_log }, /* DIF_OP_XOR */
+ { "and", dt_dis_log }, /* DIF_OP_AND */
+ { "sll", dt_dis_log }, /* DIF_OP_SLL */
+ { "srl", dt_dis_log }, /* DIF_OP_SRL */
+ { "sub", dt_dis_log }, /* DIF_OP_SUB */
+ { "add", dt_dis_log }, /* DIF_OP_ADD */
+ { "mul", dt_dis_log }, /* DIF_OP_MUL */
+ { "sdiv", dt_dis_log }, /* DIF_OP_SDIV */
+ { "udiv", dt_dis_log }, /* DIF_OP_UDIV */
+ { "srem", dt_dis_log }, /* DIF_OP_SREM */
+ { "urem", dt_dis_log }, /* DIF_OP_UREM */
+ { "not", dt_dis_r1rd }, /* DIF_OP_NOT */
+ { "mov", dt_dis_r1rd }, /* DIF_OP_MOV */
+ { "cmp", dt_dis_cmp }, /* DIF_OP_CMP */
+ { "tst", dt_dis_tst }, /* DIF_OP_TST */
+ { "ba", dt_dis_branch }, /* DIF_OP_BA */
+ { "be", dt_dis_branch }, /* DIF_OP_BE */
+ { "bne", dt_dis_branch }, /* DIF_OP_BNE */
+ { "bg", dt_dis_branch }, /* DIF_OP_BG */
+ { "bgu", dt_dis_branch }, /* DIF_OP_BGU */
+ { "bge", dt_dis_branch }, /* DIF_OP_BGE */
+ { "bgeu", dt_dis_branch }, /* DIF_OP_BGEU */
+ { "bl", dt_dis_branch }, /* DIF_OP_BL */
+ { "blu", dt_dis_branch }, /* DIF_OP_BLU */
+ { "ble", dt_dis_branch }, /* DIF_OP_BLE */
+ { "bleu", dt_dis_branch }, /* DIF_OP_BLEU */
+ { "ldsb", dt_dis_load }, /* DIF_OP_LDSB */
+ { "ldsh", dt_dis_load }, /* DIF_OP_LDSH */
+ { "ldsw", dt_dis_load }, /* DIF_OP_LDSW */
+ { "ldub", dt_dis_load }, /* DIF_OP_LDUB */
+ { "lduh", dt_dis_load }, /* DIF_OP_LDUH */
+ { "lduw", dt_dis_load }, /* DIF_OP_LDUW */
+ { "ldx", dt_dis_load }, /* DIF_OP_LDX */
+ { "ret", dt_dis_ret }, /* DIF_OP_RET */
+ { "nop", dt_dis_str }, /* DIF_OP_NOP */
+ { "setx", dt_dis_setx }, /* DIF_OP_SETX */
+ { "sets", dt_dis_sets }, /* DIF_OP_SETS */
+ { "scmp", dt_dis_cmp }, /* DIF_OP_SCMP */
+ { "ldga", dt_dis_lda }, /* DIF_OP_LDGA */
+ { "ldgs", dt_dis_ldv }, /* DIF_OP_LDGS */
+ { "stgs", dt_dis_stv }, /* DIF_OP_STGS */
+ { "ldta", dt_dis_lda }, /* DIF_OP_LDTA */
+ { "ldts", dt_dis_ldv }, /* DIF_OP_LDTS */
+ { "stts", dt_dis_stv }, /* DIF_OP_STTS */
+ { "sra", dt_dis_log }, /* DIF_OP_SRA */
+ { "call", dt_dis_call }, /* DIF_OP_CALL */
+ { "pushtr", dt_dis_pushts }, /* DIF_OP_PUSHTR */
+ { "pushtv", dt_dis_pushts }, /* DIF_OP_PUSHTV */
+ { "popts", dt_dis_str }, /* DIF_OP_POPTS */
+ { "flushts", dt_dis_str }, /* DIF_OP_FLUSHTS */
+ { "ldgaa", dt_dis_ldv }, /* DIF_OP_LDGAA */
+ { "ldtaa", dt_dis_ldv }, /* DIF_OP_LDTAA */
+ { "stgaa", dt_dis_stv }, /* DIF_OP_STGAA */
+ { "sttaa", dt_dis_stv }, /* DIF_OP_STTAA */
+ { "ldls", dt_dis_ldv }, /* DIF_OP_LDLS */
+ { "stls", dt_dis_stv }, /* DIF_OP_STLS */
+ { "allocs", dt_dis_r1rd }, /* DIF_OP_ALLOCS */
+ { "copys", dt_dis_log }, /* DIF_OP_COPYS */
+ { "stb", dt_dis_store }, /* DIF_OP_STB */
+ { "sth", dt_dis_store }, /* DIF_OP_STH */
+ { "stw", dt_dis_store }, /* DIF_OP_STW */
+ { "stx", dt_dis_store }, /* DIF_OP_STX */
+ { "uldsb", dt_dis_load }, /* DIF_OP_ULDSB */
+ { "uldsh", dt_dis_load }, /* DIF_OP_ULDSH */
+ { "uldsw", dt_dis_load }, /* DIF_OP_ULDSW */
+ { "uldub", dt_dis_load }, /* DIF_OP_ULDUB */
+ { "ulduh", dt_dis_load }, /* DIF_OP_ULDUH */
+ { "ulduw", dt_dis_load }, /* DIF_OP_ULDUW */
+ { "uldx", dt_dis_load }, /* DIF_OP_ULDX */
+ { "rldsb", dt_dis_load }, /* DIF_OP_RLDSB */
+ { "rldsh", dt_dis_load }, /* DIF_OP_RLDSH */
+ { "rldsw", dt_dis_load }, /* DIF_OP_RLDSW */
+ { "rldub", dt_dis_load }, /* DIF_OP_RLDUB */
+ { "rlduh", dt_dis_load }, /* DIF_OP_RLDUH */
+ { "rlduw", dt_dis_load }, /* DIF_OP_RLDUW */
+ { "rldx", dt_dis_load }, /* DIF_OP_RLDX */
+ { "xlate", dt_dis_xlate }, /* DIF_OP_XLATE */
+ { "xlarg", dt_dis_xlate }, /* DIF_OP_XLARG */
+ };
+
+ const struct opent *op;
+ ulong_t i = 0;
+ char type[DT_TYPE_NAMELEN];
+
+ (void) fprintf(fp, "\nDIFO %p returns %s\n", (void *)dp,
+ dt_dis_typestr(&dp->dtdo_rtype, type, sizeof (type)));
+
+ (void) fprintf(fp, "%-3s %-8s %s\n",
+ "OFF", "OPCODE", "INSTRUCTION");
+
+ for (i = 0; i < dp->dtdo_len; i++) {
+ dif_instr_t instr = dp->dtdo_buf[i];
+ dif_instr_t opcode = DIF_INSTR_OP(instr);
+
+ if (opcode >= sizeof (optab) / sizeof (optab[0]))
+ opcode = 0; /* force invalid opcode message */
+
+ op = &optab[opcode];
+ (void) fprintf(fp, "%02lu: %08x ", i, instr);
+ op->op_func(dp, op->op_name, instr, fp);
+ (void) fprintf(fp, "\n");
+ }
+
+ if (dp->dtdo_varlen != 0) {
+ (void) fprintf(fp, "\n%-16s %-4s %-3s %-3s %-4s %s\n",
+ "NAME", "ID", "KND", "SCP", "FLAG", "TYPE");
+ }
+
+ for (i = 0; i < dp->dtdo_varlen; i++) {
+ dtrace_difv_t *v = &dp->dtdo_vartab[i];
+ char kind[4], scope[4], flags[16] = { 0 };
+
+ switch (v->dtdv_kind) {
+ case DIFV_KIND_ARRAY:
+ (void) strcpy(kind, "arr");
+ break;
+ case DIFV_KIND_SCALAR:
+ (void) strcpy(kind, "scl");
+ break;
+ default:
+ (void) snprintf(kind, sizeof (kind),
+ "%u", v->dtdv_kind);
+ }
+
+ switch (v->dtdv_scope) {
+ case DIFV_SCOPE_GLOBAL:
+ (void) strcpy(scope, "glb");
+ break;
+ case DIFV_SCOPE_THREAD:
+ (void) strcpy(scope, "tls");
+ break;
+ case DIFV_SCOPE_LOCAL:
+ (void) strcpy(scope, "loc");
+ break;
+ default:
+ (void) snprintf(scope, sizeof (scope),
+ "%u", v->dtdv_scope);
+ }
+
+ if (v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)) {
+ (void) snprintf(flags, sizeof (flags), "/0x%x",
+ v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD));
+ }
+
+ if (v->dtdv_flags & DIFV_F_REF)
+ (void) strcat(flags, "/r");
+ if (v->dtdv_flags & DIFV_F_MOD)
+ (void) strcat(flags, "/w");
+
+ (void) fprintf(fp, "%-16s %-4u %-3s %-3s %-4s %s\n",
+ &dp->dtdo_strtab[v->dtdv_name],
+ v->dtdv_id, kind, scope, flags + 1,
+ dt_dis_typestr(&v->dtdv_type, type, sizeof (type)));
+ }
+
+ if (dp->dtdo_xlmlen != 0) {
+ (void) fprintf(fp, "\n%-4s %-3s %-12s %s\n",
+ "XLID", "ARG", "MEMBER", "TYPE");
+ }
+
+ for (i = 0; i < dp->dtdo_xlmlen; i++) {
+ dt_node_t *dnp = dp->dtdo_xlmtab[i];
+ dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator;
+ (void) fprintf(fp, "%-4u %-3d %-12s %s\n",
+ (uint_t)dxp->dx_id, dxp->dx_arg, dnp->dn_membname,
+ dt_node_type_name(dnp, type, sizeof (type)));
+ }
+
+ if (dp->dtdo_krelen != 0)
+ dt_dis_rtab("KREL", dp, fp, dp->dtdo_kreltab, dp->dtdo_krelen);
+
+ if (dp->dtdo_urelen != 0)
+ dt_dis_rtab("UREL", dp, fp, dp->dtdo_ureltab, dp->dtdo_urelen);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
new file mode 100644
index 000000000000..3d1d976bd3dd
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
@@ -0,0 +1,976 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#ifdef illumos
+#include <sys/sysmacros.h>
+#endif
+
+#include <strings.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <dt_impl.h>
+#include <dt_strtab.h>
+#include <dt_program.h>
+#include <dt_provider.h>
+#include <dt_xlator.h>
+#include <dt_dof.h>
+
+void
+dt_dof_init(dtrace_hdl_t *dtp)
+{
+ dt_dof_t *ddo = &dtp->dt_dof;
+
+ ddo->ddo_hdl = dtp;
+ ddo->ddo_nsecs = 0;
+ ddo->ddo_strsec = DOF_SECIDX_NONE;
+ ddo->ddo_xlimport = NULL;
+ ddo->ddo_xlexport = NULL;
+
+ dt_buf_create(dtp, &ddo->ddo_secs, "section headers", 0);
+ dt_buf_create(dtp, &ddo->ddo_strs, "string table", 0);
+ dt_buf_create(dtp, &ddo->ddo_ldata, "loadable data", 0);
+ dt_buf_create(dtp, &ddo->ddo_udata, "unloadable data", 0);
+
+ 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);
+}
+
+void
+dt_dof_fini(dtrace_hdl_t *dtp)
+{
+ dt_dof_t *ddo = &dtp->dt_dof;
+
+ dt_free(dtp, ddo->ddo_xlimport);
+ dt_free(dtp, ddo->ddo_xlexport);
+
+ dt_buf_destroy(dtp, &ddo->ddo_secs);
+ dt_buf_destroy(dtp, &ddo->ddo_strs);
+ dt_buf_destroy(dtp, &ddo->ddo_ldata);
+ dt_buf_destroy(dtp, &ddo->ddo_udata);
+
+ 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);
+}
+
+static int
+dt_dof_reset(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
+{
+ dt_dof_t *ddo = &dtp->dt_dof;
+ uint_t i, nx = dtp->dt_xlatorid;
+
+ assert(ddo->ddo_hdl == dtp);
+ ddo->ddo_pgp = pgp;
+
+ ddo->ddo_nsecs = 0;
+ ddo->ddo_strsec = DOF_SECIDX_NONE;
+
+ dt_free(dtp, ddo->ddo_xlimport);
+ dt_free(dtp, ddo->ddo_xlexport);
+
+ ddo->ddo_xlimport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx);
+ ddo->ddo_xlexport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx);
+
+ if (nx != 0 && (ddo->ddo_xlimport == NULL || ddo->ddo_xlexport == NULL))
+ return (-1); /* errno is set for us */
+
+ for (i = 0; i < nx; i++) {
+ ddo->ddo_xlimport[i] = DOF_SECIDX_NONE;
+ ddo->ddo_xlexport[i] = DOF_SECIDX_NONE;
+ }
+
+ dt_buf_reset(dtp, &ddo->ddo_secs);
+ dt_buf_reset(dtp, &ddo->ddo_strs);
+ dt_buf_reset(dtp, &ddo->ddo_ldata);
+ dt_buf_reset(dtp, &ddo->ddo_udata);
+
+ 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);
+ return (0);
+}
+
+/*
+ * Add a loadable DOF section to the file using the specified data buffer and
+ * the specified DOF section attributes. DOF_SECF_LOAD must be set in flags.
+ * If 'data' is NULL, the caller is responsible for manipulating the ldata buf.
+ */
+static dof_secidx_t
+dof_add_lsect(dt_dof_t *ddo, const void *data, uint32_t type,
+ uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size)
+{
+ dtrace_hdl_t *dtp = ddo->ddo_hdl;
+ dof_sec_t s;
+
+ s.dofs_type = type;
+ s.dofs_align = align;
+ s.dofs_flags = flags | DOF_SECF_LOAD;
+ s.dofs_entsize = entsize;
+ s.dofs_offset = dt_buf_offset(&ddo->ddo_ldata, align);
+ s.dofs_size = size;
+
+ dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t));
+
+ if (data != NULL)
+ dt_buf_write(dtp, &ddo->ddo_ldata, data, size, align);
+
+ return (ddo->ddo_nsecs++);
+}
+
+/*
+ * Add an unloadable DOF section to the file using the specified data buffer
+ * and DOF section attributes. DOF_SECF_LOAD must *not* be set in flags.
+ * If 'data' is NULL, the caller is responsible for manipulating the udata buf.
+ */
+static dof_secidx_t
+dof_add_usect(dt_dof_t *ddo, const void *data, uint32_t type,
+ uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size)
+{
+ dtrace_hdl_t *dtp = ddo->ddo_hdl;
+ dof_sec_t s;
+
+ s.dofs_type = type;
+ s.dofs_align = align;
+ s.dofs_flags = flags & ~DOF_SECF_LOAD;
+ s.dofs_entsize = entsize;
+ s.dofs_offset = dt_buf_offset(&ddo->ddo_udata, align);
+ s.dofs_size = size;
+
+ dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t));
+
+ if (data != NULL)
+ dt_buf_write(dtp, &ddo->ddo_udata, data, size, align);
+
+ return (ddo->ddo_nsecs++);
+}
+
+/*
+ * Add a string to the global string table associated with the DOF. The offset
+ * of the string is returned as an index into the string table.
+ */
+static dof_stridx_t
+dof_add_string(dt_dof_t *ddo, const char *s)
+{
+ dt_buf_t *bp = &ddo->ddo_strs;
+ dof_stridx_t i = dt_buf_len(bp);
+
+ if (i != 0 && (s == NULL || *s == '\0'))
+ return (0); /* string table has \0 at offset 0 */
+
+ dt_buf_write(ddo->ddo_hdl, bp, s, strlen(s) + 1, sizeof (char));
+ return (i);
+}
+
+static dof_attr_t
+dof_attr(const dtrace_attribute_t *ap)
+{
+ return (DOF_ATTR(ap->dtat_name, ap->dtat_data, ap->dtat_class));
+}
+
+static dof_secidx_t
+dof_add_difo(dt_dof_t *ddo, const dtrace_difo_t *dp)
+{
+ dof_secidx_t dsecs[5]; /* enough for all possible DIFO sections */
+ uint_t nsecs = 0;
+
+ dof_difohdr_t *dofd;
+ dof_relohdr_t dofr;
+ dof_secidx_t relsec;
+
+ dof_secidx_t strsec = DOF_SECIDX_NONE;
+ dof_secidx_t intsec = DOF_SECIDX_NONE;
+ dof_secidx_t hdrsec = DOF_SECIDX_NONE;
+
+ if (dp->dtdo_buf != NULL) {
+ dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_buf,
+ DOF_SECT_DIF, sizeof (dif_instr_t), 0,
+ sizeof (dif_instr_t), sizeof (dif_instr_t) * dp->dtdo_len);
+ }
+
+ if (dp->dtdo_inttab != NULL) {
+ dsecs[nsecs++] = intsec = dof_add_lsect(ddo, dp->dtdo_inttab,
+ DOF_SECT_INTTAB, sizeof (uint64_t), 0,
+ sizeof (uint64_t), sizeof (uint64_t) * dp->dtdo_intlen);
+ }
+
+ if (dp->dtdo_strtab != NULL) {
+ dsecs[nsecs++] = strsec = dof_add_lsect(ddo, dp->dtdo_strtab,
+ DOF_SECT_STRTAB, sizeof (char), 0, 0, dp->dtdo_strlen);
+ }
+
+ if (dp->dtdo_vartab != NULL) {
+ dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_vartab,
+ DOF_SECT_VARTAB, sizeof (uint_t), 0, sizeof (dtrace_difv_t),
+ sizeof (dtrace_difv_t) * dp->dtdo_varlen);
+ }
+
+ if (dp->dtdo_xlmtab != NULL) {
+ dof_xlref_t *xlt, *xlp;
+ dt_node_t **pnp;
+
+ xlt = alloca(sizeof (dof_xlref_t) * dp->dtdo_xlmlen);
+ pnp = dp->dtdo_xlmtab;
+
+ /*
+ * dtdo_xlmtab contains pointers to the translator members.
+ * The translator itself is in sect ddo_xlimport[dxp->dx_id].
+ * The XLMEMBERS entries are in order by their dn_membid, so
+ * the member section offset is the population count of bits
+ * in ddo_pgp->dp_xlrefs[] up to and not including dn_membid.
+ */
+ for (xlp = xlt; xlp < xlt + dp->dtdo_xlmlen; xlp++) {
+ dt_node_t *dnp = *pnp++;
+ dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator;
+
+ xlp->dofxr_xlator = ddo->ddo_xlimport[dxp->dx_id];
+ xlp->dofxr_member = dt_popcb(
+ ddo->ddo_pgp->dp_xrefs[dxp->dx_id], dnp->dn_membid);
+ xlp->dofxr_argn = (uint32_t)dxp->dx_arg;
+ }
+
+ dsecs[nsecs++] = dof_add_lsect(ddo, xlt, DOF_SECT_XLTAB,
+ sizeof (dof_secidx_t), 0, sizeof (dof_xlref_t),
+ sizeof (dof_xlref_t) * dp->dtdo_xlmlen);
+ }
+
+ /*
+ * Copy the return type and the array of section indices that form the
+ * DIFO into a single dof_difohdr_t and then add DOF_SECT_DIFOHDR.
+ */
+ assert(nsecs <= sizeof (dsecs) / sizeof (dsecs[0]));
+ dofd = alloca(sizeof (dtrace_diftype_t) + sizeof (dsecs));
+ bcopy(&dp->dtdo_rtype, &dofd->dofd_rtype, sizeof (dtrace_diftype_t));
+ bcopy(dsecs, &dofd->dofd_links, sizeof (dof_secidx_t) * nsecs);
+
+ hdrsec = dof_add_lsect(ddo, dofd, DOF_SECT_DIFOHDR,
+ sizeof (dof_secidx_t), 0, 0,
+ sizeof (dtrace_diftype_t) + sizeof (dof_secidx_t) * nsecs);
+
+ /*
+ * Add any other sections related to dtrace_difo_t. These are not
+ * referenced in dof_difohdr_t because they are not used by emulation.
+ */
+ if (dp->dtdo_kreltab != NULL) {
+ relsec = dof_add_lsect(ddo, dp->dtdo_kreltab, DOF_SECT_RELTAB,
+ sizeof (uint64_t), 0, sizeof (dof_relodesc_t),
+ sizeof (dof_relodesc_t) * dp->dtdo_krelen);
+
+ /*
+ * This code assumes the target of all relocations is the
+ * integer table 'intsec' (DOF_SECT_INTTAB). If other sections
+ * need relocation in the future this will need to change.
+ */
+ dofr.dofr_strtab = strsec;
+ dofr.dofr_relsec = relsec;
+ dofr.dofr_tgtsec = intsec;
+
+ (void) dof_add_lsect(ddo, &dofr, DOF_SECT_KRELHDR,
+ sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));
+ }
+
+ if (dp->dtdo_ureltab != NULL) {
+ relsec = dof_add_lsect(ddo, dp->dtdo_ureltab, DOF_SECT_RELTAB,
+ sizeof (uint64_t), 0, sizeof (dof_relodesc_t),
+ sizeof (dof_relodesc_t) * dp->dtdo_urelen);
+
+ /*
+ * This code assumes the target of all relocations is the
+ * integer table 'intsec' (DOF_SECT_INTTAB). If other sections
+ * need relocation in the future this will need to change.
+ */
+ dofr.dofr_strtab = strsec;
+ dofr.dofr_relsec = relsec;
+ dofr.dofr_tgtsec = intsec;
+
+ (void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR,
+ sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));
+ }
+
+ return (hdrsec);
+}
+
+static void
+dof_add_translator(dt_dof_t *ddo, const dt_xlator_t *dxp, uint_t type)
+{
+ dtrace_hdl_t *dtp = ddo->ddo_hdl;
+ dof_xlmember_t dofxm;
+ dof_xlator_t dofxl;
+ dof_secidx_t *xst;
+
+ char buf[DT_TYPE_NAMELEN];
+ dt_node_t *dnp;
+ uint_t i = 0;
+
+ assert(type == DOF_SECT_XLIMPORT || type == DOF_SECT_XLEXPORT);
+ xst = type == DOF_SECT_XLIMPORT ? ddo->ddo_xlimport : ddo->ddo_xlexport;
+
+ if (xst[dxp->dx_id] != DOF_SECIDX_NONE)
+ return; /* translator has already been emitted */
+
+ dt_buf_reset(dtp, &ddo->ddo_xlms);
+
+ /*
+ * Generate an array of dof_xlmember_t's into ddo_xlms. If we are
+ * importing the translator, add only those members referenced by the
+ * program and set the dofxm_difo reference of each member to NONE. If
+ * we're exporting the translator, add all members and a DIFO for each.
+ */
+ for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list, i++) {
+ if (type == DOF_SECT_XLIMPORT) {
+ if (!BT_TEST(ddo->ddo_pgp->dp_xrefs[dxp->dx_id], i))
+ continue; /* member is not referenced */
+ dofxm.dofxm_difo = DOF_SECIDX_NONE;
+ } else {
+ dofxm.dofxm_difo = dof_add_difo(ddo,
+ dxp->dx_membdif[dnp->dn_membid]);
+ }
+
+ dofxm.dofxm_name = dof_add_string(ddo, dnp->dn_membname);
+ dt_node_diftype(dtp, dnp, &dofxm.dofxm_type);
+
+ dt_buf_write(dtp, &ddo->ddo_xlms,
+ &dofxm, sizeof (dofxm), sizeof (uint32_t));
+ }
+
+ dofxl.dofxl_members = dof_add_lsect(ddo, NULL, DOF_SECT_XLMEMBERS,
+ sizeof (uint32_t), 0, sizeof (dofxm), dt_buf_len(&ddo->ddo_xlms));
+
+ dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_xlms, sizeof (uint32_t));
+
+ dofxl.dofxl_strtab = ddo->ddo_strsec;
+ dofxl.dofxl_argv = dof_add_string(ddo, ctf_type_name(
+ dxp->dx_src_ctfp, dxp->dx_src_type, buf, sizeof (buf)));
+ dofxl.dofxl_argc = 1;
+ dofxl.dofxl_type = dof_add_string(ddo, ctf_type_name(
+ dxp->dx_dst_ctfp, dxp->dx_dst_type, buf, sizeof (buf)));
+ dofxl.dofxl_attr = dof_attr(&dxp->dx_souid.di_attr);
+
+ xst[dxp->dx_id] = dof_add_lsect(ddo, &dofxl, type,
+ sizeof (uint32_t), 0, 0, sizeof (dofxl));
+}
+
+/*ARGSUSED*/
+static int
+dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
+{
+ dt_dof_t *ddo = data;
+ dtrace_hdl_t *dtp = ddo->ddo_hdl;
+ dt_probe_t *prp = idp->di_data;
+
+ dof_probe_t dofpr;
+ dof_relodesc_t dofr;
+ dt_probe_instance_t *pip;
+ dt_node_t *dnp;
+
+ char buf[DT_TYPE_NAMELEN];
+ uint_t i;
+
+ dofpr.dofpr_addr = 0;
+ dofpr.dofpr_name = dof_add_string(ddo, prp->pr_name);
+ dofpr.dofpr_nargv = dt_buf_len(&ddo->ddo_strs);
+
+ for (dnp = prp->pr_nargs; dnp != NULL; dnp = dnp->dn_list) {
+ (void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp,
+ dnp->dn_type, buf, sizeof (buf)));
+ }
+
+ dofpr.dofpr_xargv = dt_buf_len(&ddo->ddo_strs);
+
+ for (dnp = prp->pr_xargs; dnp != NULL; dnp = dnp->dn_list) {
+ (void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp,
+ dnp->dn_type, buf, sizeof (buf)));
+ }
+
+ dofpr.dofpr_argidx = dt_buf_len(&ddo->ddo_args) / sizeof (uint8_t);
+
+ for (i = 0; i < prp->pr_xargc; i++) {
+ dt_buf_write(dtp, &ddo->ddo_args, &prp->pr_mapping[i],
+ sizeof (uint8_t), sizeof (uint8_t));
+ }
+
+ dofpr.dofpr_nargc = prp->pr_nargc;
+ dofpr.dofpr_xargc = prp->pr_xargc;
+ 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);
+
+ /*
+ * There should be one probe offset or is-enabled probe offset
+ * or else this probe instance won't have been created. The
+ * kernel will reject DOF which has a probe with no offsets.
+ */
+ assert(pip->pi_noffs + pip->pi_nenoffs > 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_nenoffs * sizeof (uint32_t), sizeof (uint32_t));
+
+ dofr.dofr_name = dof_add_string(ddo, pip->pi_rname);
+ dofr.dofr_type = DOF_RELO_DOFREL;
+ dofr.dofr_offset = dt_buf_len(&ddo->ddo_probes);
+ dofr.dofr_data = 0;
+
+ dt_buf_write(dtp, &ddo->ddo_rels, &dofr,
+ sizeof (dofr), sizeof (uint64_t));
+
+ dt_buf_write(dtp, &ddo->ddo_probes, &dofpr,
+ sizeof (dofpr), sizeof (uint64_t));
+ }
+
+ return (0);
+}
+
+static int
+dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
+{
+ dtrace_hdl_t *dtp = ddo->ddo_hdl;
+ dof_provider_t dofpv;
+ dof_relohdr_t dofr;
+ dof_secidx_t *dofs;
+ ulong_t xr, nxr;
+ size_t sz;
+ id_t i;
+
+ if (pvp->pv_flags & DT_PROVIDER_IMPL) {
+ /*
+ * ignore providers that are exported by dtrace(7D)
+ */
+ return (0);
+ }
+
+ nxr = dt_popcb(pvp->pv_xrefs, pvp->pv_xrmax);
+ dofs = alloca(sizeof (dof_secidx_t) * (nxr + 1));
+ xr = 1; /* reserve dofs[0] for the provider itself */
+
+ /*
+ * For each translator referenced by the provider (pv_xrefs), emit an
+ * exported translator section for it if one hasn't been created yet.
+ */
+ for (i = 0; i < pvp->pv_xrmax; i++) {
+ if (BT_TEST(pvp->pv_xrefs, i) &&
+ dtp->dt_xlatemode == DT_XL_DYNAMIC) {
+ dof_add_translator(ddo,
+ dt_xlator_lookup_id(dtp, i), DOF_SECT_XLEXPORT);
+ dofs[xr++] = ddo->ddo_xlexport[i];
+ }
+ }
+
+ 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);
+
+ if (dt_buf_len(&ddo->ddo_probes) == 0)
+ return (dt_set_errno(dtp, EDT_NOPROBES));
+
+ dofpv.dofpv_probes = dof_add_lsect(ddo, NULL, DOF_SECT_PROBES,
+ sizeof (uint64_t), 0, sizeof (dof_probe_t),
+ dt_buf_len(&ddo->ddo_probes));
+
+ dt_buf_concat(dtp, &ddo->ddo_ldata,
+ &ddo->ddo_probes, sizeof (uint64_t));
+
+ dofpv.dofpv_prargs = dof_add_lsect(ddo, NULL, DOF_SECT_PRARGS,
+ sizeof (uint8_t), 0, sizeof (uint8_t), dt_buf_len(&ddo->ddo_args));
+
+ dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_args, sizeof (uint8_t));
+
+ 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));
+
+ if ((sz = dt_buf_len(&ddo->ddo_enoffs)) != 0) {
+ dofpv.dofpv_prenoffs = dof_add_lsect(ddo, NULL,
+ DOF_SECT_PRENOFFS, sizeof (uint_t), 0, sizeof (uint_t), sz);
+ } else {
+ dofpv.dofpv_prenoffs = DOF_SECT_NONE;
+ }
+
+ 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);
+
+ dofpv.dofpv_provattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_provider);
+ dofpv.dofpv_modattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_mod);
+ dofpv.dofpv_funcattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_func);
+ dofpv.dofpv_nameattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_name);
+ dofpv.dofpv_argsattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_args);
+
+ dofs[0] = dof_add_lsect(ddo, &dofpv, DOF_SECT_PROVIDER,
+ sizeof (dof_secidx_t), 0, 0, sizeof (dof_provider_t));
+
+ dofr.dofr_strtab = dofpv.dofpv_strtab;
+ dofr.dofr_tgtsec = dofpv.dofpv_probes;
+ dofr.dofr_relsec = dof_add_lsect(ddo, NULL, DOF_SECT_RELTAB,
+ sizeof (uint64_t), 0, sizeof (dof_relodesc_t),
+ dt_buf_len(&ddo->ddo_rels));
+
+ dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_rels, sizeof (uint64_t));
+
+ (void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR,
+ sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));
+
+ if (nxr != 0 && dtp->dt_xlatemode == DT_XL_DYNAMIC) {
+ (void) dof_add_lsect(ddo, dofs, DOF_SECT_PREXPORT,
+ sizeof (dof_secidx_t), 0, sizeof (dof_secidx_t),
+ sizeof (dof_secidx_t) * (nxr + 1));
+ }
+
+ return (0);
+}
+
+static int
+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
+ * DOF header since the values won't fit. This can only happen if the
+ * user forcibly compiles a program with an artificial configuration.
+ */
+ if (dtp->dt_conf.dtc_difversion > UINT8_MAX ||
+ dtp->dt_conf.dtc_difintregs > UINT8_MAX ||
+ dtp->dt_conf.dtc_diftupregs > UINT8_MAX)
+ return (dt_set_errno(dtp, EOVERFLOW));
+
+ bzero(hp, sizeof (dof_hdr_t));
+
+ hp->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0;
+ hp->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1;
+ hp->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2;
+ hp->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3;
+
+ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
+ hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_LP64;
+ else
+ hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_ILP32;
+
+ hp->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE;
+ 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;
+
+ hp->dofh_hdrsize = sizeof (dof_hdr_t);
+ hp->dofh_secsize = sizeof (dof_sec_t);
+ hp->dofh_secoff = sizeof (dof_hdr_t);
+
+ return (0);
+}
+
+void *
+dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
+{
+ dt_dof_t *ddo = &dtp->dt_dof;
+
+ const dtrace_ecbdesc_t *edp, *last;
+ const dtrace_probedesc_t *pdp;
+ const dtrace_actdesc_t *ap;
+ const dt_stmt_t *stp;
+
+ uint_t maxacts = 0;
+ uint_t maxfmt = 0;
+
+ dt_provider_t *pvp;
+ dt_xlator_t *dxp;
+ dof_actdesc_t *dofa;
+ dof_sec_t *sp;
+ size_t ssize, lsize;
+ dof_hdr_t h;
+
+ dt_buf_t dof;
+ char *fmt;
+ uint_t i;
+
+ if (flags & ~DTRACE_D_MASK) {
+ (void) dt_set_errno(dtp, EINVAL);
+ return (NULL);
+ }
+
+ flags |= dtp->dt_dflags;
+
+ if (dof_hdr(dtp, pgp->dp_dofversion, &h) != 0)
+ return (NULL);
+
+ if (dt_dof_reset(dtp, pgp) != 0)
+ return (NULL);
+
+ /*
+ * Iterate through the statement list computing the maximum number of
+ * actions and the maximum format string for allocating local buffers.
+ */
+ for (last = NULL, stp = dt_list_next(&pgp->dp_stmts);
+ stp != NULL; stp = dt_list_next(stp), last = edp) {
+
+ dtrace_stmtdesc_t *sdp = stp->ds_desc;
+ dtrace_actdesc_t *ap = sdp->dtsd_action;
+
+ if (sdp->dtsd_fmtdata != NULL) {
+ i = dtrace_printf_format(dtp,
+ sdp->dtsd_fmtdata, NULL, 0);
+ maxfmt = MAX(maxfmt, i);
+ }
+
+ if ((edp = sdp->dtsd_ecbdesc) == last)
+ continue; /* same ecb as previous statement */
+
+ for (i = 0, ap = edp->dted_action; ap; ap = ap->dtad_next)
+ i++;
+
+ maxacts = MAX(maxacts, i);
+ }
+
+ dofa = alloca(sizeof (dof_actdesc_t) * maxacts);
+ fmt = alloca(maxfmt + 1);
+
+ ddo->ddo_strsec = dof_add_lsect(ddo, NULL, DOF_SECT_STRTAB, 1, 0, 0, 0);
+ (void) dof_add_string(ddo, "");
+
+ /*
+ * If there are references to dynamic translators in the program, add
+ * an imported translator table entry for each referenced translator.
+ */
+ if (pgp->dp_xrefslen != 0) {
+ for (dxp = dt_list_next(&dtp->dt_xlators);
+ dxp != NULL; dxp = dt_list_next(dxp)) {
+ if (dxp->dx_id < pgp->dp_xrefslen &&
+ pgp->dp_xrefs[dxp->dx_id] != NULL)
+ dof_add_translator(ddo, dxp, DOF_SECT_XLIMPORT);
+ }
+ }
+
+ /*
+ * Now iterate through the statement list, creating the DOF section
+ * headers and data for each one and adding them to our buffers.
+ */
+ for (last = NULL, stp = dt_list_next(&pgp->dp_stmts);
+ stp != NULL; stp = dt_list_next(stp), last = edp) {
+
+ dof_secidx_t probesec = DOF_SECIDX_NONE;
+ dof_secidx_t prdsec = DOF_SECIDX_NONE;
+ dof_secidx_t actsec = DOF_SECIDX_NONE;
+
+ const dt_stmt_t *next = stp;
+ dtrace_stmtdesc_t *sdp = stp->ds_desc;
+ dof_stridx_t strndx = 0;
+ dof_probedesc_t dofp;
+ dof_ecbdesc_t dofe;
+ uint_t i;
+
+ if ((edp = stp->ds_desc->dtsd_ecbdesc) == last)
+ continue; /* same ecb as previous statement */
+
+ pdp = &edp->dted_probe;
+
+ /*
+ * Add a DOF_SECT_PROBEDESC for the ECB's probe description,
+ * and copy the probe description strings into the string table.
+ */
+ dofp.dofp_strtab = ddo->ddo_strsec;
+ dofp.dofp_provider = dof_add_string(ddo, pdp->dtpd_provider);
+ dofp.dofp_mod = dof_add_string(ddo, pdp->dtpd_mod);
+ dofp.dofp_func = dof_add_string(ddo, pdp->dtpd_func);
+ dofp.dofp_name = dof_add_string(ddo, pdp->dtpd_name);
+ dofp.dofp_id = pdp->dtpd_id;
+
+ probesec = dof_add_lsect(ddo, &dofp, DOF_SECT_PROBEDESC,
+ sizeof (dof_secidx_t), 0,
+ sizeof (dof_probedesc_t), sizeof (dof_probedesc_t));
+
+ /*
+ * If there is a predicate DIFO associated with the ecbdesc,
+ * write out the DIFO sections and save the DIFO section index.
+ */
+ if (edp->dted_pred.dtpdd_difo != NULL)
+ prdsec = dof_add_difo(ddo, edp->dted_pred.dtpdd_difo);
+
+ /*
+ * Now iterate through the action list generating DIFOs as
+ * referenced therein and adding action descriptions to 'dofa'.
+ */
+ for (i = 0, ap = edp->dted_action;
+ ap != NULL; ap = ap->dtad_next, i++) {
+
+ if (ap->dtad_difo != NULL) {
+ dofa[i].dofa_difo =
+ dof_add_difo(ddo, ap->dtad_difo);
+ } else
+ dofa[i].dofa_difo = DOF_SECIDX_NONE;
+
+ /*
+ * If the first action in a statement has string data,
+ * add the string to the global string table. This can
+ * be due either to a printf() format string
+ * (dtsd_fmtdata) or a print() type string
+ * (dtsd_strdata).
+ */
+ if (sdp != NULL && ap == sdp->dtsd_action) {
+ if (sdp->dtsd_fmtdata != NULL) {
+ (void) dtrace_printf_format(dtp,
+ sdp->dtsd_fmtdata, fmt, maxfmt + 1);
+ strndx = dof_add_string(ddo, fmt);
+ } else if (sdp->dtsd_strdata != NULL) {
+ strndx = dof_add_string(ddo,
+ sdp->dtsd_strdata);
+ } else {
+ strndx = 0; /* use dtad_arg instead */
+ }
+
+ if ((next = dt_list_next(next)) != NULL)
+ sdp = next->ds_desc;
+ else
+ sdp = NULL;
+ }
+
+ if (strndx != 0) {
+ dofa[i].dofa_arg = strndx;
+ dofa[i].dofa_strtab = ddo->ddo_strsec;
+ } else {
+ dofa[i].dofa_arg = ap->dtad_arg;
+ dofa[i].dofa_strtab = DOF_SECIDX_NONE;
+ }
+
+ dofa[i].dofa_kind = ap->dtad_kind;
+ dofa[i].dofa_ntuple = ap->dtad_ntuple;
+ dofa[i].dofa_uarg = ap->dtad_uarg;
+ }
+
+ if (i > 0) {
+ actsec = dof_add_lsect(ddo, dofa, DOF_SECT_ACTDESC,
+ sizeof (uint64_t), 0, sizeof (dof_actdesc_t),
+ sizeof (dof_actdesc_t) * i);
+ }
+
+ /*
+ * Now finally, add the DOF_SECT_ECBDESC referencing all the
+ * previously created sub-sections.
+ */
+ dofe.dofe_probes = probesec;
+ dofe.dofe_pred = prdsec;
+ dofe.dofe_actions = actsec;
+ dofe.dofe_pad = 0;
+ dofe.dofe_uarg = edp->dted_uarg;
+
+ (void) dof_add_lsect(ddo, &dofe, DOF_SECT_ECBDESC,
+ sizeof (uint64_t), 0, 0, sizeof (dof_ecbdesc_t));
+ }
+
+ /*
+ * If any providers are user-defined, output DOF sections corresponding
+ * to the providers and the probes and arguments that they define.
+ */
+ if (flags & DTRACE_D_PROBES) {
+ for (pvp = dt_list_next(&dtp->dt_provlist);
+ pvp != NULL; pvp = dt_list_next(pvp)) {
+ if (dof_add_provider(ddo, pvp) != 0)
+ return (NULL);
+ }
+ }
+
+ /*
+ * If we're not stripping unloadable sections, generate compiler
+ * comments and any other unloadable miscellany.
+ */
+ if (!(flags & DTRACE_D_STRIP)) {
+ (void) dof_add_usect(ddo, _dtrace_version, DOF_SECT_COMMENTS,
+ sizeof (char), 0, 0, strlen(_dtrace_version) + 1);
+ (void) dof_add_usect(ddo, &dtp->dt_uts, DOF_SECT_UTSNAME,
+ sizeof (char), 0, 0, sizeof (struct utsname));
+ }
+
+ /*
+ * Compute and fill in the appropriate values for the dof_hdr_t's
+ * dofh_secnum, dofh_loadsz, and dofh_filez values.
+ */
+ h.dofh_secnum = ddo->ddo_nsecs;
+ ssize = sizeof (h) + dt_buf_len(&ddo->ddo_secs);
+
+ h.dofh_loadsz = ssize +
+ dt_buf_len(&ddo->ddo_ldata) +
+ dt_buf_len(&ddo->ddo_strs);
+
+ if (dt_buf_len(&ddo->ddo_udata) != 0) {
+ lsize = roundup(h.dofh_loadsz, sizeof (uint64_t));
+ h.dofh_filesz = lsize + dt_buf_len(&ddo->ddo_udata);
+ } else {
+ lsize = h.dofh_loadsz;
+ h.dofh_filesz = lsize;
+ }
+
+ /*
+ * Set the global DOF_SECT_STRTAB's offset to be after the header,
+ * section headers, and other loadable data. Since we're going to
+ * iterate over the buffer data directly, we must check for errors.
+ */
+ if ((i = dt_buf_error(&ddo->ddo_secs)) != 0) {
+ (void) dt_set_errno(dtp, i);
+ return (NULL);
+ }
+
+ sp = dt_buf_ptr(&ddo->ddo_secs);
+ assert(sp[ddo->ddo_strsec].dofs_type == DOF_SECT_STRTAB);
+ assert(ssize == sizeof (h) + sizeof (dof_sec_t) * ddo->ddo_nsecs);
+
+ sp[ddo->ddo_strsec].dofs_offset = ssize + dt_buf_len(&ddo->ddo_ldata);
+ sp[ddo->ddo_strsec].dofs_size = dt_buf_len(&ddo->ddo_strs);
+
+ /*
+ * Now relocate all the other section headers by adding the appropriate
+ * delta to their respective dofs_offset values.
+ */
+ for (i = 0; i < ddo->ddo_nsecs; i++, sp++) {
+ if (i == ddo->ddo_strsec)
+ continue; /* already relocated above */
+
+ if (sp->dofs_flags & DOF_SECF_LOAD)
+ sp->dofs_offset += ssize;
+ else
+ sp->dofs_offset += lsize;
+ }
+
+ /*
+ * Finally, assemble the complete in-memory DOF buffer by writing the
+ * header and then concatenating all our buffers. dt_buf_concat() will
+ * propagate any errors and cause dt_buf_claim() to return NULL.
+ */
+ dt_buf_create(dtp, &dof, "dof", h.dofh_filesz);
+
+ dt_buf_write(dtp, &dof, &h, sizeof (h), sizeof (uint64_t));
+ dt_buf_concat(dtp, &dof, &ddo->ddo_secs, sizeof (uint64_t));
+ dt_buf_concat(dtp, &dof, &ddo->ddo_ldata, sizeof (uint64_t));
+ dt_buf_concat(dtp, &dof, &ddo->ddo_strs, sizeof (char));
+ dt_buf_concat(dtp, &dof, &ddo->ddo_udata, sizeof (uint64_t));
+
+ return (dt_buf_claim(dtp, &dof));
+}
+
+void
+dtrace_dof_destroy(dtrace_hdl_t *dtp, void *dof)
+{
+ dt_free(dtp, dof);
+}
+
+void *
+dtrace_getopt_dof(dtrace_hdl_t *dtp)
+{
+ dof_hdr_t *dof;
+ dof_sec_t *sec;
+ dof_optdesc_t *dofo;
+ int i, nopts = 0, len = sizeof (dof_hdr_t) +
+ roundup(sizeof (dof_sec_t), sizeof (uint64_t));
+
+ for (i = 0; i < DTRACEOPT_MAX; i++) {
+ if (dtp->dt_options[i] != DTRACEOPT_UNSET)
+ nopts++;
+ }
+
+ len += sizeof (dof_optdesc_t) * nopts;
+
+ if ((dof = dt_zalloc(dtp, len)) == NULL ||
+ dof_hdr(dtp, DOF_VERSION, dof) != 0) {
+ dt_free(dtp, dof);
+ return (NULL);
+ }
+
+ dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */
+ dof->dofh_loadsz = len;
+ dof->dofh_filesz = len;
+
+ /*
+ * Fill in the option section header...
+ */
+ sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t));
+ sec->dofs_type = DOF_SECT_OPTDESC;
+ sec->dofs_align = sizeof (uint64_t);
+ sec->dofs_flags = DOF_SECF_LOAD;
+ sec->dofs_entsize = sizeof (dof_optdesc_t);
+
+ dofo = (dof_optdesc_t *)((uintptr_t)sec +
+ roundup(sizeof (dof_sec_t), sizeof (uint64_t)));
+
+ sec->dofs_offset = (uintptr_t)dofo - (uintptr_t)dof;
+ sec->dofs_size = sizeof (dof_optdesc_t) * nopts;
+
+ for (i = 0; i < DTRACEOPT_MAX; i++) {
+ if (dtp->dt_options[i] == DTRACEOPT_UNSET)
+ continue;
+
+ dofo->dofo_option = i;
+ dofo->dofo_strtab = DOF_SECIDX_NONE;
+ dofo->dofo_value = dtp->dt_options[i];
+ dofo++;
+ }
+
+ return (dof);
+}
+
+void *
+dtrace_geterr_dof(dtrace_hdl_t *dtp)
+{
+ if (dtp->dt_errprog != NULL)
+ return (dtrace_dof_create(dtp, dtp->dt_errprog, 0));
+
+ (void) dt_set_errno(dtp, EDT_BADERROR);
+ return (NULL);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.h
new file mode 100644
index 000000000000..e0a4bf52502d
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.h
@@ -0,0 +1,66 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_DOF_H
+#define _DT_DOF_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <dtrace.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dt_buf.h>
+
+typedef struct dt_dof {
+ dtrace_hdl_t *ddo_hdl; /* libdtrace handle */
+ dtrace_prog_t *ddo_pgp; /* current program */
+ uint_t ddo_nsecs; /* number of sections */
+ dof_secidx_t ddo_strsec; /* global strings section index */
+ dof_secidx_t *ddo_xlimport; /* imported xlator section indices */
+ dof_secidx_t *ddo_xlexport; /* exported xlator section indices */
+ dt_buf_t ddo_secs; /* section headers */
+ dt_buf_t ddo_strs; /* global strings */
+ dt_buf_t ddo_ldata; /* loadable section data */
+ dt_buf_t ddo_udata; /* unloadable section data */
+ 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;
+
+extern void dt_dof_init(dtrace_hdl_t *);
+extern void dt_dof_fini(dtrace_hdl_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_DOF_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c
new file mode 100644
index 000000000000..339e2de5d150
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c
@@ -0,0 +1,241 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <string.h>
+#include <strings.h>
+#include <dt_impl.h>
+
+static const struct {
+ int err;
+ const char *msg;
+} _dt_errlist[] = {
+ { EDT_VERSION, "Client requested version newer than library" },
+ { EDT_VERSINVAL, "Version is not properly formatted or is too large" },
+ { EDT_VERSUNDEF, "Requested version is not supported by compiler" },
+ { EDT_VERSREDUCED, "Requested version conflicts with earlier setting" },
+ { EDT_CTF, "Unexpected libctf error" },
+ { EDT_COMPILER, "Error in D program compilation" },
+ { EDT_NOTUPREG, "Insufficient tuple registers to generate code" },
+ { EDT_NOMEM, "Memory allocation failure" },
+ { EDT_INT2BIG, "Integer constant table limit exceeded" },
+ { EDT_STR2BIG, "String constant table limit exceeded" },
+ { EDT_NOMOD, "Unknown module name" },
+ { EDT_NOPROV, "Unknown provider name" },
+ { EDT_NOPROBE, "No probe matches description" },
+ { EDT_NOSYM, "Unknown symbol name" },
+ { EDT_NOSYMADDR, "No symbol corresponds to address" },
+ { EDT_NOTYPE, "Unknown type name" },
+ { EDT_NOVAR, "Unknown variable name" },
+ { EDT_NOAGG, "Unknown aggregation name" },
+ { EDT_BADSCOPE, "Improper use of scoping operator in type name" },
+ { EDT_BADSPEC, "Overspecified probe description" },
+ { EDT_BADSPCV, "Undefined macro variable in probe description" },
+ { EDT_BADID, "Unknown probe identifier" },
+ { EDT_NOTLOADED, "Module is no longer loaded" },
+ { EDT_NOCTF, "Module does not contain any CTF data" },
+ { EDT_DATAMODEL, "Module and program data models do not match" },
+ { EDT_DIFVERS, "Library uses newer DIF version than kernel" },
+ { EDT_BADAGG, "Unknown aggregating action" },
+ { EDT_FIO, "Error occurred while reading from input stream" },
+ { EDT_DIFINVAL, "DIF program content is invalid" },
+ { EDT_DIFSIZE, "DIF program exceeds maximum program size" },
+ { EDT_DIFFAULT, "DIF program contains invalid pointer" },
+ { EDT_BADPROBE, "Invalid probe specification" },
+ { EDT_BADPGLOB, "Probe description has too many globbing characters" },
+ { EDT_NOSCOPE, "Declaration scope stack underflow" },
+ { EDT_NODECL, "Declaration stack underflow" },
+ { EDT_DMISMATCH, "Data record list does not match statement" },
+ { EDT_DOFFSET, "Data record offset exceeds buffer boundary" },
+ { EDT_DALIGN, "Data record has inappropriate alignment" },
+ { EDT_BADOPTNAME, "Invalid option name" },
+ { EDT_BADOPTVAL, "Invalid value for specified option" },
+ { EDT_BADOPTCTX, "Option cannot be used from within a D program" },
+ { EDT_CPPFORK, "Failed to fork preprocessor" },
+ { EDT_CPPEXEC, "Failed to exec preprocessor" },
+ { EDT_CPPENT, "Preprocessor not found" },
+ { EDT_CPPERR, "Preprocessor failed to process input program" },
+ { EDT_SYMOFLOW, "Symbol table identifier space exhausted" },
+ { EDT_ACTIVE, "Operation illegal when tracing is active" },
+ { EDT_DESTRUCTIVE, "Destructive actions not allowed" },
+ { EDT_NOANON, "No anonymous tracing state" },
+ { EDT_ISANON, "Can't claim anonymous state and enable probes" },
+ { EDT_ENDTOOBIG, "END enablings exceed size of principal buffer" },
+ { EDT_NOCONV, "Failed to load type for printf conversion" },
+ { EDT_BADCONV, "Incomplete printf conversion" },
+ { EDT_BADERROR, "Invalid library ERROR action" },
+ { EDT_ERRABORT, "Abort due to error" },
+ { EDT_DROPABORT, "Abort due to drop" },
+ { EDT_DIRABORT, "Abort explicitly directed" },
+ { EDT_BADRVAL, "Invalid return value from callback" },
+ { EDT_BADNORMAL, "Invalid normalization" },
+ { EDT_BUFTOOSMALL, "Enabling exceeds size of buffer" },
+ { EDT_BADTRUNC, "Invalid truncation" },
+ { EDT_BUSY, "DTrace cannot be used when kernel debugger is active" },
+ { EDT_ACCESS, "DTrace requires additional privileges" },
+ { EDT_NOENT, "DTrace device not available on system" },
+ { EDT_BRICKED, "Abort due to systemic unresponsiveness" },
+ { EDT_HARDWIRE, "Failed to load language definitions" },
+ { EDT_ELFVERSION, "libelf is out-of-date with respect to libdtrace" },
+ { EDT_NOBUFFERED, "Attempt to buffer output without handler" },
+ { EDT_UNSTABLE, "Description matched an unstable set of probes" },
+ { EDT_BADSETOPT, "Invalid setopt() library action" },
+ { EDT_BADSTACKPC, "Invalid stack program counter size" },
+ { EDT_BADAGGVAR, "Invalid aggregation variable identifier" },
+ { EDT_OVERSION, "Client requested deprecated version of library" },
+ { EDT_ENABLING_ERR, "Failed to enable probe" },
+ { EDT_NOPROBES, "No probe sites found for declared provider" },
+ { EDT_CANTLOAD, "Failed to load module" },
+};
+
+static const int _dt_nerr = sizeof (_dt_errlist) / sizeof (_dt_errlist[0]);
+
+const char *
+dtrace_errmsg(dtrace_hdl_t *dtp, int error)
+{
+ const char *str;
+ int i;
+
+ if (error == EDT_COMPILER && dtp != NULL && dtp->dt_errmsg[0] != '\0')
+ str = dtp->dt_errmsg;
+ else if (error == EDT_CTF && dtp != NULL && dtp->dt_ctferr != 0)
+ str = ctf_errmsg(dtp->dt_ctferr);
+ else if (error >= EDT_BASE && (error - EDT_BASE) < _dt_nerr) {
+ for (i = 0; i < _dt_nerr; i++) {
+ if (_dt_errlist[i].err == error)
+ return (_dt_errlist[i].msg);
+ }
+ str = NULL;
+ } else
+ str = strerror(error);
+
+ return (str ? str : "Unknown error");
+}
+
+int
+dtrace_errno(dtrace_hdl_t *dtp)
+{
+ return (dtp->dt_errno);
+}
+
+#ifdef illumos
+int
+dt_set_errno(dtrace_hdl_t *dtp, int err)
+{
+ dtp->dt_errno = err;
+ return (-1);
+}
+#else
+int
+_dt_set_errno(dtrace_hdl_t *dtp, int err, const char *errfile, int errline)
+{
+ dtp->dt_errno = err;
+ dtp->dt_errfile = errfile;
+ dtp->dt_errline = errline;
+ return (-1);
+}
+
+void dt_get_errloc(dtrace_hdl_t *dtp, const char **p_errfile, int *p_errline)
+{
+ *p_errfile = dtp->dt_errfile;
+ *p_errline = dtp->dt_errline;
+}
+#endif
+
+void
+dt_set_errmsg(dtrace_hdl_t *dtp, const char *errtag, const char *region,
+ const char *filename, int lineno, const char *format, va_list ap)
+{
+ size_t len, n;
+ char *p, *s;
+
+ s = dtp->dt_errmsg;
+ n = sizeof (dtp->dt_errmsg);
+
+ if (errtag != NULL && (yypcb->pcb_cflags & DTRACE_C_ETAGS))
+ (void) snprintf(s, n, "[%s] ", errtag);
+ else
+ s[0] = '\0';
+
+ len = strlen(dtp->dt_errmsg);
+ s = dtp->dt_errmsg + len;
+ n = sizeof (dtp->dt_errmsg) - len;
+
+ if (filename == NULL)
+ filename = dtp->dt_filetag;
+
+ if (filename != NULL)
+ (void) snprintf(s, n, "\"%s\", line %d: ", filename, lineno);
+ else if (lineno != 0)
+ (void) snprintf(s, n, "line %d: ", lineno);
+ else if (region != NULL)
+ (void) snprintf(s, n, "in %s: ", region);
+
+ len = strlen(dtp->dt_errmsg);
+ s = dtp->dt_errmsg + len;
+ n = sizeof (dtp->dt_errmsg) - len;
+ (void) vsnprintf(s, n, format, ap);
+
+ if ((p = strrchr(dtp->dt_errmsg, '\n')) != NULL)
+ *p = '\0'; /* remove trailing \n from message buffer */
+
+ dtp->dt_errtag = errtag;
+}
+
+/*ARGSUSED*/
+const char *
+dtrace_faultstr(dtrace_hdl_t *dtp, int fault)
+{
+ int i;
+
+ static const struct {
+ int code;
+ const char *str;
+ } faults[] = {
+ { DTRACEFLT_BADADDR, "invalid address" },
+ { DTRACEFLT_BADALIGN, "invalid alignment" },
+ { DTRACEFLT_ILLOP, "illegal operation" },
+ { DTRACEFLT_DIVZERO, "divide-by-zero" },
+ { DTRACEFLT_NOSCRATCH, "out of scratch space" },
+ { DTRACEFLT_KPRIV, "invalid kernel access" },
+ { DTRACEFLT_UPRIV, "invalid user access" },
+ { DTRACEFLT_TUPOFLOW, "tuple stack overflow" },
+ { DTRACEFLT_BADSTACK, "bad stack" },
+ { DTRACEFLT_LIBRARY, "library-level fault" },
+ { 0, NULL }
+ };
+
+ for (i = 0; faults[i].str != NULL; i++) {
+ if (faults[i].code == fault)
+ return (faults[i].str);
+ }
+
+ return ("unknown fault");
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h
new file mode 100644
index 000000000000..d95de2dfa992
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+ /*
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#ifndef _DT_ERRTAGS_H
+#define _DT_ERRTAGS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This enum definition is used to define a set of error tags associated with
+ * the D compiler's various error conditions. The shell script mkerrtags.sh is
+ * used to parse this file and create a corresponding dt_errtags.c source file.
+ * If you do something other than add a new error tag here, you may need to
+ * update the mkerrtags shell script as it is based upon simple regexps.
+ */
+typedef enum {
+ D_UNKNOWN, /* unknown D compiler error */
+ D_SYNTAX, /* syntax error in input stream */
+ D_EMPTY, /* empty translation unit */
+ D_TYPE_ERR, /* type definition missing */
+ D_TYPE_MEMBER, /* type member not found */
+ D_ASRELO, /* relocation remains against symbol */
+ D_CG_EXPR, /* tracing function called from expr */
+ D_CG_DYN, /* expression returns dynamic result */
+ D_ATTR_MIN, /* attributes less than amin setting */
+ D_ID_OFLOW, /* identifier space overflow */
+ D_PDESC_ZERO, /* probedesc matches zero probes */
+ D_PDESC_INVAL, /* probedesc is not valid */
+ D_PRED_SCALAR, /* predicate must be of scalar type */
+ D_FUNC_IDENT, /* function designator is not ident */
+ D_FUNC_UNDEF, /* function ident is not defined */
+ D_FUNC_IDKIND, /* function ident is of wrong idkind */
+ D_OFFSETOF_TYPE, /* offsetof arg is not sou type */
+ D_OFFSETOF_BITFIELD, /* offsetof applied to field member */
+ D_SIZEOF_TYPE, /* invalid sizeof type */
+ D_SIZEOF_BITFIELD, /* sizeof applied to field member */
+ D_STRINGOF_TYPE, /* invalid stringof type */
+ D_OP_IDENT, /* operand must be an identifier */
+ D_OP_INT, /* operand must be integral type */
+ D_OP_SCALAR, /* operand must be scalar type */
+ D_OP_ARITH, /* operand must be arithmetic type */
+ D_OP_WRITE, /* operand must be writable variable */
+ D_OP_LVAL, /* operand must be lvalue */
+ D_OP_INCOMPAT, /* operand types are not compatible */
+ D_OP_VFPTR, /* operand cannot be void or func ptr */
+ D_OP_ARRFUN, /* operand cannot be array or func */
+ D_OP_PTR, /* operand must be a pointer */
+ D_OP_SOU, /* operand must be struct or union */
+ D_OP_INCOMPLETE, /* operand is an incomplete type */
+ D_OP_DYN, /* operand cannot be of dynamic type */
+ D_OP_ACT, /* operand cannot be action */
+ D_AGG_REDEF, /* aggregation cannot be redefined */
+ D_AGG_FUNC, /* aggregating function required */
+ D_AGG_MDIM, /* aggregation used as multi-dim arr */
+ D_ARR_BADREF, /* access non-array using tuple */
+ D_ARR_LOCAL, /* cannot define local assc array */
+ D_DIV_ZERO, /* division by zero detected */
+ D_DEREF_NONPTR, /* dereference non-pointer type */
+ D_DEREF_VOID, /* dereference void pointer */
+ D_DEREF_FUNC, /* dereference function pointer */
+ D_ADDROF_LVAL, /* unary & applied to non-lvalue */
+ D_ADDROF_VAR, /* unary & applied to variable */
+ D_ADDROF_BITFIELD, /* unary & applied to field member */
+ D_XLATE_REDECL, /* translator redeclared */
+ D_XLATE_NOCONV, /* no conversion for member defined */
+ D_XLATE_NONE, /* no translator for type combo */
+ D_XLATE_SOU, /* dst must be struct or union type */
+ D_XLATE_INCOMPAT, /* translator member type incompat */
+ D_XLATE_MEMB, /* translator member is not valid */
+ D_CAST_INVAL, /* invalid cast expression */
+ D_PRAGERR, /* #pragma error message */
+ D_PRAGCTL_INVAL, /* invalid control directive */
+ D_PRAGMA_INVAL, /* invalid compiler pragma */
+ D_PRAGMA_UNUSED, /* unused compiler pragma */
+ D_PRAGMA_MALFORM, /* malformed #pragma argument list */
+ D_PRAGMA_OPTSET, /* failed to set #pragma option */
+ D_PRAGMA_SCOPE, /* #pragma identifier scope error */
+ D_PRAGMA_DEPEND, /* #pragma dependency not satisfied */
+ D_MACRO_UNDEF, /* macro parameter is not defined */
+ D_MACRO_OFLOW, /* macro parameter integer overflow */
+ D_MACRO_UNUSED, /* macro parameter is never used */
+ D_INT_OFLOW, /* integer constant overflow */
+ D_INT_DIGIT, /* integer digit is not valid */
+ D_STR_NL, /* newline in string literal */
+ D_CHR_NL, /* newline in character constant */
+ D_CHR_NULL, /* empty character constant */
+ D_CHR_OFLOW, /* character constant is too long */
+ D_IDENT_BADREF, /* identifier expected type mismatch */
+ D_IDENT_UNDEF, /* identifier is not known/defined */
+ D_IDENT_AMBIG, /* identifier is ambiguous (var/enum) */
+ D_SYM_BADREF, /* kernel/user symbol ref mismatch */
+ D_SYM_NOTYPES, /* no CTF data available for sym ref */
+ D_SYM_MODEL, /* module/program data model mismatch */
+ D_VAR_UNDEF, /* reference to undefined variable */
+ D_VAR_UNSUP, /* unsupported variable specification */
+ D_PROTO_LEN, /* prototype length mismatch */
+ D_PROTO_ARG, /* prototype argument mismatch */
+ D_ARGS_MULTI, /* description matches unstable set */
+ D_ARGS_XLATOR, /* no args[] translator defined */
+ D_ARGS_NONE, /* no args[] available */
+ D_ARGS_TYPE, /* invalid args[] type */
+ D_ARGS_IDX, /* invalid args[] index */
+ D_REGS_IDX, /* invalid regs[] index */
+ D_KEY_TYPE, /* invalid agg or array key type */
+ D_PRINTF_DYN_PROTO, /* dynamic size argument missing */
+ D_PRINTF_DYN_TYPE, /* dynamic size type mismatch */
+ D_PRINTF_AGG_CONV, /* improper use of %@ conversion */
+ D_PRINTF_ARG_PROTO, /* conversion missing value argument */
+ D_PRINTF_ARG_TYPE, /* conversion arg has wrong type */
+ D_PRINTF_ARG_EXTRA, /* extra arguments specified */
+ D_PRINTF_ARG_FMT, /* format string is not a constant */
+ D_PRINTF_FMT_EMPTY, /* format string is empty */
+ D_DECL_CHARATTR, /* bad attributes for char decl */
+ D_DECL_VOIDATTR, /* bad attributes for void decl */
+ D_DECL_SIGNINT, /* sign/unsign with non-integer decl */
+ D_DECL_LONGINT, /* long with non-arithmetic decl */
+ D_DECL_IDENT, /* old-style declaration or bad type */
+ D_DECL_CLASS, /* more than one storage class given */
+ D_DECL_BADCLASS, /* decl class not supported in D */
+ D_DECL_PARMCLASS, /* invalid class for parameter type */
+ D_DECL_COMBO, /* bad decl specifier combination */
+ D_DECL_ARRSUB, /* const int required for array size */
+ D_DECL_ARRNULL, /* array decl requires dim or tuple */
+ D_DECL_ARRBIG, /* array size too big */
+ D_DECL_IDRED, /* decl identifier redeclared */
+ D_DECL_TYPERED, /* decl type redeclared */
+ D_DECL_MNAME, /* member name missing */
+ D_DECL_SCOPE, /* scoping operator used in decl */
+ D_DECL_BFCONST, /* bit-field requires const size expr */
+ D_DECL_BFSIZE, /* bit-field size too big for type */
+ D_DECL_BFTYPE, /* bit-field type is not valid */
+ D_DECL_ENCONST, /* enum tag requires const size expr */
+ D_DECL_ENOFLOW, /* enumerator value overflows INT_MAX */
+ D_DECL_USELESS, /* useless external declaration */
+ D_DECL_LOCASSC, /* attempt to decl local assc array */
+ D_DECL_VOIDOBJ, /* attempt to decl void object */
+ D_DECL_DYNOBJ, /* attempt to decl dynamic object */
+ D_DECL_INCOMPLETE, /* declaration uses incomplete type */
+ D_DECL_PROTO_VARARGS, /* varargs not allowed in prototype */
+ D_DECL_PROTO_TYPE, /* type not allowed in prototype */
+ D_DECL_PROTO_VOID, /* void must be sole parameter */
+ D_DECL_PROTO_NAME, /* void parameter may not have a name */
+ D_DECL_PROTO_FORM, /* parameter name has no formal */
+ D_COMM_COMM, /* commit() after commit() */
+ D_COMM_DREC, /* commit() after data action */
+ D_SPEC_SPEC, /* speculate() after speculate() */
+ D_SPEC_COMM, /* speculate() after commit() */
+ D_SPEC_DREC, /* speculate() after data action */
+ D_AGG_COMM, /* aggregating act after commit() */
+ D_AGG_SPEC, /* aggregating act after speculate() */
+ D_AGG_NULL, /* aggregation stmt has null effect */
+ D_AGG_SCALAR, /* aggregating function needs scalar */
+ D_ACT_SPEC, /* destructive action after speculate */
+ D_EXIT_SPEC, /* exit() action after speculate */
+ D_DREC_COMM, /* data action after commit() */
+ D_PRINTA_PROTO, /* printa() prototype mismatch */
+ D_PRINTA_AGGARG, /* aggregation arg type mismatch */
+ D_PRINTA_AGGBAD, /* printa() aggregation not defined */
+ D_PRINTA_AGGKEY, /* printa() aggregation key mismatch */
+ D_PRINTA_AGGPROTO, /* printa() aggregation mismatch */
+ D_TRACE_VOID, /* trace() argument has void type */
+ D_TRACE_DYN, /* trace() argument has dynamic type */
+ D_TRACE_AGG, /* trace() argument is an aggregation */
+ D_PRINT_VOID, /* print() argument has void type */
+ D_PRINT_DYN, /* print() argument has dynamic type */
+ D_PRINT_AGG, /* print() argument is an aggregation */
+ D_TRACEMEM_ADDR, /* tracemem() address bad type */
+ D_TRACEMEM_SIZE, /* tracemem() size bad type */
+ D_TRACEMEM_ARGS, /* tracemem() illegal number of args */
+ D_TRACEMEM_DYNSIZE, /* tracemem() dynamic size bad type */
+ D_STACK_PROTO, /* stack() prototype mismatch */
+ D_STACK_SIZE, /* stack() size argument bad type */
+ D_USTACK_FRAMES, /* ustack() frames arg bad type */
+ D_USTACK_STRSIZE, /* ustack() strsize arg bad type */
+ D_USTACK_PROTO, /* ustack() prototype mismatch */
+ D_LQUANT_BASETYPE, /* lquantize() bad base type */
+ D_LQUANT_BASEVAL, /* lquantize() bad base value */
+ D_LQUANT_LIMTYPE, /* lquantize() bad limit type */
+ D_LQUANT_LIMVAL, /* lquantize() bad limit value */
+ D_LQUANT_MISMATCH, /* lquantize() limit < base */
+ D_LQUANT_STEPTYPE, /* lquantize() bad step type */
+ D_LQUANT_STEPVAL, /* lquantize() bad step value */
+ D_LQUANT_STEPLARGE, /* lquantize() step too large */
+ D_LQUANT_STEPSMALL, /* lquantize() step too small */
+ D_QUANT_PROTO, /* quantize() prototype mismatch */
+ D_PROC_OFF, /* byte offset exceeds function size */
+ D_PROC_ALIGN, /* byte offset has invalid alignment */
+ D_PROC_NAME, /* invalid process probe name */
+ D_PROC_GRAB, /* failed to grab process */
+ D_PROC_DYN, /* process is not dynamically linked */
+ D_PROC_LIB, /* invalid process library name */
+ D_PROC_FUNC, /* no such function in process */
+ D_PROC_CREATEFAIL, /* pid probe creation failed */
+ D_PROC_NODEV, /* fasttrap device is not installed */
+ D_PROC_BADPID, /* user probe pid invalid */
+ D_PROC_BADPROV, /* user probe provider invalid */
+ D_PROC_USDT, /* problem initializing usdt */
+ D_CLEAR_PROTO, /* clear() prototype mismatch */
+ D_CLEAR_AGGARG, /* aggregation arg type mismatch */
+ D_CLEAR_AGGBAD, /* clear() aggregation not defined */
+ D_NORMALIZE_PROTO, /* normalize() prototype mismatch */
+ D_NORMALIZE_SCALAR, /* normalize() value must be scalar */
+ D_NORMALIZE_AGGARG, /* aggregation arg type mismatch */
+ D_NORMALIZE_AGGBAD, /* normalize() aggregation not def. */
+ D_TRUNC_PROTO, /* trunc() prototype mismatch */
+ D_TRUNC_SCALAR, /* trunc() value must be scalar */
+ D_TRUNC_AGGARG, /* aggregation arg type mismatch */
+ D_TRUNC_AGGBAD, /* trunc() aggregation not def. */
+ D_PROV_BADNAME, /* invalid provider name */
+ D_PROV_INCOMPAT, /* provider/probe interface mismatch */
+ D_PROV_PRDUP, /* duplicate probe declaration */
+ D_PROV_PRARGLEN, /* probe argument list too long */
+ D_PROV_PRXLATOR, /* probe argument translator missing */
+ D_FREOPEN_INVALID, /* frename() filename is invalid */
+ D_LQUANT_MATCHBASE, /* lquantize() mismatch on base */
+ D_LQUANT_MATCHLIM, /* lquantize() mismatch on limit */
+ D_LQUANT_MATCHSTEP, /* lquantize() mismatch on step */
+ D_LLQUANT_FACTORTYPE, /* llquantize() bad magnitude type */
+ D_LLQUANT_FACTORVAL, /* llquantize() bad magnitude value */
+ D_LLQUANT_FACTORMATCH, /* llquantize() mismatch on magnitude */
+ D_LLQUANT_LOWTYPE, /* llquantize() bad low mag type */
+ D_LLQUANT_LOWVAL, /* llquantize() bad low mag value */
+ D_LLQUANT_LOWMATCH, /* llquantize() mismatch on low mag */
+ D_LLQUANT_HIGHTYPE, /* llquantize() bad high mag type */
+ D_LLQUANT_HIGHVAL, /* llquantize() bad high mag value */
+ D_LLQUANT_HIGHMATCH, /* llquantize() mismatch on high mag */
+ D_LLQUANT_NSTEPTYPE, /* llquantize() bad # steps type */
+ D_LLQUANT_NSTEPVAL, /* llquantize() bad # steps value */
+ D_LLQUANT_NSTEPMATCH, /* llquantize() mismatch on # steps */
+ D_LLQUANT_MAGRANGE, /* llquantize() bad magnitude range */
+ D_LLQUANT_FACTORNSTEPS, /* llquantize() # steps < factor */
+ D_LLQUANT_FACTOREVEN, /* llquantize() bad # steps/factor */
+ D_LLQUANT_FACTORSMALL, /* llquantize() magnitude too small */
+ D_LLQUANT_MAGTOOBIG, /* llquantize() high mag too large */
+ D_NOREG, /* no available internal registers */
+ D_PRINTM_ADDR, /* printm() memref bad type */
+ D_PRINTM_SIZE, /* printm() size bad type */
+} dt_errtag_t;
+
+extern const char *dt_errtag(dt_errtag_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_ERRTAGS_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y
new file mode 100644
index 000000000000..0cb6fa6b5253
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y
@@ -0,0 +1,885 @@
+%{
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <dt_impl.h>
+
+#define OP1(op, c) dt_node_op1(op, c)
+#define OP2(op, l, r) dt_node_op2(op, l, r)
+#define OP3(x, y, z) dt_node_op3(x, y, z)
+#define LINK(l, r) dt_node_link(l, r)
+#define DUP(s) strdup(s)
+
+%}
+
+%union {
+ dt_node_t *l_node;
+ dt_decl_t *l_decl;
+ char *l_str;
+ uintmax_t l_int;
+ int l_tok;
+}
+
+%token DT_TOK_COMMA DT_TOK_ELLIPSIS
+%token DT_TOK_ASGN DT_TOK_ADD_EQ DT_TOK_SUB_EQ DT_TOK_MUL_EQ
+%token DT_TOK_DIV_EQ DT_TOK_MOD_EQ DT_TOK_AND_EQ DT_TOK_XOR_EQ DT_TOK_OR_EQ
+%token DT_TOK_LSH_EQ DT_TOK_RSH_EQ DT_TOK_QUESTION DT_TOK_COLON
+%token DT_TOK_LOR DT_TOK_LXOR DT_TOK_LAND
+%token DT_TOK_BOR DT_TOK_XOR DT_TOK_BAND DT_TOK_EQU DT_TOK_NEQ
+%token DT_TOK_LT DT_TOK_LE DT_TOK_GT DT_TOK_GE DT_TOK_LSH DT_TOK_RSH
+%token DT_TOK_ADD DT_TOK_SUB DT_TOK_MUL DT_TOK_DIV DT_TOK_MOD
+%token DT_TOK_LNEG DT_TOK_BNEG DT_TOK_ADDADD DT_TOK_SUBSUB
+%token DT_TOK_PREINC DT_TOK_POSTINC DT_TOK_PREDEC DT_TOK_POSTDEC
+%token DT_TOK_IPOS DT_TOK_INEG DT_TOK_DEREF DT_TOK_ADDROF
+%token DT_TOK_OFFSETOF DT_TOK_SIZEOF DT_TOK_STRINGOF DT_TOK_XLATE
+%token DT_TOK_LPAR DT_TOK_RPAR DT_TOK_LBRAC DT_TOK_RBRAC DT_TOK_PTR DT_TOK_DOT
+
+%token <l_str> DT_TOK_STRING
+%token <l_str> DT_TOK_IDENT
+%token <l_str> DT_TOK_PSPEC
+%token <l_str> DT_TOK_AGG
+%token <l_str> DT_TOK_TNAME
+%token <l_int> DT_TOK_INT
+
+%token DT_KEY_AUTO
+%token DT_KEY_BREAK
+%token DT_KEY_CASE
+%token DT_KEY_CHAR
+%token DT_KEY_CONST
+%token DT_KEY_CONTINUE
+%token DT_KEY_COUNTER
+%token DT_KEY_DEFAULT
+%token DT_KEY_DO
+%token DT_KEY_DOUBLE
+%token DT_KEY_ELSE
+%token DT_KEY_ENUM
+%token DT_KEY_EXTERN
+%token DT_KEY_FLOAT
+%token DT_KEY_FOR
+%token DT_KEY_GOTO
+%token DT_KEY_IF
+%token DT_KEY_IMPORT
+%token DT_KEY_INLINE
+%token DT_KEY_INT
+%token DT_KEY_LONG
+%token DT_KEY_PROBE
+%token DT_KEY_PROVIDER
+%token DT_KEY_REGISTER
+%token DT_KEY_RESTRICT
+%token DT_KEY_RETURN
+%token DT_KEY_SELF
+%token DT_KEY_SHORT
+%token DT_KEY_SIGNED
+%token DT_KEY_STATIC
+%token DT_KEY_STRING
+%token DT_KEY_STRUCT
+%token DT_KEY_SWITCH
+%token DT_KEY_THIS
+%token DT_KEY_TYPEDEF
+%token DT_KEY_UNION
+%token DT_KEY_UNSIGNED
+%token DT_KEY_USERLAND
+%token DT_KEY_VOID
+%token DT_KEY_VOLATILE
+%token DT_KEY_WHILE
+%token DT_KEY_XLATOR
+
+%token DT_TOK_EPRED
+%token DT_CTX_DEXPR
+%token DT_CTX_DPROG
+%token DT_CTX_DTYPE
+%token DT_TOK_EOF 0
+
+%left DT_TOK_COMMA
+%right DT_TOK_ASGN DT_TOK_ADD_EQ DT_TOK_SUB_EQ DT_TOK_MUL_EQ DT_TOK_DIV_EQ
+ DT_TOK_MOD_EQ DT_TOK_AND_EQ DT_TOK_XOR_EQ DT_TOK_OR_EQ DT_TOK_LSH_EQ
+ DT_TOK_RSH_EQ
+%left DT_TOK_QUESTION DT_TOK_COLON
+%left DT_TOK_LOR
+%left DT_TOK_LXOR
+%left DT_TOK_LAND
+%left DT_TOK_BOR
+%left DT_TOK_XOR
+%left DT_TOK_BAND
+%left DT_TOK_EQU DT_TOK_NEQ
+%left DT_TOK_LT DT_TOK_LE DT_TOK_GT DT_TOK_GE
+%left DT_TOK_LSH DT_TOK_RSH
+%left DT_TOK_ADD DT_TOK_SUB
+%left DT_TOK_MUL DT_TOK_DIV DT_TOK_MOD
+%right DT_TOK_LNEG DT_TOK_BNEG DT_TOK_ADDADD DT_TOK_SUBSUB
+ DT_TOK_IPOS DT_TOK_INEG
+%right DT_TOK_DEREF DT_TOK_ADDROF DT_TOK_SIZEOF DT_TOK_STRINGOF DT_TOK_XLATE
+%left DT_TOK_LPAR DT_TOK_RPAR DT_TOK_LBRAC DT_TOK_RBRAC DT_TOK_PTR DT_TOK_DOT
+
+%type <l_node> d_expression
+%type <l_node> d_program
+%type <l_node> d_type
+
+%type <l_node> translation_unit
+%type <l_node> external_declaration
+%type <l_node> inline_definition
+%type <l_node> translator_definition
+%type <l_node> translator_member_list
+%type <l_node> translator_member
+%type <l_node> provider_definition
+%type <l_node> provider_probe_list
+%type <l_node> provider_probe
+%type <l_node> probe_definition
+%type <l_node> probe_specifiers
+%type <l_node> probe_specifier_list
+%type <l_node> probe_specifier
+%type <l_node> statement_list
+%type <l_node> statement_list_impl
+%type <l_node> statement_or_block
+%type <l_node> statement
+%type <l_node> declaration
+%type <l_node> init_declarator_list
+%type <l_node> init_declarator
+
+%type <l_decl> type_specifier
+%type <l_decl> type_qualifier
+%type <l_decl> struct_or_union_specifier
+%type <l_decl> specifier_qualifier_list
+%type <l_decl> enum_specifier
+%type <l_decl> declarator
+%type <l_decl> direct_declarator
+%type <l_decl> pointer
+%type <l_decl> type_qualifier_list
+%type <l_decl> type_name
+%type <l_decl> abstract_declarator
+%type <l_decl> direct_abstract_declarator
+
+%type <l_node> parameter_type_list
+%type <l_node> parameter_list
+%type <l_node> parameter_declaration
+
+%type <l_node> array
+%type <l_node> array_parameters
+%type <l_node> function
+%type <l_node> function_parameters
+
+%type <l_node> expression
+%type <l_node> assignment_expression
+%type <l_node> conditional_expression
+%type <l_node> constant_expression
+%type <l_node> logical_or_expression
+%type <l_node> logical_xor_expression
+%type <l_node> logical_and_expression
+%type <l_node> inclusive_or_expression
+%type <l_node> exclusive_or_expression
+%type <l_node> and_expression
+%type <l_node> equality_expression
+%type <l_node> relational_expression
+%type <l_node> shift_expression
+%type <l_node> additive_expression
+%type <l_node> multiplicative_expression
+%type <l_node> cast_expression
+%type <l_node> unary_expression
+%type <l_node> postfix_expression
+%type <l_node> primary_expression
+%type <l_node> argument_expression_list
+
+%type <l_tok> assignment_operator
+%type <l_tok> unary_operator
+%type <l_tok> struct_or_union
+
+%type <l_str> dtrace_keyword_ident
+
+%%
+
+dtrace_program: d_expression DT_TOK_EOF { return (dt_node_root($1)); }
+ | d_program DT_TOK_EOF { return (dt_node_root($1)); }
+ | d_type DT_TOK_EOF { return (dt_node_root($1)); }
+ ;
+
+d_expression: DT_CTX_DEXPR { $$ = NULL; }
+ | DT_CTX_DEXPR expression { $$ = $2; }
+ ;
+
+d_program: DT_CTX_DPROG { $$ = dt_node_program(NULL); }
+ | DT_CTX_DPROG translation_unit { $$ = dt_node_program($2); }
+ ;
+
+d_type: DT_CTX_DTYPE { $$ = NULL; }
+ | DT_CTX_DTYPE type_name { $$ = (dt_node_t *)$2; }
+ ;
+
+translation_unit:
+ external_declaration
+ | translation_unit external_declaration { $$ = LINK($1, $2); }
+ ;
+
+external_declaration:
+ inline_definition
+ | translator_definition
+ | provider_definition
+ | probe_definition
+ | declaration
+ ;
+
+inline_definition:
+ DT_KEY_INLINE declaration_specifiers declarator
+ { dt_scope_push(NULL, CTF_ERR); } DT_TOK_ASGN
+ assignment_expression ';' {
+ /*
+ * We push a new declaration scope before shifting the
+ * assignment_expression in order to preserve ds_class
+ * and ds_ident for use in dt_node_inline(). Once the
+ * entire inline_definition rule is matched, pop the
+ * scope and construct the inline using the saved decl.
+ */
+ dt_scope_pop();
+ $$ = dt_node_inline($6);
+ }
+ ;
+
+translator_definition:
+ DT_KEY_XLATOR type_name DT_TOK_LT type_name
+ DT_TOK_IDENT DT_TOK_GT '{' translator_member_list '}' ';' {
+ $$ = dt_node_xlator($2, $4, $5, $8);
+ }
+ | DT_KEY_XLATOR type_name DT_TOK_LT type_name
+ DT_TOK_IDENT DT_TOK_GT '{' '}' ';' {
+ $$ = dt_node_xlator($2, $4, $5, NULL);
+ }
+ ;
+
+translator_member_list:
+ translator_member
+ | translator_member_list translator_member { $$ = LINK($1,$2); }
+ ;
+
+translator_member:
+ DT_TOK_IDENT DT_TOK_ASGN assignment_expression ';' {
+ $$ = dt_node_member(NULL, $1, $3);
+ }
+ ;
+
+provider_definition:
+ DT_KEY_PROVIDER DT_TOK_IDENT '{' provider_probe_list '}' ';' {
+ $$ = dt_node_provider($2, $4);
+ }
+ | DT_KEY_PROVIDER DT_TOK_IDENT '{' '}' ';' {
+ $$ = dt_node_provider($2, NULL);
+ }
+ ;
+
+provider_probe_list:
+ provider_probe
+ | provider_probe_list provider_probe { $$ = LINK($1, $2); }
+ ;
+
+provider_probe:
+ DT_KEY_PROBE DT_TOK_IDENT function DT_TOK_COLON function ';' {
+ $$ = dt_node_probe($2, 2, $3, $5);
+ }
+ | DT_KEY_PROBE DT_TOK_IDENT function ';' {
+ $$ = dt_node_probe($2, 1, $3, NULL);
+ }
+ ;
+
+
+probe_definition:
+ probe_specifiers {
+ /*
+ * If the input stream is a file, do not permit a probe
+ * specification without / <pred> / or { <act> } after
+ * it. This can only occur if the next token is EOF or
+ * an ambiguous predicate was slurped up as a comment.
+ * We cannot perform this check if input() is a string
+ * because dtrace(1M) [-fmnP] also use the compiler and
+ * things like dtrace -n BEGIN have to be accepted.
+ */
+ if (yypcb->pcb_fileptr != NULL) {
+ dnerror($1, D_SYNTAX, "expected predicate and/"
+ "or actions following probe description\n");
+ }
+ $$ = dt_node_clause($1, NULL, NULL);
+ yybegin(YYS_CLAUSE);
+ }
+ | probe_specifiers '{' statement_list '}' {
+ $$ = dt_node_clause($1, NULL, $3);
+ yybegin(YYS_CLAUSE);
+ }
+ | probe_specifiers DT_TOK_DIV expression DT_TOK_EPRED {
+ dnerror($3, D_SYNTAX, "expected actions { } following "
+ "probe description and predicate\n");
+ }
+ | probe_specifiers DT_TOK_DIV expression DT_TOK_EPRED
+ '{' statement_list '}' {
+ $$ = dt_node_clause($1, $3, $6);
+ yybegin(YYS_CLAUSE);
+ }
+ ;
+
+probe_specifiers:
+ probe_specifier_list { yybegin(YYS_EXPR); $$ = $1; }
+ ;
+
+probe_specifier_list:
+ probe_specifier
+ | probe_specifier_list DT_TOK_COMMA probe_specifier {
+ $$ = LINK($1, $3);
+ }
+ ;
+
+probe_specifier:
+ DT_TOK_PSPEC { $$ = dt_node_pdesc_by_name($1); }
+ | DT_TOK_INT { $$ = dt_node_pdesc_by_id($1); }
+ ;
+
+statement_list_impl: /* empty */ { $$ = NULL; }
+ | statement_list_impl statement { $$ = LINK($1, $2); }
+ ;
+
+statement_list:
+ statement_list_impl { $$ = $1; }
+ | statement_list_impl expression {
+ $$ = LINK($1, dt_node_statement($2));
+ }
+ ;
+
+statement_or_block:
+ statement
+ | '{' statement_list '}' { $$ = $2; }
+
+statement: ';' { $$ = NULL; }
+ | expression ';' { $$ = dt_node_statement($1); }
+ | DT_KEY_IF DT_TOK_LPAR expression DT_TOK_RPAR statement_or_block {
+ $$ = dt_node_if($3, $5, NULL);
+ }
+ | DT_KEY_IF DT_TOK_LPAR expression DT_TOK_RPAR
+ statement_or_block DT_KEY_ELSE statement_or_block {
+ $$ = dt_node_if($3, $5, $7);
+ }
+ ;
+
+argument_expression_list:
+ assignment_expression
+ | argument_expression_list DT_TOK_COMMA assignment_expression {
+ $$ = LINK($1, $3);
+ }
+ ;
+
+primary_expression:
+ DT_TOK_IDENT { $$ = dt_node_ident($1); }
+ | DT_TOK_AGG { $$ = dt_node_ident($1); }
+ | DT_TOK_INT { $$ = dt_node_int($1); }
+ | DT_TOK_STRING { $$ = dt_node_string($1); }
+ | DT_KEY_SELF { $$ = dt_node_ident(DUP("self")); }
+ | DT_KEY_THIS { $$ = dt_node_ident(DUP("this")); }
+ | DT_TOK_LPAR expression DT_TOK_RPAR { $$ = $2; }
+ ;
+
+postfix_expression:
+ primary_expression
+ | postfix_expression
+ DT_TOK_LBRAC argument_expression_list DT_TOK_RBRAC {
+ $$ = OP2(DT_TOK_LBRAC, $1, $3);
+ }
+ | postfix_expression DT_TOK_LPAR DT_TOK_RPAR {
+ $$ = dt_node_func($1, NULL);
+ }
+ | postfix_expression
+ DT_TOK_LPAR argument_expression_list DT_TOK_RPAR {
+ $$ = dt_node_func($1, $3);
+ }
+ | postfix_expression DT_TOK_DOT DT_TOK_IDENT {
+ $$ = OP2(DT_TOK_DOT, $1, dt_node_ident($3));
+ }
+ | postfix_expression DT_TOK_DOT DT_TOK_TNAME {
+ $$ = OP2(DT_TOK_DOT, $1, dt_node_ident($3));
+ }
+ | postfix_expression DT_TOK_DOT dtrace_keyword_ident {
+ $$ = OP2(DT_TOK_DOT, $1, dt_node_ident($3));
+ }
+ | postfix_expression DT_TOK_PTR DT_TOK_IDENT {
+ $$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
+ }
+ | postfix_expression DT_TOK_PTR DT_TOK_TNAME {
+ $$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
+ }
+ | postfix_expression DT_TOK_PTR dtrace_keyword_ident {
+ $$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
+ }
+ | postfix_expression DT_TOK_ADDADD {
+ $$ = OP1(DT_TOK_POSTINC, $1);
+ }
+ | postfix_expression DT_TOK_SUBSUB {
+ $$ = OP1(DT_TOK_POSTDEC, $1);
+ }
+ | DT_TOK_OFFSETOF DT_TOK_LPAR type_name DT_TOK_COMMA
+ DT_TOK_IDENT DT_TOK_RPAR {
+ $$ = dt_node_offsetof($3, $5);
+ }
+ | DT_TOK_OFFSETOF DT_TOK_LPAR type_name DT_TOK_COMMA
+ DT_TOK_TNAME DT_TOK_RPAR {
+ $$ = dt_node_offsetof($3, $5);
+ }
+ | DT_TOK_OFFSETOF DT_TOK_LPAR type_name DT_TOK_COMMA
+ dtrace_keyword_ident DT_TOK_RPAR {
+ $$ = dt_node_offsetof($3, $5);
+ }
+ | DT_TOK_XLATE DT_TOK_LT type_name DT_TOK_GT
+ DT_TOK_LPAR expression DT_TOK_RPAR {
+ $$ = OP2(DT_TOK_XLATE, dt_node_type($3), $6);
+ }
+ ;
+
+unary_expression:
+ postfix_expression
+ | DT_TOK_ADDADD unary_expression { $$ = OP1(DT_TOK_PREINC, $2); }
+ | DT_TOK_SUBSUB unary_expression { $$ = OP1(DT_TOK_PREDEC, $2); }
+ | unary_operator cast_expression { $$ = OP1($1, $2); }
+ | DT_TOK_SIZEOF unary_expression { $$ = OP1(DT_TOK_SIZEOF, $2); }
+ | DT_TOK_SIZEOF DT_TOK_LPAR type_name DT_TOK_RPAR {
+ $$ = OP1(DT_TOK_SIZEOF, dt_node_type($3));
+ }
+ | DT_TOK_STRINGOF unary_expression {
+ $$ = OP1(DT_TOK_STRINGOF, $2);
+ }
+ ;
+
+unary_operator: DT_TOK_BAND { $$ = DT_TOK_ADDROF; }
+ | DT_TOK_MUL { $$ = DT_TOK_DEREF; }
+ | DT_TOK_ADD { $$ = DT_TOK_IPOS; }
+ | DT_TOK_SUB { $$ = DT_TOK_INEG; }
+ | DT_TOK_BNEG { $$ = DT_TOK_BNEG; }
+ | DT_TOK_LNEG { $$ = DT_TOK_LNEG; }
+ ;
+
+cast_expression:
+ unary_expression
+ | DT_TOK_LPAR type_name DT_TOK_RPAR cast_expression {
+ $$ = OP2(DT_TOK_LPAR, dt_node_type($2), $4);
+ }
+ ;
+
+multiplicative_expression:
+ cast_expression
+ | multiplicative_expression DT_TOK_MUL cast_expression {
+ $$ = OP2(DT_TOK_MUL, $1, $3);
+ }
+ | multiplicative_expression DT_TOK_DIV cast_expression {
+ $$ = OP2(DT_TOK_DIV, $1, $3);
+ }
+ | multiplicative_expression DT_TOK_MOD cast_expression {
+ $$ = OP2(DT_TOK_MOD, $1, $3);
+ }
+ ;
+
+additive_expression:
+ multiplicative_expression
+ | additive_expression DT_TOK_ADD multiplicative_expression {
+ $$ = OP2(DT_TOK_ADD, $1, $3);
+ }
+ | additive_expression DT_TOK_SUB multiplicative_expression {
+ $$ = OP2(DT_TOK_SUB, $1, $3);
+ }
+ ;
+
+shift_expression:
+ additive_expression
+ | shift_expression DT_TOK_LSH additive_expression {
+ $$ = OP2(DT_TOK_LSH, $1, $3);
+ }
+ | shift_expression DT_TOK_RSH additive_expression {
+ $$ = OP2(DT_TOK_RSH, $1, $3);
+ }
+ ;
+
+relational_expression:
+ shift_expression
+ | relational_expression DT_TOK_LT shift_expression {
+ $$ = OP2(DT_TOK_LT, $1, $3);
+ }
+ | relational_expression DT_TOK_GT shift_expression {
+ $$ = OP2(DT_TOK_GT, $1, $3);
+ }
+ | relational_expression DT_TOK_LE shift_expression {
+ $$ = OP2(DT_TOK_LE, $1, $3);
+ }
+ | relational_expression DT_TOK_GE shift_expression {
+ $$ = OP2(DT_TOK_GE, $1, $3);
+ }
+ ;
+
+equality_expression:
+ relational_expression
+ | equality_expression DT_TOK_EQU relational_expression {
+ $$ = OP2(DT_TOK_EQU, $1, $3);
+ }
+ | equality_expression DT_TOK_NEQ relational_expression {
+ $$ = OP2(DT_TOK_NEQ, $1, $3);
+ }
+ ;
+
+and_expression:
+ equality_expression
+ | and_expression DT_TOK_BAND equality_expression {
+ $$ = OP2(DT_TOK_BAND, $1, $3);
+ }
+ ;
+
+exclusive_or_expression:
+ and_expression
+ | exclusive_or_expression DT_TOK_XOR and_expression {
+ $$ = OP2(DT_TOK_XOR, $1, $3);
+ }
+ ;
+
+inclusive_or_expression:
+ exclusive_or_expression
+ | inclusive_or_expression DT_TOK_BOR exclusive_or_expression {
+ $$ = OP2(DT_TOK_BOR, $1, $3);
+ }
+ ;
+
+logical_and_expression:
+ inclusive_or_expression
+ | logical_and_expression DT_TOK_LAND inclusive_or_expression {
+ $$ = OP2(DT_TOK_LAND, $1, $3);
+ }
+ ;
+
+logical_xor_expression:
+ logical_and_expression
+ | logical_xor_expression DT_TOK_LXOR logical_and_expression {
+ $$ = OP2(DT_TOK_LXOR, $1, $3);
+ }
+ ;
+
+logical_or_expression:
+ logical_xor_expression
+ | logical_or_expression DT_TOK_LOR logical_xor_expression {
+ $$ = OP2(DT_TOK_LOR, $1, $3);
+ }
+ ;
+
+constant_expression: conditional_expression
+ ;
+
+conditional_expression:
+ logical_or_expression
+ | logical_or_expression DT_TOK_QUESTION expression DT_TOK_COLON
+ conditional_expression { $$ = OP3($1, $3, $5); }
+ ;
+
+assignment_expression:
+ conditional_expression
+ | unary_expression assignment_operator assignment_expression {
+ $$ = OP2($2, $1, $3);
+ }
+ ;
+
+assignment_operator:
+ DT_TOK_ASGN { $$ = DT_TOK_ASGN; }
+ | DT_TOK_MUL_EQ { $$ = DT_TOK_MUL_EQ; }
+ | DT_TOK_DIV_EQ { $$ = DT_TOK_DIV_EQ; }
+ | DT_TOK_MOD_EQ { $$ = DT_TOK_MOD_EQ; }
+ | DT_TOK_ADD_EQ { $$ = DT_TOK_ADD_EQ; }
+ | DT_TOK_SUB_EQ { $$ = DT_TOK_SUB_EQ; }
+ | DT_TOK_LSH_EQ { $$ = DT_TOK_LSH_EQ; }
+ | DT_TOK_RSH_EQ { $$ = DT_TOK_RSH_EQ; }
+ | DT_TOK_AND_EQ { $$ = DT_TOK_AND_EQ; }
+ | DT_TOK_XOR_EQ { $$ = DT_TOK_XOR_EQ; }
+ | DT_TOK_OR_EQ { $$ = DT_TOK_OR_EQ; }
+ ;
+
+expression: assignment_expression
+ | expression DT_TOK_COMMA assignment_expression {
+ $$ = OP2(DT_TOK_COMMA, $1, $3);
+ }
+ ;
+
+declaration: declaration_specifiers ';' {
+ $$ = dt_node_decl();
+ dt_decl_free(dt_decl_pop());
+ yybegin(YYS_CLAUSE);
+ }
+ | declaration_specifiers init_declarator_list ';' {
+ $$ = $2;
+ dt_decl_free(dt_decl_pop());
+ yybegin(YYS_CLAUSE);
+ }
+ ;
+
+declaration_specifiers:
+ d_storage_class_specifier
+ | d_storage_class_specifier declaration_specifiers
+ | type_specifier
+ | type_specifier declaration_specifiers
+ | type_qualifier
+ | type_qualifier declaration_specifiers
+ ;
+
+parameter_declaration_specifiers:
+ storage_class_specifier
+ | storage_class_specifier declaration_specifiers
+ | type_specifier
+ | type_specifier declaration_specifiers
+ | type_qualifier
+ | type_qualifier declaration_specifiers
+ ;
+
+storage_class_specifier:
+ DT_KEY_AUTO { dt_decl_class(DT_DC_AUTO); }
+ | DT_KEY_REGISTER { dt_decl_class(DT_DC_REGISTER); }
+ | DT_KEY_STATIC { dt_decl_class(DT_DC_STATIC); }
+ | DT_KEY_EXTERN { dt_decl_class(DT_DC_EXTERN); }
+ | DT_KEY_TYPEDEF { dt_decl_class(DT_DC_TYPEDEF); }
+ ;
+
+d_storage_class_specifier:
+ storage_class_specifier
+ | DT_KEY_SELF { dt_decl_class(DT_DC_SELF); }
+ | DT_KEY_THIS { dt_decl_class(DT_DC_THIS); }
+ ;
+
+type_specifier: DT_KEY_VOID { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("void")); }
+ | DT_KEY_CHAR { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("char")); }
+ | DT_KEY_SHORT { $$ = dt_decl_attr(DT_DA_SHORT); }
+ | DT_KEY_INT { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("int")); }
+ | DT_KEY_LONG { $$ = dt_decl_attr(DT_DA_LONG); }
+ | DT_KEY_FLOAT { $$ = dt_decl_spec(CTF_K_FLOAT, DUP("float")); }
+ | DT_KEY_DOUBLE { $$ = dt_decl_spec(CTF_K_FLOAT, DUP("double")); }
+ | DT_KEY_SIGNED { $$ = dt_decl_attr(DT_DA_SIGNED); }
+ | DT_KEY_UNSIGNED { $$ = dt_decl_attr(DT_DA_UNSIGNED); }
+ | DT_KEY_USERLAND { $$ = dt_decl_attr(DT_DA_USER); }
+ | DT_KEY_STRING {
+ $$ = dt_decl_spec(CTF_K_TYPEDEF, DUP("string"));
+ }
+ | DT_TOK_TNAME { $$ = dt_decl_spec(CTF_K_TYPEDEF, $1); }
+ | struct_or_union_specifier
+ | enum_specifier
+ ;
+
+type_qualifier: DT_KEY_CONST { $$ = dt_decl_attr(DT_DA_CONST); }
+ | DT_KEY_RESTRICT { $$ = dt_decl_attr(DT_DA_RESTRICT); }
+ | DT_KEY_VOLATILE { $$ = dt_decl_attr(DT_DA_VOLATILE); }
+ ;
+
+struct_or_union_specifier:
+ struct_or_union_definition struct_declaration_list '}' {
+ $$ = dt_scope_pop();
+ }
+ | struct_or_union DT_TOK_IDENT { $$ = dt_decl_spec($1, $2); }
+ | struct_or_union DT_TOK_TNAME { $$ = dt_decl_spec($1, $2); }
+ ;
+
+struct_or_union_definition:
+ struct_or_union '{' { dt_decl_sou($1, NULL); }
+ | struct_or_union DT_TOK_IDENT '{' { dt_decl_sou($1, $2); }
+ | struct_or_union DT_TOK_TNAME '{' { dt_decl_sou($1, $2); }
+ ;
+
+struct_or_union:
+ DT_KEY_STRUCT { $$ = CTF_K_STRUCT; }
+ | DT_KEY_UNION { $$ = CTF_K_UNION; }
+ ;
+
+struct_declaration_list:
+ struct_declaration
+ | struct_declaration_list struct_declaration
+ ;
+
+init_declarator_list:
+ init_declarator
+ | init_declarator_list DT_TOK_COMMA init_declarator {
+ $$ = LINK($1, $3);
+ }
+ ;
+
+init_declarator:
+ declarator {
+ $$ = dt_node_decl();
+ dt_decl_reset();
+ }
+ ;
+
+struct_declaration:
+ specifier_qualifier_list struct_declarator_list ';' {
+ dt_decl_free(dt_decl_pop());
+ }
+ ;
+
+specifier_qualifier_list:
+ type_specifier
+ | type_specifier specifier_qualifier_list { $$ = $2; }
+ | type_qualifier
+ | type_qualifier specifier_qualifier_list { $$ = $2; }
+ ;
+
+struct_declarator_list:
+ struct_declarator
+ | struct_declarator_list DT_TOK_COMMA struct_declarator
+ ;
+
+struct_declarator:
+ declarator { dt_decl_member(NULL); }
+ | DT_TOK_COLON constant_expression { dt_decl_member($2); }
+ | declarator DT_TOK_COLON constant_expression {
+ dt_decl_member($3);
+ }
+ ;
+
+enum_specifier:
+ enum_definition enumerator_list '}' { $$ = dt_scope_pop(); }
+ | DT_KEY_ENUM DT_TOK_IDENT { $$ = dt_decl_spec(CTF_K_ENUM, $2); }
+ | DT_KEY_ENUM DT_TOK_TNAME { $$ = dt_decl_spec(CTF_K_ENUM, $2); }
+ ;
+
+enum_definition:
+ DT_KEY_ENUM '{' { dt_decl_enum(NULL); }
+ | DT_KEY_ENUM DT_TOK_IDENT '{' { dt_decl_enum($2); }
+ | DT_KEY_ENUM DT_TOK_TNAME '{' { dt_decl_enum($2); }
+ ;
+
+enumerator_list:
+ enumerator
+ | enumerator_list DT_TOK_COMMA enumerator
+ ;
+
+enumerator: DT_TOK_IDENT { dt_decl_enumerator($1, NULL); }
+ | DT_TOK_IDENT DT_TOK_ASGN expression {
+ dt_decl_enumerator($1, $3);
+ }
+ ;
+
+declarator: direct_declarator
+ | pointer direct_declarator
+ ;
+
+direct_declarator:
+ DT_TOK_IDENT { $$ = dt_decl_ident($1); }
+ | lparen declarator DT_TOK_RPAR { $$ = $2; }
+ | direct_declarator array { dt_decl_array($2); }
+ | direct_declarator function { dt_decl_func($1, $2); }
+ ;
+
+lparen: DT_TOK_LPAR { dt_decl_top()->dd_attr |= DT_DA_PAREN; }
+ ;
+
+pointer: DT_TOK_MUL { $$ = dt_decl_ptr(); }
+ | DT_TOK_MUL type_qualifier_list { $$ = dt_decl_ptr(); }
+ | DT_TOK_MUL pointer { $$ = dt_decl_ptr(); }
+ | DT_TOK_MUL type_qualifier_list pointer { $$ = dt_decl_ptr(); }
+ ;
+
+type_qualifier_list:
+ type_qualifier
+ | type_qualifier_list type_qualifier { $$ = $2; }
+ ;
+
+parameter_type_list:
+ parameter_list
+ | DT_TOK_ELLIPSIS { $$ = dt_node_vatype(); }
+ | parameter_list DT_TOK_COMMA DT_TOK_ELLIPSIS {
+ $$ = LINK($1, dt_node_vatype());
+ }
+ ;
+
+parameter_list: parameter_declaration
+ | parameter_list DT_TOK_COMMA parameter_declaration {
+ $$ = LINK($1, $3);
+ }
+ ;
+
+parameter_declaration:
+ parameter_declaration_specifiers {
+ $$ = dt_node_type(NULL);
+ }
+ | parameter_declaration_specifiers declarator {
+ $$ = dt_node_type(NULL);
+ }
+ | parameter_declaration_specifiers abstract_declarator {
+ $$ = dt_node_type(NULL);
+ }
+ ;
+
+type_name: specifier_qualifier_list {
+ $$ = dt_decl_pop();
+ }
+ | specifier_qualifier_list abstract_declarator {
+ $$ = dt_decl_pop();
+ }
+ ;
+
+abstract_declarator:
+ pointer
+ | direct_abstract_declarator
+ | pointer direct_abstract_declarator
+ ;
+
+direct_abstract_declarator:
+ lparen abstract_declarator DT_TOK_RPAR { $$ = $2; }
+ | direct_abstract_declarator array { dt_decl_array($2); }
+ | array { dt_decl_array($1); $$ = NULL; }
+ | direct_abstract_declarator function { dt_decl_func($1, $2); }
+ | function { dt_decl_func(NULL, $1); }
+ ;
+
+array: DT_TOK_LBRAC { dt_scope_push(NULL, CTF_ERR); }
+ array_parameters DT_TOK_RBRAC {
+ dt_scope_pop();
+ $$ = $3;
+ }
+ ;
+
+array_parameters:
+ /* empty */ { $$ = NULL; }
+ | constant_expression { $$ = $1; }
+ | parameter_type_list { $$ = $1; }
+ ;
+
+function: DT_TOK_LPAR { dt_scope_push(NULL, CTF_ERR); }
+ function_parameters DT_TOK_RPAR {
+ dt_scope_pop();
+ $$ = $3;
+ }
+ ;
+
+function_parameters:
+ /* empty */ { $$ = NULL; }
+ | parameter_type_list { $$ = $1; }
+ ;
+
+dtrace_keyword_ident:
+ DT_KEY_PROBE { $$ = DUP("probe"); }
+ | DT_KEY_PROVIDER { $$ = DUP("provider"); }
+ | DT_KEY_SELF { $$ = DUP("self"); }
+ | DT_KEY_STRING { $$ = DUP("string"); }
+ | DT_TOK_STRINGOF { $$ = DUP("stringof"); }
+ | DT_KEY_USERLAND { $$ = DUP("userland"); }
+ | DT_TOK_XLATE { $$ = DUP("xlate"); }
+ | DT_KEY_XLATOR { $$ = DUP("translator"); }
+ ;
+
+%%
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c
new file mode 100644
index 000000000000..f26126bba517
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c
@@ -0,0 +1,485 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+
+#include <dt_impl.h>
+#include <dt_program.h>
+
+static const char _dt_errprog[] =
+"dtrace:::ERROR"
+"{"
+" trace(arg1);"
+" trace(arg2);"
+" trace(arg3);"
+" trace(arg4);"
+" trace(arg5);"
+"}";
+
+int
+dtrace_handle_err(dtrace_hdl_t *dtp, dtrace_handle_err_f *hdlr, void *arg)
+{
+ dtrace_prog_t *pgp = NULL;
+ dt_stmt_t *stp;
+ dtrace_ecbdesc_t *edp;
+
+ /*
+ * We don't currently support multiple error handlers.
+ */
+ if (dtp->dt_errhdlr != NULL)
+ return (dt_set_errno(dtp, EALREADY));
+
+ /*
+ * If the DTRACEOPT_GRABANON is enabled, the anonymous enabling will
+ * already have a dtrace:::ERROR probe enabled; save 'hdlr' and 'arg'
+ * but do not bother compiling and enabling _dt_errprog.
+ */
+ if (dtp->dt_options[DTRACEOPT_GRABANON] != DTRACEOPT_UNSET)
+ goto out;
+
+ if ((pgp = dtrace_program_strcompile(dtp, _dt_errprog,
+ DTRACE_PROBESPEC_NAME, DTRACE_C_ZDEFS, 0, NULL)) == NULL)
+ return (dt_set_errno(dtp, dtrace_errno(dtp)));
+
+ stp = dt_list_next(&pgp->dp_stmts);
+ assert(stp != NULL);
+
+ edp = stp->ds_desc->dtsd_ecbdesc;
+ assert(edp != NULL);
+ edp->dted_uarg = DT_ECB_ERROR;
+
+out:
+ dtp->dt_errhdlr = hdlr;
+ dtp->dt_errarg = arg;
+ dtp->dt_errprog = pgp;
+
+ return (0);
+}
+
+int
+dtrace_handle_drop(dtrace_hdl_t *dtp, dtrace_handle_drop_f *hdlr, void *arg)
+{
+ if (dtp->dt_drophdlr != NULL)
+ return (dt_set_errno(dtp, EALREADY));
+
+ dtp->dt_drophdlr = hdlr;
+ dtp->dt_droparg = arg;
+
+ return (0);
+}
+
+int
+dtrace_handle_proc(dtrace_hdl_t *dtp, dtrace_handle_proc_f *hdlr, void *arg)
+{
+ if (dtp->dt_prochdlr != NULL)
+ return (dt_set_errno(dtp, EALREADY));
+
+ dtp->dt_prochdlr = hdlr;
+ dtp->dt_procarg = arg;
+
+ return (0);
+}
+
+int
+dtrace_handle_buffered(dtrace_hdl_t *dtp, dtrace_handle_buffered_f *hdlr,
+ void *arg)
+{
+ if (dtp->dt_bufhdlr != NULL)
+ return (dt_set_errno(dtp, EALREADY));
+
+ if (hdlr == NULL)
+ return (dt_set_errno(dtp, EINVAL));
+
+ dtp->dt_bufhdlr = hdlr;
+ dtp->dt_bufarg = arg;
+
+ return (0);
+}
+
+int
+dtrace_handle_setopt(dtrace_hdl_t *dtp, dtrace_handle_setopt_f *hdlr,
+ void *arg)
+{
+ if (hdlr == NULL)
+ return (dt_set_errno(dtp, EINVAL));
+
+ dtp->dt_setopthdlr = hdlr;
+ dtp->dt_setoptarg = arg;
+
+ return (0);
+}
+
+#define DT_REC(type, ndx) *((type *)((uintptr_t)data->dtpda_data + \
+ epd->dtepd_rec[(ndx)].dtrd_offset))
+
+static int
+dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
+{
+ dtrace_eprobedesc_t *epd = data->dtpda_edesc, *errepd;
+ dtrace_probedesc_t *pd = data->dtpda_pdesc, *errpd;
+ dtrace_errdata_t err;
+ dtrace_epid_t epid;
+
+ char where[30];
+ char details[30];
+ char offinfo[30];
+ const int slop = 80;
+ const char *faultstr;
+ char *str;
+ int len;
+
+ assert(epd->dtepd_uarg == DT_ECB_ERROR);
+
+ if (epd->dtepd_nrecs != 5 || strcmp(pd->dtpd_provider, "dtrace") != 0 ||
+ strcmp(pd->dtpd_name, "ERROR") != 0)
+ return (dt_set_errno(dtp, EDT_BADERROR));
+
+ /*
+ * This is an error. We have the following items here: EPID,
+ * faulting action, DIF offset, fault code and faulting address.
+ */
+ epid = (uint32_t)DT_REC(uint64_t, 0);
+
+ if (dt_epid_lookup(dtp, epid, &errepd, &errpd) != 0)
+ return (dt_set_errno(dtp, EDT_BADERROR));
+
+ err.dteda_edesc = errepd;
+ err.dteda_pdesc = errpd;
+ err.dteda_cpu = data->dtpda_cpu;
+ err.dteda_action = (int)DT_REC(uint64_t, 1);
+ err.dteda_offset = (int)DT_REC(uint64_t, 2);
+ err.dteda_fault = (int)DT_REC(uint64_t, 3);
+ err.dteda_addr = DT_REC(uint64_t, 4);
+
+ faultstr = dtrace_faultstr(dtp, err.dteda_fault);
+ len = sizeof (where) + sizeof (offinfo) + strlen(faultstr) +
+ strlen(errpd->dtpd_provider) + strlen(errpd->dtpd_mod) +
+ strlen(errpd->dtpd_name) + strlen(errpd->dtpd_func) +
+ slop;
+
+ str = (char *)alloca(len);
+
+ if (err.dteda_action == 0) {
+ (void) sprintf(where, "predicate");
+ } else {
+ (void) sprintf(where, "action #%d", err.dteda_action);
+ }
+
+ if (err.dteda_offset != -1) {
+ (void) sprintf(offinfo, " at DIF offset %d", err.dteda_offset);
+ } else {
+ offinfo[0] = 0;
+ }
+
+ switch (err.dteda_fault) {
+ case DTRACEFLT_BADADDR:
+ case DTRACEFLT_BADALIGN:
+ case DTRACEFLT_BADSTACK:
+ (void) sprintf(details, " (0x%llx)",
+ (u_longlong_t)err.dteda_addr);
+ break;
+
+ default:
+ details[0] = 0;
+ }
+
+ (void) snprintf(str, len, "error on enabled probe ID %u "
+ "(ID %u: %s:%s:%s:%s): %s%s in %s%s\n",
+ epid, errpd->dtpd_id, errpd->dtpd_provider,
+ errpd->dtpd_mod, errpd->dtpd_func,
+ errpd->dtpd_name, dtrace_faultstr(dtp, err.dteda_fault),
+ details, where, offinfo);
+
+ err.dteda_msg = str;
+
+ if (dtp->dt_errhdlr == NULL)
+ return (dt_set_errno(dtp, EDT_ERRABORT));
+
+ if ((*dtp->dt_errhdlr)(&err, dtp->dt_errarg) == DTRACE_HANDLE_ABORT)
+ return (dt_set_errno(dtp, EDT_ERRABORT));
+
+ return (0);
+}
+
+int
+dt_handle_liberr(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
+ const char *faultstr)
+{
+ dtrace_probedesc_t *errpd = data->dtpda_pdesc;
+ dtrace_errdata_t err;
+ const int slop = 80;
+ char *str;
+ int len;
+
+ err.dteda_edesc = data->dtpda_edesc;
+ err.dteda_pdesc = errpd;
+ err.dteda_cpu = data->dtpda_cpu;
+ err.dteda_action = -1;
+ err.dteda_offset = -1;
+ err.dteda_fault = DTRACEFLT_LIBRARY;
+ err.dteda_addr = 0;
+
+ len = strlen(faultstr) +
+ strlen(errpd->dtpd_provider) + strlen(errpd->dtpd_mod) +
+ strlen(errpd->dtpd_name) + strlen(errpd->dtpd_func) +
+ slop;
+
+ str = alloca(len);
+
+ (void) snprintf(str, len, "error on enabled probe ID %u "
+ "(ID %u: %s:%s:%s:%s): %s\n",
+ data->dtpda_edesc->dtepd_epid,
+ errpd->dtpd_id, errpd->dtpd_provider,
+ errpd->dtpd_mod, errpd->dtpd_func,
+ errpd->dtpd_name, faultstr);
+
+ err.dteda_msg = str;
+
+ if (dtp->dt_errhdlr == NULL)
+ return (dt_set_errno(dtp, EDT_ERRABORT));
+
+ if ((*dtp->dt_errhdlr)(&err, dtp->dt_errarg) == DTRACE_HANDLE_ABORT)
+ return (dt_set_errno(dtp, EDT_ERRABORT));
+
+ return (0);
+}
+
+#define DROPTAG(x) x, #x
+
+static const struct {
+ dtrace_dropkind_t dtdrg_kind;
+ char *dtdrg_tag;
+} _dt_droptags[] = {
+ { DROPTAG(DTRACEDROP_PRINCIPAL) },
+ { DROPTAG(DTRACEDROP_AGGREGATION) },
+ { DROPTAG(DTRACEDROP_DYNAMIC) },
+ { DROPTAG(DTRACEDROP_DYNRINSE) },
+ { DROPTAG(DTRACEDROP_DYNDIRTY) },
+ { DROPTAG(DTRACEDROP_SPEC) },
+ { DROPTAG(DTRACEDROP_SPECBUSY) },
+ { DROPTAG(DTRACEDROP_SPECUNAVAIL) },
+ { DROPTAG(DTRACEDROP_DBLERROR) },
+ { DROPTAG(DTRACEDROP_STKSTROVERFLOW) },
+ { 0, NULL }
+};
+
+static const char *
+dt_droptag(dtrace_dropkind_t kind)
+{
+ int i;
+
+ for (i = 0; _dt_droptags[i].dtdrg_tag != NULL; i++) {
+ if (_dt_droptags[i].dtdrg_kind == kind)
+ return (_dt_droptags[i].dtdrg_tag);
+ }
+
+ return ("DTRACEDROP_UNKNOWN");
+}
+
+int
+dt_handle_cpudrop(dtrace_hdl_t *dtp, processorid_t cpu,
+ dtrace_dropkind_t what, uint64_t howmany)
+{
+ dtrace_dropdata_t drop;
+ char str[80], *s;
+ int size;
+
+ assert(what == DTRACEDROP_PRINCIPAL || what == DTRACEDROP_AGGREGATION);
+
+ bzero(&drop, sizeof (drop));
+ drop.dtdda_handle = dtp;
+ drop.dtdda_cpu = cpu;
+ drop.dtdda_kind = what;
+ drop.dtdda_drops = howmany;
+ drop.dtdda_msg = str;
+
+ if (dtp->dt_droptags) {
+ (void) snprintf(str, sizeof (str), "[%s] ", dt_droptag(what));
+ s = &str[strlen(str)];
+ size = sizeof (str) - (s - str);
+ } else {
+ s = str;
+ size = sizeof (str);
+ }
+
+ (void) snprintf(s, size, "%llu %sdrop%s on CPU %d\n",
+ (u_longlong_t)howmany,
+ what == DTRACEDROP_PRINCIPAL ? "" : "aggregation ",
+ howmany > 1 ? "s" : "", cpu);
+
+ if (dtp->dt_drophdlr == NULL)
+ return (dt_set_errno(dtp, EDT_DROPABORT));
+
+ if ((*dtp->dt_drophdlr)(&drop, dtp->dt_droparg) == DTRACE_HANDLE_ABORT)
+ return (dt_set_errno(dtp, EDT_DROPABORT));
+
+ return (0);
+}
+
+static const struct {
+ dtrace_dropkind_t dtdrt_kind;
+ uintptr_t dtdrt_offset;
+ const char *dtdrt_str;
+ const char *dtdrt_msg;
+} _dt_droptab[] = {
+ { DTRACEDROP_DYNAMIC,
+ offsetof(dtrace_status_t, dtst_dyndrops),
+ "dynamic variable drop" },
+
+ { DTRACEDROP_DYNRINSE,
+ offsetof(dtrace_status_t, dtst_dyndrops_rinsing),
+ "dynamic variable drop", " with non-empty rinsing list" },
+
+ { DTRACEDROP_DYNDIRTY,
+ offsetof(dtrace_status_t, dtst_dyndrops_dirty),
+ "dynamic variable drop", " with non-empty dirty list" },
+
+ { DTRACEDROP_SPEC,
+ offsetof(dtrace_status_t, dtst_specdrops),
+ "speculative drop" },
+
+ { DTRACEDROP_SPECBUSY,
+ offsetof(dtrace_status_t, dtst_specdrops_busy),
+ "failed speculation", " (available buffer(s) still busy)" },
+
+ { DTRACEDROP_SPECUNAVAIL,
+ offsetof(dtrace_status_t, dtst_specdrops_unavail),
+ "failed speculation", " (no speculative buffer available)" },
+
+ { DTRACEDROP_STKSTROVERFLOW,
+ offsetof(dtrace_status_t, dtst_stkstroverflows),
+ "jstack()/ustack() string table overflow" },
+
+ { DTRACEDROP_DBLERROR,
+ offsetof(dtrace_status_t, dtst_dblerrors),
+ "error", " in ERROR probe enabling" },
+
+ { 0, 0, NULL }
+};
+
+int
+dt_handle_status(dtrace_hdl_t *dtp, dtrace_status_t *old, dtrace_status_t *new)
+{
+ dtrace_dropdata_t drop;
+ char str[80], *s;
+ uintptr_t base = (uintptr_t)new, obase = (uintptr_t)old;
+ int i, size;
+
+ bzero(&drop, sizeof (drop));
+ drop.dtdda_handle = dtp;
+ drop.dtdda_cpu = DTRACE_CPUALL;
+ drop.dtdda_msg = str;
+
+ /*
+ * First, check to see if we've been killed -- in which case we abort.
+ */
+ if (new->dtst_killed && !old->dtst_killed)
+ return (dt_set_errno(dtp, EDT_BRICKED));
+
+ for (i = 0; _dt_droptab[i].dtdrt_str != NULL; i++) {
+ uintptr_t naddr = base + _dt_droptab[i].dtdrt_offset;
+ uintptr_t oaddr = obase + _dt_droptab[i].dtdrt_offset;
+
+ uint64_t nval = *((uint64_t *)naddr);
+ uint64_t oval = *((uint64_t *)oaddr);
+
+ if (nval == oval)
+ continue;
+
+ if (dtp->dt_droptags) {
+ (void) snprintf(str, sizeof (str), "[%s] ",
+ dt_droptag(_dt_droptab[i].dtdrt_kind));
+ s = &str[strlen(str)];
+ size = sizeof (str) - (s - str);
+ } else {
+ s = str;
+ size = sizeof (str);
+ }
+
+ (void) snprintf(s, size, "%llu %s%s%s\n",
+ (u_longlong_t)(nval - oval),
+ _dt_droptab[i].dtdrt_str, (nval - oval > 1) ? "s" : "",
+ _dt_droptab[i].dtdrt_msg != NULL ?
+ _dt_droptab[i].dtdrt_msg : "");
+
+ drop.dtdda_kind = _dt_droptab[i].dtdrt_kind;
+ drop.dtdda_total = nval;
+ drop.dtdda_drops = nval - oval;
+
+ if (dtp->dt_drophdlr == NULL)
+ return (dt_set_errno(dtp, EDT_DROPABORT));
+
+ if ((*dtp->dt_drophdlr)(&drop,
+ dtp->dt_droparg) == DTRACE_HANDLE_ABORT)
+ return (dt_set_errno(dtp, EDT_DROPABORT));
+ }
+
+ return (0);
+}
+
+int
+dt_handle_setopt(dtrace_hdl_t *dtp, dtrace_setoptdata_t *data)
+{
+ void *arg = dtp->dt_setoptarg;
+
+ if (dtp->dt_setopthdlr == NULL)
+ return (0);
+
+ if ((*dtp->dt_setopthdlr)(data, arg) == DTRACE_HANDLE_ABORT)
+ return (dt_set_errno(dtp, EDT_DIRABORT));
+
+ return (0);
+}
+
+int
+dt_handle(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
+{
+ dtrace_eprobedesc_t *epd = data->dtpda_edesc;
+ int rval;
+
+ switch (epd->dtepd_uarg) {
+ case DT_ECB_ERROR:
+ rval = dt_handle_err(dtp, data);
+ break;
+
+ default:
+ return (DTRACE_CONSUME_THIS);
+ }
+
+ if (rval == 0)
+ return (DTRACE_CONSUME_NEXT);
+
+ return (DTRACE_CONSUME_ERROR);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c
new file mode 100644
index 000000000000..b9164ac26cf9
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c
@@ -0,0 +1,1052 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef illumos
+#include <sys/sysmacros.h>
+#endif
+#include <strings.h>
+#include <stdlib.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <assert.h>
+#include <errno.h>
+#include <ctype.h>
+#ifdef illumos
+#include <sys/procfs_isa.h>
+#endif
+#include <limits.h>
+
+#include <dt_ident.h>
+#include <dt_parser.h>
+#include <dt_provider.h>
+#include <dt_strtab.h>
+#include <dt_impl.h>
+
+/*
+ * Common code for cooking an identifier that uses a typed signature list (we
+ * use this for associative arrays and functions). If the argument list is
+ * of the same length and types, then return the return type. Otherwise
+ * print an appropriate compiler error message and abort the compile.
+ */
+static void
+dt_idcook_sign(dt_node_t *dnp, dt_ident_t *idp,
+ int argc, dt_node_t *args, const char *prefix, const char *suffix)
+{
+ dt_idsig_t *isp = idp->di_data;
+ int i, compat, mismatch, arglimit, iskey;
+
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ iskey = idp->di_kind == DT_IDENT_ARRAY || idp->di_kind == DT_IDENT_AGG;
+
+ if (isp->dis_varargs >= 0) {
+ mismatch = argc < isp->dis_varargs;
+ arglimit = isp->dis_varargs;
+ } else if (isp->dis_optargs >= 0) {
+ mismatch = (argc < isp->dis_optargs || argc > isp->dis_argc);
+ arglimit = argc;
+ } else {
+ mismatch = argc != isp->dis_argc;
+ arglimit = isp->dis_argc;
+ }
+
+ if (mismatch) {
+ xyerror(D_PROTO_LEN, "%s%s%s prototype mismatch: %d %s%s"
+ "passed, %s%d expected\n", prefix, idp->di_name, suffix,
+ argc, iskey ? "key" : "arg", argc == 1 ? " " : "s ",
+ isp->dis_optargs >= 0 ? "at least " : "",
+ isp->dis_optargs >= 0 ? isp->dis_optargs : arglimit);
+ }
+
+ for (i = 0; i < arglimit; i++, args = args->dn_list) {
+ if (isp->dis_args[i].dn_ctfp != NULL)
+ compat = dt_node_is_argcompat(&isp->dis_args[i], args);
+ else
+ compat = 1; /* "@" matches any type */
+
+ if (!compat) {
+ xyerror(D_PROTO_ARG,
+ "%s%s%s %s #%d is incompatible with "
+ "prototype:\n\tprototype: %s\n\t%9s: %s\n",
+ prefix, idp->di_name, suffix,
+ iskey ? "key" : "argument", i + 1,
+ dt_node_type_name(&isp->dis_args[i], n1,
+ sizeof (n1)),
+ iskey ? "key" : "argument",
+ dt_node_type_name(args, n2, sizeof (n2)));
+ }
+ }
+
+ dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
+}
+
+/*
+ * Cook an associative array identifier. If this is the first time we are
+ * cooking this array, create its signature based on the argument list.
+ * Otherwise validate the argument list against the existing signature.
+ */
+static void
+dt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
+{
+ if (idp->di_data == NULL) {
+ dt_idsig_t *isp = idp->di_data = malloc(sizeof (dt_idsig_t));
+ char n[DT_TYPE_NAMELEN];
+ int i;
+
+ if (isp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ isp->dis_varargs = -1;
+ isp->dis_optargs = -1;
+ isp->dis_argc = argc;
+ isp->dis_args = NULL;
+ isp->dis_auxinfo = 0;
+
+ if (argc != 0 && (isp->dis_args = calloc(argc,
+ sizeof (dt_node_t))) == NULL) {
+ idp->di_data = NULL;
+ free(isp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ /*
+ * If this identifier has not been explicitly declared earlier,
+ * set the identifier's base type to be our special type <DYN>.
+ * If this ident is an aggregation, it will remain as is. If
+ * this ident is an associative array, it will be reassigned
+ * based on the result type of the first assignment statement.
+ */
+ if (!(idp->di_flags & DT_IDFLG_DECL)) {
+ idp->di_ctfp = DT_DYN_CTFP(yypcb->pcb_hdl);
+ idp->di_type = DT_DYN_TYPE(yypcb->pcb_hdl);
+ }
+
+ for (i = 0; i < argc; i++, args = args->dn_list) {
+ if (dt_node_is_dynamic(args) || dt_node_is_void(args)) {
+ xyerror(D_KEY_TYPE, "%s expression may not be "
+ "used as %s index: key #%d\n",
+ dt_node_type_name(args, n, sizeof (n)),
+ dt_idkind_name(idp->di_kind), i + 1);
+ }
+
+ dt_node_type_propagate(args, &isp->dis_args[i]);
+ isp->dis_args[i].dn_list = &isp->dis_args[i + 1];
+ }
+
+ if (argc != 0)
+ isp->dis_args[argc - 1].dn_list = NULL;
+
+ dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
+
+ } else {
+ dt_idcook_sign(dnp, idp, argc, args,
+ idp->di_kind == DT_IDENT_AGG ? "@" : "", "[ ]");
+ }
+}
+
+/*
+ * Cook a function call. If this is the first time we are cooking this
+ * identifier, create its type signature based on predefined prototype stored
+ * in di_iarg. We then validate the argument list against this signature.
+ */
+static void
+dt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
+{
+ if (idp->di_data == NULL) {
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dtrace_typeinfo_t dtt;
+ dt_idsig_t *isp;
+ char *s, *p1, *p2;
+ int i = 0;
+
+ assert(idp->di_iarg != NULL);
+ s = alloca(strlen(idp->di_iarg) + 1);
+ (void) strcpy(s, idp->di_iarg);
+
+ if ((p2 = strrchr(s, ')')) != NULL)
+ *p2 = '\0'; /* mark end of parameter list string */
+
+ if ((p1 = strchr(s, '(')) != NULL)
+ *p1++ = '\0'; /* mark end of return type string */
+
+ if (p1 == NULL || p2 == NULL) {
+ xyerror(D_UNKNOWN, "internal error: malformed entry "
+ "for built-in function %s\n", idp->di_name);
+ }
+
+ for (p2 = p1; *p2 != '\0'; p2++) {
+ if (!isspace(*p2)) {
+ i++;
+ break;
+ }
+ }
+
+ for (p2 = strchr(p2, ','); p2++ != NULL; i++)
+ p2 = strchr(p2, ',');
+
+ /*
+ * We first allocate a new ident signature structure with the
+ * appropriate number of argument entries, and then look up
+ * the return type and store its CTF data in di_ctfp/type.
+ */
+ if ((isp = idp->di_data = malloc(sizeof (dt_idsig_t))) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ isp->dis_varargs = -1;
+ isp->dis_optargs = -1;
+ isp->dis_argc = i;
+ isp->dis_args = NULL;
+ isp->dis_auxinfo = 0;
+
+ if (i != 0 && (isp->dis_args = calloc(i,
+ sizeof (dt_node_t))) == NULL) {
+ idp->di_data = NULL;
+ free(isp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ if (dt_type_lookup(s, &dtt) == -1) {
+ xyerror(D_UNKNOWN, "failed to resolve type of %s (%s):"
+ " %s\n", idp->di_name, s,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ if (idp->di_kind == DT_IDENT_AGGFUNC) {
+ idp->di_ctfp = DT_DYN_CTFP(dtp);
+ idp->di_type = DT_DYN_TYPE(dtp);
+ } else {
+ idp->di_ctfp = dtt.dtt_ctfp;
+ idp->di_type = dtt.dtt_type;
+ }
+
+ /*
+ * For each comma-delimited parameter in the prototype string,
+ * we look up the corresponding type and store its CTF data in
+ * the corresponding location in dis_args[]. We also recognize
+ * the special type string "@" to indicate that the specified
+ * parameter may be a D expression of *any* type (represented
+ * as a dis_args[] element with ctfp = NULL, type == CTF_ERR).
+ * If a varargs "..." is present, we record the argument index
+ * in dis_varargs for the benefit of dt_idcook_sign(), above.
+ * If the type of an argument is enclosed in square brackets
+ * (e.g. "[int]"), the argument is considered optional: the
+ * argument may be absent, but if it is present, it must be of
+ * the specified type. Note that varargs may not optional,
+ * optional arguments may not follow varargs, and non-optional
+ * arguments may not follow optional arguments.
+ */
+ for (i = 0; i < isp->dis_argc; i++, p1 = p2) {
+ while (isspace(*p1))
+ p1++; /* skip leading whitespace */
+
+ if ((p2 = strchr(p1, ',')) == NULL)
+ p2 = p1 + strlen(p1);
+ else
+ *p2++ = '\0';
+
+ if (strcmp(p1, "@") == 0 || strcmp(p1, "...") == 0) {
+ isp->dis_args[i].dn_ctfp = NULL;
+ isp->dis_args[i].dn_type = CTF_ERR;
+ if (*p1 == '.')
+ isp->dis_varargs = i;
+ continue;
+ }
+
+ if (*p1 == '[' && p1[strlen(p1) - 1] == ']') {
+ if (isp->dis_varargs != -1) {
+ xyerror(D_UNKNOWN, "optional arg#%d "
+ "may not follow variable arg#%d\n",
+ i + 1, isp->dis_varargs + 1);
+ }
+
+ if (isp->dis_optargs == -1)
+ isp->dis_optargs = i;
+
+ p1[strlen(p1) - 1] = '\0';
+ p1++;
+ } else if (isp->dis_optargs != -1) {
+ xyerror(D_UNKNOWN, "required arg#%d may not "
+ "follow optional arg#%d\n", i + 1,
+ isp->dis_optargs + 1);
+ }
+
+ if (dt_type_lookup(p1, &dtt) == -1) {
+ xyerror(D_UNKNOWN, "failed to resolve type of "
+ "%s arg#%d (%s): %s\n", idp->di_name, i + 1,
+ p1, dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ dt_node_type_assign(&isp->dis_args[i],
+ dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
+ }
+ }
+
+ dt_idcook_sign(dnp, idp, argc, args, "", "( )");
+}
+
+/*
+ * Cook a reference to the dynamically typed args[] array. We verify that the
+ * reference is using a single integer constant, and then construct a new ident
+ * representing the appropriate type or translation specifically for this node.
+ */
+static void
+dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_probe_t *prp = yypcb->pcb_probe;
+
+ dt_node_t tag, *nnp, *xnp;
+ dt_xlator_t *dxp;
+ dt_ident_t *xidp;
+
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ if (argc != 1) {
+ xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
+ "passed, 1 expected\n", idp->di_name, argc,
+ argc == 1 ? " " : "s ");
+ }
+
+ if (ap->dn_kind != DT_NODE_INT) {
+ xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
+ "prototype:\n\tprototype: %s\n\t argument: %s\n",
+ idp->di_name, "integer constant",
+ dt_type_name(ap->dn_ctfp, ap->dn_type, n1, sizeof (n1)));
+ }
+
+ if (yypcb->pcb_pdesc == NULL) {
+ xyerror(D_ARGS_NONE, "%s[ ] may not be referenced outside "
+ "of a probe clause\n", idp->di_name);
+ }
+
+ if (prp == NULL) {
+ xyerror(D_ARGS_MULTI,
+ "%s[ ] may not be referenced because probe description %s "
+ "matches an unstable set of probes\n", idp->di_name,
+ dtrace_desc2str(yypcb->pcb_pdesc, n1, sizeof (n1)));
+ }
+
+ if (ap->dn_value >= prp->pr_argc) {
+ xyerror(D_ARGS_IDX, "index %lld is out of range for %s %s[ ]\n",
+ (longlong_t)ap->dn_value, dtrace_desc2str(yypcb->pcb_pdesc,
+ n1, sizeof (n1)), idp->di_name);
+ }
+
+ /*
+ * Look up the native and translated argument types for the probe.
+ * If no translation is needed, these will be the same underlying node.
+ * If translation is needed, look up the appropriate translator. Once
+ * we have the appropriate node, create a new dt_ident_t for this node,
+ * assign it the appropriate attributes, and set the type of 'dnp'.
+ */
+ xnp = prp->pr_xargv[ap->dn_value];
+ nnp = prp->pr_nargv[prp->pr_mapping[ap->dn_value]];
+
+ if (xnp->dn_type == CTF_ERR) {
+ xyerror(D_ARGS_TYPE, "failed to resolve translated type for "
+ "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
+ }
+
+ if (nnp->dn_type == CTF_ERR) {
+ xyerror(D_ARGS_TYPE, "failed to resolve native type for "
+ "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
+ }
+
+ if (dtp->dt_xlatemode == DT_XL_STATIC && (
+ nnp == xnp || dt_node_is_argcompat(nnp, xnp))) {
+ dnp->dn_ident = dt_ident_create(idp->di_name, idp->di_kind,
+ idp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
+ idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);
+
+ if (dnp->dn_ident == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dt_node_type_assign(dnp,
+ prp->pr_argv[ap->dn_value].dtt_ctfp,
+ prp->pr_argv[ap->dn_value].dtt_type,
+ prp->pr_argv[ap->dn_value].dtt_flags & DTT_FL_USER ?
+ B_TRUE : B_FALSE);
+
+ } else if ((dxp = dt_xlator_lookup(dtp,
+ nnp, xnp, DT_XLATE_FUZZY)) != NULL || (
+ dxp = dt_xlator_lookup(dtp, dt_probe_tag(prp, ap->dn_value, &tag),
+ xnp, DT_XLATE_EXACT | DT_XLATE_EXTERN)) != NULL) {
+
+ xidp = dt_xlator_ident(dxp, xnp->dn_ctfp, xnp->dn_type);
+
+ dnp->dn_ident = dt_ident_create(idp->di_name, xidp->di_kind,
+ xidp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
+ idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);
+
+ if (dnp->dn_ident == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ if (dt_xlator_dynamic(dxp))
+ dxp->dx_arg = (int)ap->dn_value;
+
+ /*
+ * Propagate relevant members from the translator's internal
+ * dt_ident_t. This code must be kept in sync with the state
+ * that is initialized for idents in dt_xlator_create().
+ */
+ dnp->dn_ident->di_data = xidp->di_data;
+ dnp->dn_ident->di_ctfp = xidp->di_ctfp;
+ dnp->dn_ident->di_type = xidp->di_type;
+
+ dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp),
+ B_FALSE);
+
+ } else {
+ xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s "
+ "is not defined\n", idp->di_name, (longlong_t)ap->dn_value,
+ dt_node_type_name(nnp, n1, sizeof (n1)),
+ dt_node_type_name(xnp, n2, sizeof (n2)));
+ }
+
+ assert(dnp->dn_ident->di_flags & DT_IDFLG_ORPHAN);
+ assert(dnp->dn_ident->di_id == idp->di_id);
+}
+
+static void
+dt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
+{
+ dtrace_typeinfo_t dtt;
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ char n[DT_TYPE_NAMELEN];
+
+ if (argc != 1) {
+ xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
+ "passed, 1 expected\n", idp->di_name,
+ argc, argc == 1 ? " " : "s ");
+ }
+
+ if (ap->dn_kind != DT_NODE_INT) {
+ xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
+ "prototype:\n\tprototype: %s\n\t argument: %s\n",
+ idp->di_name, "integer constant",
+ dt_type_name(ap->dn_ctfp, ap->dn_type, n, sizeof (n)));
+ }
+
+ if ((ap->dn_flags & DT_NF_SIGNED) && (int64_t)ap->dn_value < 0) {
+ xyerror(D_REGS_IDX, "index %lld is out of range for array %s\n",
+ (longlong_t)ap->dn_value, idp->di_name);
+ }
+
+ if (dt_type_lookup("uint64_t", &dtt) == -1) {
+ xyerror(D_UNKNOWN, "failed to resolve type of %s: %s\n",
+ idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ idp->di_ctfp = dtt.dtt_ctfp;
+ idp->di_type = dtt.dtt_type;
+
+ dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
+}
+
+/*ARGSUSED*/
+static void
+dt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
+{
+ if (idp->di_type == CTF_ERR) {
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dtrace_typeinfo_t dtt;
+
+ if (dt_type_lookup(idp->di_iarg, &dtt) == -1) {
+ xyerror(D_UNKNOWN,
+ "failed to resolve type %s for identifier %s: %s\n",
+ (const char *)idp->di_iarg, idp->di_name,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ idp->di_ctfp = dtt.dtt_ctfp;
+ idp->di_type = dtt.dtt_type;
+ }
+
+ dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
+}
+
+/*ARGSUSED*/
+static void
+dt_idcook_thaw(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
+{
+ if (idp->di_ctfp != NULL && idp->di_type != CTF_ERR)
+ dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
+}
+
+static void
+dt_idcook_inline(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
+{
+ if (idp->di_kind == DT_IDENT_ARRAY)
+ dt_idcook_assc(dnp, idp, argc, args);
+ else
+ dt_idcook_thaw(dnp, idp, argc, args);
+}
+
+static void
+dt_iddtor_sign(dt_ident_t *idp)
+{
+ if (idp->di_data != NULL)
+ free(((dt_idsig_t *)idp->di_data)->dis_args);
+ free(idp->di_data);
+}
+
+static void
+dt_iddtor_free(dt_ident_t *idp)
+{
+ free(idp->di_data);
+}
+
+static void
+dt_iddtor_inline(dt_ident_t *idp)
+{
+ dt_idnode_t *inp = idp->di_iarg;
+
+ if (inp != NULL) {
+ dt_node_link_free(&inp->din_list);
+
+ if (inp->din_hash != NULL)
+ dt_idhash_destroy(inp->din_hash);
+
+ free(inp->din_argv);
+ free(inp);
+ }
+
+ if (idp->di_kind == DT_IDENT_ARRAY)
+ dt_iddtor_sign(idp);
+ else
+ dt_iddtor_free(idp);
+}
+
+/*ARGSUSED*/
+static void
+dt_iddtor_none(dt_ident_t *idp)
+{
+ /* do nothing */
+}
+
+static void
+dt_iddtor_probe(dt_ident_t *idp)
+{
+ if (idp->di_data != NULL)
+ dt_probe_destroy(idp->di_data);
+}
+
+static size_t
+dt_idsize_type(dt_ident_t *idp)
+{
+ return (ctf_type_size(idp->di_ctfp, idp->di_type));
+}
+
+/*ARGSUSED*/
+static size_t
+dt_idsize_none(dt_ident_t *idp)
+{
+ return (0);
+}
+
+const dt_idops_t dt_idops_assc = {
+ dt_idcook_assc,
+ dt_iddtor_sign,
+ dt_idsize_none,
+};
+
+const dt_idops_t dt_idops_func = {
+ dt_idcook_func,
+ dt_iddtor_sign,
+ dt_idsize_none,
+};
+
+const dt_idops_t dt_idops_args = {
+ dt_idcook_args,
+ dt_iddtor_none,
+ dt_idsize_none,
+};
+
+const dt_idops_t dt_idops_regs = {
+ dt_idcook_regs,
+ dt_iddtor_free,
+ dt_idsize_none,
+};
+
+const dt_idops_t dt_idops_type = {
+ dt_idcook_type,
+ dt_iddtor_free,
+ dt_idsize_type,
+};
+
+const dt_idops_t dt_idops_thaw = {
+ dt_idcook_thaw,
+ dt_iddtor_free,
+ dt_idsize_type,
+};
+
+const dt_idops_t dt_idops_inline = {
+ dt_idcook_inline,
+ dt_iddtor_inline,
+ dt_idsize_type,
+};
+
+const dt_idops_t dt_idops_probe = {
+ dt_idcook_thaw,
+ dt_iddtor_probe,
+ dt_idsize_none,
+};
+
+static void
+dt_idhash_populate(dt_idhash_t *dhp)
+{
+ const dt_ident_t *idp = dhp->dh_tmpl;
+
+ dhp->dh_tmpl = NULL; /* clear dh_tmpl first to avoid recursion */
+ dt_dprintf("populating %s idhash from %p\n", dhp->dh_name, (void *)idp);
+
+ for (; idp->di_name != NULL; idp++) {
+ if (dt_idhash_insert(dhp, idp->di_name,
+ idp->di_kind, idp->di_flags, idp->di_id, idp->di_attr,
+ idp->di_vers, idp->di_ops ? idp->di_ops : &dt_idops_thaw,
+ idp->di_iarg, 0) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+}
+
+dt_idhash_t *
+dt_idhash_create(const char *name, const dt_ident_t *tmpl,
+ uint_t min, uint_t max)
+{
+ dt_idhash_t *dhp;
+ size_t size;
+
+ assert(min <= max);
+
+ size = sizeof (dt_idhash_t) +
+ sizeof (dt_ident_t *) * (_dtrace_strbuckets - 1);
+
+ if ((dhp = malloc(size)) == NULL)
+ return (NULL);
+
+ bzero(dhp, size);
+ dhp->dh_name = name;
+ dhp->dh_tmpl = tmpl;
+ dhp->dh_nextid = min;
+ dhp->dh_minid = min;
+ dhp->dh_maxid = max;
+ dhp->dh_hashsz = _dtrace_strbuckets;
+
+ return (dhp);
+}
+
+/*
+ * Destroy an entire identifier hash. This must be done using two passes with
+ * an inlined version of dt_ident_destroy() to avoid referencing freed memory.
+ * In the first pass di_dtor() is called for all identifiers; then the second
+ * pass frees the actual dt_ident_t's. These must be done separately because
+ * a di_dtor() may operate on data structures which contain references to other
+ * identifiers inside of this hash itself (e.g. a global inline definition
+ * which contains a parse tree that refers to another global variable).
+ */
+void
+dt_idhash_destroy(dt_idhash_t *dhp)
+{
+ dt_ident_t *idp, *next;
+ ulong_t i;
+
+ for (i = 0; i < dhp->dh_hashsz; i++) {
+ for (idp = dhp->dh_hash[i]; idp != NULL; idp = next) {
+ next = idp->di_next;
+ idp->di_ops->di_dtor(idp);
+ }
+ }
+
+ for (i = 0; i < dhp->dh_hashsz; i++) {
+ for (idp = dhp->dh_hash[i]; idp != NULL; idp = next) {
+ next = idp->di_next;
+ free(idp->di_name);
+ free(idp);
+ }
+ }
+
+ free(dhp);
+}
+
+void
+dt_idhash_update(dt_idhash_t *dhp)
+{
+ uint_t nextid = dhp->dh_minid;
+ dt_ident_t *idp;
+ ulong_t i;
+
+ for (i = 0; i < dhp->dh_hashsz; i++) {
+ for (idp = dhp->dh_hash[i]; idp != NULL; idp = idp->di_next) {
+ /*
+ * Right now we're hard coding which types need to be
+ * reset, but ideally this would be done dynamically.
+ */
+ if (idp->di_kind == DT_IDENT_ARRAY ||
+ idp->di_kind == DT_IDENT_SCALAR ||
+ idp->di_kind == DT_IDENT_AGG)
+ nextid = MAX(nextid, idp->di_id + 1);
+ }
+ }
+
+ dhp->dh_nextid = nextid;
+}
+
+dt_ident_t *
+dt_idhash_lookup(dt_idhash_t *dhp, const char *name)
+{
+ size_t len;
+ ulong_t h = dt_strtab_hash(name, &len) % dhp->dh_hashsz;
+ dt_ident_t *idp;
+
+ if (dhp->dh_tmpl != NULL)
+ dt_idhash_populate(dhp); /* fill hash w/ initial population */
+
+ for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) {
+ if (strcmp(idp->di_name, name) == 0)
+ return (idp);
+ }
+
+ return (NULL);
+}
+
+int
+dt_idhash_nextid(dt_idhash_t *dhp, uint_t *p)
+{
+ if (dhp->dh_nextid >= dhp->dh_maxid)
+ return (-1); /* no more id's are free to allocate */
+
+ *p = dhp->dh_nextid++;
+ return (0);
+}
+
+ulong_t
+dt_idhash_size(const dt_idhash_t *dhp)
+{
+ return (dhp->dh_nelems);
+}
+
+const char *
+dt_idhash_name(const dt_idhash_t *dhp)
+{
+ return (dhp->dh_name);
+}
+
+dt_ident_t *
+dt_idhash_insert(dt_idhash_t *dhp, const char *name, ushort_t kind,
+ ushort_t flags, uint_t id, dtrace_attribute_t attr, uint_t vers,
+ const dt_idops_t *ops, void *iarg, ulong_t gen)
+{
+ dt_ident_t *idp;
+ ulong_t h;
+
+ if (dhp->dh_tmpl != NULL)
+ dt_idhash_populate(dhp); /* fill hash w/ initial population */
+
+ idp = dt_ident_create(name, kind, flags, id,
+ attr, vers, ops, iarg, gen);
+
+ if (idp == NULL)
+ return (NULL);
+
+ h = dt_strtab_hash(name, NULL) % dhp->dh_hashsz;
+ idp->di_next = dhp->dh_hash[h];
+
+ dhp->dh_hash[h] = idp;
+ dhp->dh_nelems++;
+
+ if (dhp->dh_defer != NULL)
+ dhp->dh_defer(dhp, idp);
+
+ return (idp);
+}
+
+void
+dt_idhash_xinsert(dt_idhash_t *dhp, dt_ident_t *idp)
+{
+ ulong_t h;
+
+ if (dhp->dh_tmpl != NULL)
+ dt_idhash_populate(dhp); /* fill hash w/ initial population */
+
+ h = dt_strtab_hash(idp->di_name, NULL) % dhp->dh_hashsz;
+ idp->di_next = dhp->dh_hash[h];
+ idp->di_flags &= ~DT_IDFLG_ORPHAN;
+
+ dhp->dh_hash[h] = idp;
+ dhp->dh_nelems++;
+
+ if (dhp->dh_defer != NULL)
+ dhp->dh_defer(dhp, idp);
+}
+
+void
+dt_idhash_delete(dt_idhash_t *dhp, dt_ident_t *key)
+{
+ size_t len;
+ ulong_t h = dt_strtab_hash(key->di_name, &len) % dhp->dh_hashsz;
+ dt_ident_t **pp = &dhp->dh_hash[h];
+ dt_ident_t *idp;
+
+ for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) {
+ if (idp == key)
+ break;
+ else
+ pp = &idp->di_next;
+ }
+
+ assert(idp == key);
+ *pp = idp->di_next;
+
+ assert(dhp->dh_nelems != 0);
+ dhp->dh_nelems--;
+
+ if (!(idp->di_flags & DT_IDFLG_ORPHAN))
+ dt_ident_destroy(idp);
+}
+
+static int
+dt_idhash_comp(const void *lp, const void *rp)
+{
+ const dt_ident_t *lhs = *((const dt_ident_t **)lp);
+ const dt_ident_t *rhs = *((const dt_ident_t **)rp);
+
+ if (lhs->di_id != rhs->di_id)
+ return ((int)(lhs->di_id - rhs->di_id));
+ else
+ return (strcmp(lhs->di_name, rhs->di_name));
+}
+
+int
+dt_idhash_iter(dt_idhash_t *dhp, dt_idhash_f *func, void *data)
+{
+ dt_ident_t **ids;
+ dt_ident_t *idp;
+ ulong_t i, j, n;
+ int rv;
+
+ if (dhp->dh_tmpl != NULL)
+ dt_idhash_populate(dhp); /* fill hash w/ initial population */
+
+ n = dhp->dh_nelems;
+ ids = alloca(sizeof (dt_ident_t *) * n);
+
+ for (i = 0, j = 0; i < dhp->dh_hashsz; i++) {
+ for (idp = dhp->dh_hash[i]; idp != NULL; idp = idp->di_next)
+ ids[j++] = idp;
+ }
+
+ qsort(ids, dhp->dh_nelems, sizeof (dt_ident_t *), dt_idhash_comp);
+
+ for (i = 0; i < n; i++) {
+ if ((rv = func(dhp, ids[i], data)) != 0)
+ return (rv);
+ }
+
+ return (0);
+}
+
+dt_ident_t *
+dt_idstack_lookup(dt_idstack_t *sp, const char *name)
+{
+ dt_idhash_t *dhp;
+ dt_ident_t *idp;
+
+ for (dhp = dt_list_prev(&sp->dids_list);
+ dhp != NULL; dhp = dt_list_prev(dhp)) {
+ if ((idp = dt_idhash_lookup(dhp, name)) != NULL)
+ return (idp);
+ }
+
+ return (NULL);
+}
+
+void
+dt_idstack_push(dt_idstack_t *sp, dt_idhash_t *dhp)
+{
+ dt_list_append(&sp->dids_list, dhp);
+}
+
+void
+dt_idstack_pop(dt_idstack_t *sp, dt_idhash_t *dhp)
+{
+ assert(dt_list_prev(&sp->dids_list) == dhp);
+ dt_list_delete(&sp->dids_list, dhp);
+}
+
+dt_ident_t *
+dt_ident_create(const char *name, ushort_t kind, ushort_t flags, uint_t id,
+ dtrace_attribute_t attr, uint_t vers,
+ const dt_idops_t *ops, void *iarg, ulong_t gen)
+{
+ dt_ident_t *idp;
+ char *s = NULL;
+
+ if ((name != NULL && (s = strdup(name)) == NULL) ||
+ (idp = malloc(sizeof (dt_ident_t))) == NULL) {
+ free(s);
+ return (NULL);
+ }
+
+ idp->di_name = s;
+ idp->di_kind = kind;
+ idp->di_flags = flags;
+ idp->di_id = id;
+ idp->di_attr = attr;
+ idp->di_vers = vers;
+ idp->di_ops = ops;
+ idp->di_iarg = iarg;
+ idp->di_data = NULL;
+ idp->di_ctfp = NULL;
+ idp->di_type = CTF_ERR;
+ idp->di_next = NULL;
+ idp->di_gen = gen;
+ idp->di_lineno = yylineno;
+
+ return (idp);
+}
+
+/*
+ * Destroy an individual identifier. This code must be kept in sync with the
+ * dt_idhash_destroy() function below, which separates out the call to di_dtor.
+ */
+void
+dt_ident_destroy(dt_ident_t *idp)
+{
+ idp->di_ops->di_dtor(idp);
+ free(idp->di_name);
+ free(idp);
+}
+
+void
+dt_ident_morph(dt_ident_t *idp, ushort_t kind,
+ const dt_idops_t *ops, void *iarg)
+{
+ idp->di_ops->di_dtor(idp);
+ idp->di_kind = kind;
+ idp->di_ops = ops;
+ idp->di_iarg = iarg;
+ idp->di_data = NULL;
+}
+
+dtrace_attribute_t
+dt_ident_cook(dt_node_t *dnp, dt_ident_t *idp, dt_node_t **pargp)
+{
+ dtrace_attribute_t attr;
+ dt_node_t *args, *argp;
+ int argc = 0;
+
+ attr = dt_node_list_cook(pargp, DT_IDFLG_REF);
+ args = pargp ? *pargp : NULL;
+
+ for (argp = args; argp != NULL; argp = argp->dn_list)
+ argc++;
+
+ idp->di_ops->di_cook(dnp, idp, argc, args);
+
+ if (idp->di_flags & DT_IDFLG_USER)
+ dnp->dn_flags |= DT_NF_USERLAND;
+
+ return (dt_attr_min(attr, idp->di_attr));
+}
+
+void
+dt_ident_type_assign(dt_ident_t *idp, ctf_file_t *fp, ctf_id_t type)
+{
+ idp->di_ctfp = fp;
+ idp->di_type = type;
+}
+
+dt_ident_t *
+dt_ident_resolve(dt_ident_t *idp)
+{
+ while (idp->di_flags & DT_IDFLG_INLINE) {
+ const dt_node_t *dnp = ((dt_idnode_t *)idp->di_iarg)->din_root;
+
+ if (dnp == NULL)
+ break; /* can't resolve any further yet */
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_VAR:
+ case DT_NODE_SYM:
+ case DT_NODE_FUNC:
+ case DT_NODE_AGG:
+ case DT_NODE_INLINE:
+ case DT_NODE_PROBE:
+ idp = dnp->dn_ident;
+ continue;
+ }
+
+ if (dt_node_is_dynamic(dnp))
+ idp = dnp->dn_ident;
+ else
+ break;
+ }
+
+ return (idp);
+}
+
+size_t
+dt_ident_size(dt_ident_t *idp)
+{
+ idp = dt_ident_resolve(idp);
+ return (idp->di_ops->di_size(idp));
+}
+
+int
+dt_ident_unref(const dt_ident_t *idp)
+{
+ return (idp->di_gen == yypcb->pcb_hdl->dt_gen &&
+ (idp->di_flags & (DT_IDFLG_REF|DT_IDFLG_MOD|DT_IDFLG_DECL)) == 0);
+}
+
+const char *
+dt_idkind_name(uint_t kind)
+{
+ switch (kind) {
+ case DT_IDENT_ARRAY: return ("associative array");
+ case DT_IDENT_SCALAR: return ("scalar");
+ case DT_IDENT_PTR: return ("pointer");
+ case DT_IDENT_FUNC: return ("function");
+ case DT_IDENT_AGG: return ("aggregation");
+ case DT_IDENT_AGGFUNC: return ("aggregating function");
+ case DT_IDENT_ACTFUNC: return ("tracing function");
+ case DT_IDENT_XLSOU: return ("translated data");
+ case DT_IDENT_XLPTR: return ("pointer to translated data");
+ case DT_IDENT_SYMBOL: return ("external symbol reference");
+ case DT_IDENT_ENUM: return ("enumerator");
+ case DT_IDENT_PRAGAT: return ("#pragma attributes");
+ case DT_IDENT_PRAGBN: return ("#pragma binding");
+ case DT_IDENT_PROBE: return ("probe definition");
+ default: return ("<?>");
+ }
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.h
new file mode 100644
index 000000000000..cc80d6e98b57
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.h
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_IDENT_H
+#define _DT_IDENT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libctf.h>
+#include <dtrace.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dt_list.h>
+
+struct dt_node;
+struct dt_ident;
+struct dt_idhash;
+struct dt_irlist;
+struct dt_regset;
+
+typedef struct dt_idsig {
+ int dis_varargs; /* argument index of start of varargs (or -1) */
+ int dis_optargs; /* argument index of start of optargs (or -1) */
+ int dis_argc; /* number of types in this signature */
+ struct dt_node *dis_args; /* array of nodes representing formal types */
+ uint64_t dis_auxinfo; /* auxiliary signature information, if any */
+} dt_idsig_t;
+
+typedef struct dt_idnode {
+ struct dt_node *din_list; /* allocation list for parse tree nodes */
+ struct dt_node *din_root; /* root of this identifier's parse tree */
+ struct dt_idhash *din_hash; /* identifiers private to this subtree */
+ struct dt_ident **din_argv; /* identifiers in din_hash for arguments */
+ int din_argc; /* length of din_argv[] array */
+} dt_idnode_t;
+
+typedef struct dt_idops {
+ void (*di_cook)(struct dt_node *, struct dt_ident *,
+ int, struct dt_node *);
+ void (*di_dtor)(struct dt_ident *);
+ size_t (*di_size)(struct dt_ident *);
+} dt_idops_t;
+
+typedef struct dt_ident {
+ char *di_name; /* identifier name */
+ ushort_t di_kind; /* identifier kind (see below) */
+ ushort_t di_flags; /* identifier flags (see below) */
+ uint_t di_id; /* variable or subr id (see <sys/dtrace.h>) */
+ dtrace_attribute_t di_attr; /* identifier stability attributes */
+ uint_t di_vers; /* identifier version number (dt_version_t) */
+ const dt_idops_t *di_ops; /* identifier's class-specific ops vector */
+ void *di_iarg; /* initial argument pointer for ops vector */
+ void *di_data; /* private data pointer for ops vector */
+ ctf_file_t *di_ctfp; /* CTF container for the variable data type */
+ ctf_id_t di_type; /* CTF identifier for the variable data type */
+ struct dt_ident *di_next; /* pointer to next ident in hash chain */
+ ulong_t di_gen; /* generation number (pass that created me) */
+ int di_lineno; /* line number that defined this identifier */
+} dt_ident_t;
+
+#define DT_IDENT_ARRAY 0 /* identifier is an array variable */
+#define DT_IDENT_SCALAR 1 /* identifier is a scalar variable */
+#define DT_IDENT_PTR 2 /* identifier is a magic pointer */
+#define DT_IDENT_FUNC 3 /* identifier is a built-in function */
+#define DT_IDENT_AGG 4 /* identifier is an aggregation */
+#define DT_IDENT_AGGFUNC 5 /* identifier is an aggregating function */
+#define DT_IDENT_ACTFUNC 6 /* identifier is an action function */
+#define DT_IDENT_XLSOU 7 /* identifier is a translated struct or union */
+#define DT_IDENT_XLPTR 8 /* identifier is a translated pointer */
+#define DT_IDENT_SYMBOL 9 /* identifier is an external symbol */
+#define DT_IDENT_ENUM 10 /* identifier is an enumerator */
+#define DT_IDENT_PRAGAT 11 /* identifier is #pragma attributes */
+#define DT_IDENT_PRAGBN 12 /* identifier is #pragma binding */
+#define DT_IDENT_PROBE 13 /* identifier is a probe definition */
+
+#define DT_IDFLG_TLS 0x0001 /* variable is thread-local storage */
+#define DT_IDFLG_LOCAL 0x0002 /* variable is local storage */
+#define DT_IDFLG_WRITE 0x0004 /* variable is writable (can be modified) */
+#define DT_IDFLG_INLINE 0x0008 /* variable is an inline definition */
+#define DT_IDFLG_REF 0x0010 /* variable is referenced by this program */
+#define DT_IDFLG_MOD 0x0020 /* variable is modified by this program */
+#define DT_IDFLG_DIFR 0x0040 /* variable is referenced by current DIFO */
+#define DT_IDFLG_DIFW 0x0080 /* variable is modified by current DIFO */
+#define DT_IDFLG_CGREG 0x0100 /* variable is inlined by code generator */
+#define DT_IDFLG_USER 0x0200 /* variable is associated with userland */
+#define DT_IDFLG_PRIM 0x0400 /* variable is associated with primary object */
+#define DT_IDFLG_DECL 0x0800 /* variable is associated with explicit decl */
+#define DT_IDFLG_ORPHAN 0x1000 /* variable is in a dt_node and not dt_idhash */
+
+typedef struct dt_idhash {
+ dt_list_t dh_list; /* list prev/next pointers for dt_idstack */
+ const char *dh_name; /* name of this hash table */
+ void (*dh_defer)(struct dt_idhash *, dt_ident_t *); /* defer callback */
+ const dt_ident_t *dh_tmpl; /* template for initial ident population */
+ uint_t dh_nextid; /* next id to be returned by idhash_nextid() */
+ uint_t dh_minid; /* min id to be returned by idhash_nextid() */
+ uint_t dh_maxid; /* max id to be returned by idhash_nextid() */
+ ulong_t dh_nelems; /* number of identifiers in hash table */
+ ulong_t dh_hashsz; /* number of entries in dh_buckets array */
+ dt_ident_t *dh_hash[1]; /* array of hash table bucket pointers */
+} dt_idhash_t;
+
+typedef struct dt_idstack {
+ dt_list_t dids_list; /* list meta-data for dt_idhash_t stack */
+} dt_idstack_t;
+
+extern const dt_idops_t dt_idops_assc; /* associative array or aggregation */
+extern const dt_idops_t dt_idops_func; /* function call built-in */
+extern const dt_idops_t dt_idops_args; /* args[] built-in */
+extern const dt_idops_t dt_idops_regs; /* regs[]/uregs[] built-in */
+extern const dt_idops_t dt_idops_type; /* predefined type name string */
+extern const dt_idops_t dt_idops_thaw; /* prefrozen type identifier */
+extern const dt_idops_t dt_idops_inline; /* inline variable */
+extern const dt_idops_t dt_idops_probe; /* probe definition */
+
+extern dt_idhash_t *dt_idhash_create(const char *, const dt_ident_t *,
+ uint_t, uint_t);
+extern void dt_idhash_destroy(dt_idhash_t *);
+extern void dt_idhash_update(dt_idhash_t *);
+extern dt_ident_t *dt_idhash_lookup(dt_idhash_t *, const char *);
+extern int dt_idhash_nextid(dt_idhash_t *, uint_t *);
+extern ulong_t dt_idhash_size(const dt_idhash_t *);
+extern const char *dt_idhash_name(const dt_idhash_t *);
+
+extern dt_ident_t *dt_idhash_insert(dt_idhash_t *, const char *, ushort_t,
+ ushort_t, uint_t, dtrace_attribute_t, uint_t,
+ const dt_idops_t *, void *, ulong_t);
+
+extern void dt_idhash_xinsert(dt_idhash_t *, dt_ident_t *);
+extern void dt_idhash_delete(dt_idhash_t *, dt_ident_t *);
+
+typedef int dt_idhash_f(dt_idhash_t *, dt_ident_t *, void *);
+extern int dt_idhash_iter(dt_idhash_t *, dt_idhash_f *, void *);
+
+extern dt_ident_t *dt_idstack_lookup(dt_idstack_t *, const char *);
+extern void dt_idstack_push(dt_idstack_t *, dt_idhash_t *);
+extern void dt_idstack_pop(dt_idstack_t *, dt_idhash_t *);
+
+extern dt_ident_t *dt_ident_create(const char *, ushort_t, ushort_t, uint_t,
+ dtrace_attribute_t, uint_t, const dt_idops_t *, void *, ulong_t);
+extern void dt_ident_destroy(dt_ident_t *);
+extern void dt_ident_morph(dt_ident_t *, ushort_t, const dt_idops_t *, void *);
+extern dtrace_attribute_t dt_ident_cook(struct dt_node *,
+ dt_ident_t *, struct dt_node **);
+
+extern void dt_ident_type_assign(dt_ident_t *, ctf_file_t *, ctf_id_t);
+extern dt_ident_t *dt_ident_resolve(dt_ident_t *);
+extern size_t dt_ident_size(dt_ident_t *);
+extern int dt_ident_unref(const dt_ident_t *);
+
+extern const char *dt_idkind_name(uint_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_IDENT_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
new file mode 100644
index 000000000000..f2c60a2b07d4
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
@@ -0,0 +1,756 @@
+/*
+ * 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 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
+ */
+
+#ifndef _DT_IMPL_H
+#define _DT_IMPL_H
+
+#include <sys/param.h>
+#include <sys/objfs.h>
+#ifndef illumos
+#include <sys/bitmap.h>
+#include <sys/utsname.h>
+#include <sys/ioccom.h>
+#include <sys/time.h>
+#include <string.h>
+#endif
+#include <setjmp.h>
+#include <libctf.h>
+#include <dtrace.h>
+#include <gelf.h>
+#ifdef illumos
+#include <synch.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dt_parser.h>
+#include <dt_regset.h>
+#include <dt_inttab.h>
+#include <dt_strtab.h>
+#include <dt_ident.h>
+#include <dt_list.h>
+#include <dt_decl.h>
+#include <dt_as.h>
+#include <dt_proc.h>
+#include <dt_dof.h>
+#include <dt_pcb.h>
+#include <dt_pq.h>
+
+struct dt_module; /* see below */
+struct dt_pfdict; /* see <dt_printf.h> */
+struct dt_arg; /* see below */
+struct dt_provider; /* see <dt_provider.h> */
+struct dt_xlator; /* see <dt_xlator.h> */
+
+typedef struct dt_intrinsic {
+ const char *din_name; /* string name of the intrinsic type */
+ ctf_encoding_t din_data; /* integer or floating-point CTF encoding */
+ uint_t din_kind; /* CTF type kind to instantiate */
+} dt_intrinsic_t;
+
+typedef struct dt_typedef {
+ const char *dty_src; /* string name of typedef source type */
+ const char *dty_dst; /* string name of typedef destination type */
+} dt_typedef_t;
+
+typedef struct dt_intdesc {
+ const char *did_name; /* string name of the integer type */
+ ctf_file_t *did_ctfp; /* CTF container for this type reference */
+ ctf_id_t did_type; /* CTF type reference for this type */
+ uintmax_t did_limit; /* maximum positive value held by type */
+} dt_intdesc_t;
+
+typedef struct dt_modops {
+ uint_t (*do_syminit)(struct dt_module *);
+ void (*do_symsort)(struct dt_module *);
+ GElf_Sym *(*do_symname)(struct dt_module *,
+ const char *, GElf_Sym *, uint_t *);
+ GElf_Sym *(*do_symaddr)(struct dt_module *,
+ GElf_Addr, GElf_Sym *, uint_t *);
+} dt_modops_t;
+
+typedef struct dt_arg {
+ int da_ndx; /* index of this argument */
+ int da_mapping; /* mapping of argument indices to arguments */
+ ctf_id_t da_type; /* type of argument */
+ ctf_file_t *da_ctfp; /* CTF container for type */
+ dt_ident_t *da_xlator; /* translator, if any */
+ struct dt_arg *da_next; /* next argument */
+} dt_arg_t;
+
+typedef struct dt_sym {
+ uint_t ds_symid; /* id of corresponding symbol */
+ uint_t ds_next; /* index of next element in hash chain */
+} dt_sym_t;
+
+typedef struct dt_module {
+ dt_list_t dm_list; /* list forward/back pointers */
+ char dm_name[DTRACE_MODNAMELEN]; /* string name of module */
+ char dm_file[MAXPATHLEN]; /* file path of module (if any) */
+ struct dt_module *dm_next; /* pointer to next module in hash chain */
+ const dt_modops_t *dm_ops; /* pointer to data model's ops vector */
+ Elf *dm_elf; /* libelf handle for module object */
+ objfs_info_t dm_info; /* object filesystem private info */
+ ctf_sect_t dm_symtab; /* symbol table for module */
+ ctf_sect_t dm_strtab; /* string table for module */
+ ctf_sect_t dm_ctdata; /* CTF data for module */
+ ctf_file_t *dm_ctfp; /* CTF container handle */
+ uint_t *dm_symbuckets; /* symbol table hash buckets (chain indices) */
+ dt_sym_t *dm_symchains; /* symbol table hash chains buffer */
+ void *dm_asmap; /* symbol pointers sorted by value */
+ uint_t dm_symfree; /* index of next free hash element */
+ uint_t dm_nsymbuckets; /* number of elements in bucket array */
+ uint_t dm_nsymelems; /* number of elements in hash table */
+ uint_t dm_asrsv; /* actual reserved size of dm_asmap */
+ uint_t dm_aslen; /* number of entries in dm_asmap */
+ uint_t dm_flags; /* module flags (see below) */
+ int dm_modid; /* modinfo(1M) module identifier */
+ GElf_Addr dm_text_va; /* virtual address of text section */
+ GElf_Xword dm_text_size; /* size in bytes of text section */
+ GElf_Addr dm_data_va; /* virtual address of data section */
+ GElf_Xword dm_data_size; /* size in bytes of data section */
+ GElf_Addr dm_bss_va; /* virtual address of BSS */
+ GElf_Xword dm_bss_size; /* size in bytes of BSS */
+ dt_idhash_t *dm_extern; /* external symbol definitions */
+#ifndef illumos
+ caddr_t dm_reloc_offset; /* Symbol relocation offset. */
+ uintptr_t *dm_sec_offsets;
+#endif
+ pid_t dm_pid; /* pid for this module */
+ uint_t dm_nctflibs; /* number of ctf children libraries */
+ ctf_file_t **dm_libctfp; /* process library ctf pointers */
+ char **dm_libctfn; /* names of process ctf containers */
+} dt_module_t;
+
+#define DT_DM_LOADED 0x1 /* module symbol and type data is loaded */
+#define DT_DM_KERNEL 0x2 /* module is associated with a kernel object */
+#define DT_DM_PRIMARY 0x4 /* module is a krtld primary kernel object */
+
+#ifdef __FreeBSD__
+/*
+ * A representation of a FreeBSD kernel module, used when checking module
+ * dependencies. This differs from dt_module_t, which refers to a KLD in the
+ * case of kernel probes. Since modules can be identified regardless of whether
+ * they've been compiled into the kernel, we use them to identify DTrace
+ * modules.
+ */
+typedef struct dt_kmodule {
+ struct dt_kmodule *dkm_next; /* hash table entry */
+ char *dkm_name; /* string name of module */
+ dt_module_t *dkm_module; /* corresponding KLD module */
+} dt_kmodule_t;
+#endif
+
+typedef struct dt_provmod {
+ char *dp_name; /* name of provider module */
+ struct dt_provmod *dp_next; /* next module */
+} dt_provmod_t;
+
+typedef struct dt_ahashent {
+ struct dt_ahashent *dtahe_prev; /* prev on hash chain */
+ struct dt_ahashent *dtahe_next; /* next on hash chain */
+ struct dt_ahashent *dtahe_prevall; /* prev on list of all */
+ struct dt_ahashent *dtahe_nextall; /* next on list of all */
+ uint64_t dtahe_hashval; /* hash value */
+ size_t dtahe_size; /* size of data */
+ dtrace_aggdata_t dtahe_data; /* data */
+ void (*dtahe_aggregate)(int64_t *, int64_t *, size_t); /* function */
+} dt_ahashent_t;
+
+typedef struct dt_ahash {
+ dt_ahashent_t **dtah_hash; /* hash table */
+ dt_ahashent_t *dtah_all; /* list of all elements */
+ size_t dtah_size; /* size of hash table */
+} dt_ahash_t;
+
+typedef struct dt_aggregate {
+ dtrace_bufdesc_t dtat_buf; /* buf aggregation snapshot */
+ int dtat_flags; /* aggregate flags */
+ processorid_t dtat_ncpus; /* number of CPUs in aggregate */
+ processorid_t *dtat_cpus; /* CPUs in aggregate */
+ processorid_t dtat_ncpu; /* size of dtat_cpus array */
+ processorid_t dtat_maxcpu; /* maximum number of CPUs */
+ dt_ahash_t dtat_hash; /* aggregate hash table */
+} dt_aggregate_t;
+
+typedef struct dt_print_aggdata {
+ dtrace_hdl_t *dtpa_dtp; /* pointer to libdtrace handle */
+ dtrace_aggvarid_t dtpa_id; /* aggregation variable of interest */
+ FILE *dtpa_fp; /* file pointer */
+ int dtpa_allunprint; /* print only unprinted aggregations */
+ int dtpa_agghist; /* print aggregation as histogram */
+ int dtpa_agghisthdr; /* aggregation histogram hdr printed */
+ int dtpa_aggpack; /* pack quantized aggregations */
+} dt_print_aggdata_t;
+
+typedef struct dt_dirpath {
+ dt_list_t dir_list; /* linked-list forward/back pointers */
+ char *dir_path; /* directory pathname */
+} dt_dirpath_t;
+
+typedef struct dt_lib_depend {
+ dt_list_t dtld_deplist; /* linked-list forward/back pointers */
+ char *dtld_library; /* library name */
+ char *dtld_libpath; /* library pathname */
+ uint_t dtld_finish; /* completion time in tsort for lib */
+ uint_t dtld_start; /* starting time in tsort for lib */
+ uint_t dtld_loaded; /* boolean: is this library loaded */
+ dt_list_t dtld_dependencies; /* linked-list of lib dependencies */
+ dt_list_t dtld_dependents; /* linked-list of lib dependents */
+} dt_lib_depend_t;
+
+typedef uint32_t dt_version_t; /* encoded version (see below) */
+
+struct dtrace_hdl {
+ const dtrace_vector_t *dt_vector; /* library vector, if vectored open */
+ void *dt_varg; /* vector argument, if vectored open */
+ dtrace_conf_t dt_conf; /* DTrace driver configuration profile */
+ char dt_errmsg[BUFSIZ]; /* buffer for formatted syntax error msgs */
+ const char *dt_errtag; /* tag used with last call to dt_set_errmsg() */
+ dt_pcb_t *dt_pcb; /* pointer to current parsing control block */
+ ulong_t dt_gen; /* compiler generation number */
+ dt_list_t dt_programs; /* linked list of dtrace_prog_t's */
+ dt_list_t dt_xlators; /* linked list of dt_xlator_t's */
+ struct dt_xlator **dt_xlatormap; /* dt_xlator_t's indexed by dx_id */
+ id_t dt_xlatorid; /* next dt_xlator_t id to assign */
+ dt_ident_t *dt_externs; /* linked list of external symbol identifiers */
+ dt_idhash_t *dt_macros; /* hash table of macro variable identifiers */
+ dt_idhash_t *dt_aggs; /* hash table of aggregation identifiers */
+ dt_idhash_t *dt_globals; /* hash table of global identifiers */
+ dt_idhash_t *dt_tls; /* hash table of thread-local identifiers */
+ dt_list_t dt_modlist; /* linked list of dt_module_t's */
+ dt_module_t **dt_mods; /* hash table of dt_module_t's */
+#ifdef __FreeBSD__
+ dt_kmodule_t **dt_kmods; /* hash table of dt_kmodule_t's */
+#endif
+ uint_t dt_modbuckets; /* number of module hash buckets */
+ uint_t dt_nmods; /* number of modules in hash and list */
+ dt_provmod_t *dt_provmod; /* linked list of provider modules */
+ dt_module_t *dt_exec; /* pointer to executable module */
+ dt_module_t *dt_rtld; /* pointer to run-time linker module */
+ dt_module_t *dt_cdefs; /* pointer to C dynamic type module */
+ dt_module_t *dt_ddefs; /* pointer to D dynamic type module */
+ dt_list_t dt_provlist; /* linked list of dt_provider_t's */
+ struct dt_provider **dt_provs; /* hash table of dt_provider_t's */
+ uint_t dt_provbuckets; /* number of provider hash buckets */
+ uint_t dt_nprovs; /* number of providers in hash and list */
+ dt_proc_hash_t *dt_procs; /* hash table of grabbed process handles */
+ char **dt_proc_env; /* additional environment variables */
+ dt_intdesc_t dt_ints[6]; /* cached integer type descriptions */
+ ctf_id_t dt_type_func; /* cached CTF identifier for function type */
+ ctf_id_t dt_type_fptr; /* cached CTF identifier for function pointer */
+ ctf_id_t dt_type_str; /* cached CTF identifier for string type */
+ ctf_id_t dt_type_dyn; /* cached CTF identifier for <DYN> type */
+ ctf_id_t dt_type_stack; /* cached CTF identifier for stack type */
+ ctf_id_t dt_type_symaddr; /* cached CTF identifier for _symaddr type */
+ ctf_id_t dt_type_usymaddr; /* cached CTF ident. for _usymaddr type */
+ size_t dt_maxprobe; /* max enabled probe ID */
+ dtrace_eprobedesc_t **dt_edesc; /* enabled probe descriptions */
+ dtrace_probedesc_t **dt_pdesc; /* probe descriptions for enabled prbs */
+ size_t dt_maxagg; /* max aggregation ID */
+ dtrace_aggdesc_t **dt_aggdesc; /* aggregation descriptions */
+ int dt_maxformat; /* max format ID */
+ void **dt_formats; /* pointer to format array */
+ int dt_maxstrdata; /* max strdata ID */
+ char **dt_strdata; /* pointer to strdata array */
+ dt_aggregate_t dt_aggregate; /* aggregate */
+ dt_pq_t *dt_bufq; /* CPU-specific data queue */
+ struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */
+ dt_version_t dt_vmax; /* optional ceiling on program API binding */
+ dtrace_attribute_t dt_amin; /* optional floor on program attributes */
+ char *dt_cpp_path; /* pathname of cpp(1) to invoke if needed */
+ char **dt_cpp_argv; /* argument vector for exec'ing cpp(1) */
+ int dt_cpp_argc; /* count of initialized cpp(1) arguments */
+ int dt_cpp_args; /* size of dt_cpp_argv[] array */
+ char *dt_ld_path; /* pathname of ld(1) to invoke if needed */
+#ifdef __FreeBSD__
+ char *dt_objcopy_path; /* pathname of objcopy(1) to invoke if needed */
+#endif
+ dt_list_t dt_lib_path; /* linked-list forming library search path */
+ uint_t dt_lazyload; /* boolean: set via -xlazyload */
+ uint_t dt_droptags; /* boolean: set via -xdroptags */
+ uint_t dt_active; /* boolean: set once tracing is active */
+ uint_t dt_stopped; /* boolean: set once tracing is stopped */
+ processorid_t dt_beganon; /* CPU that executed BEGIN probe (if any) */
+ processorid_t dt_endedon; /* CPU that executed END probe (if any) */
+ uint_t dt_oflags; /* dtrace open-time options (see dtrace.h) */
+ uint_t dt_cflags; /* dtrace compile-time options (see dtrace.h) */
+ uint_t dt_dflags; /* dtrace link-time options (see dtrace.h) */
+ uint_t dt_prcmode; /* dtrace process create mode (see dt_proc.h) */
+ uint_t dt_linkmode; /* dtrace symbol linking mode (see below) */
+ uint_t dt_linktype; /* dtrace link output file type (see below) */
+ uint_t dt_xlatemode; /* dtrace translator linking mode (see below) */
+ uint_t dt_stdcmode; /* dtrace stdc compatibility mode (see below) */
+ uint_t dt_encoding; /* dtrace output encoding (see below) */
+ uint_t dt_treedump; /* dtrace tree debug bitmap (see below) */
+ uint64_t dt_options[DTRACEOPT_MAX]; /* dtrace run-time options */
+ int dt_version; /* library version requested by client */
+ int dt_ctferr; /* error resulting from last CTF failure */
+ int dt_errno; /* error resulting from last failed operation */
+#ifndef illumos
+ const char *dt_errfile;
+ int dt_errline;
+#endif
+ int dt_fd; /* file descriptor for dtrace pseudo-device */
+ int dt_ftfd; /* file descriptor for fasttrap pseudo-device */
+ int dt_fterr; /* saved errno from failed open of dt_ftfd */
+ int dt_cdefs_fd; /* file descriptor for C CTF debugging cache */
+ int dt_ddefs_fd; /* file descriptor for D CTF debugging cache */
+#ifdef illumos
+ int dt_stdout_fd; /* file descriptor for saved stdout */
+#else
+ FILE *dt_freopen_fp; /* file pointer for freopened stdout */
+#endif
+ dtrace_handle_err_f *dt_errhdlr; /* error handler, if any */
+ void *dt_errarg; /* error handler argument */
+ dtrace_prog_t *dt_errprog; /* error handler program, if any */
+ dtrace_handle_drop_f *dt_drophdlr; /* drop handler, if any */
+ void *dt_droparg; /* drop handler argument */
+ dtrace_handle_proc_f *dt_prochdlr; /* proc handler, if any */
+ void *dt_procarg; /* proc handler argument */
+ dtrace_handle_setopt_f *dt_setopthdlr; /* setopt handler, if any */
+ void *dt_setoptarg; /* setopt handler argument */
+ dtrace_status_t dt_status[2]; /* status cache */
+ int dt_statusgen; /* current status generation */
+ hrtime_t dt_laststatus; /* last status */
+ hrtime_t dt_lastswitch; /* last switch of buffer data */
+ hrtime_t dt_lastagg; /* last snapshot of aggregation data */
+ char *dt_sprintf_buf; /* buffer for dtrace_sprintf() */
+ int dt_sprintf_buflen; /* length of dtrace_sprintf() buffer */
+ const char *dt_filetag; /* default filetag for dt_set_errmsg() */
+ char *dt_buffered_buf; /* buffer for buffered output */
+ size_t dt_buffered_offs; /* current offset into buffered buffer */
+ size_t dt_buffered_size; /* size of buffered buffer */
+ dtrace_handle_buffered_f *dt_bufhdlr; /* buffered handler, if any */
+ void *dt_bufarg; /* buffered handler argument */
+ dt_dof_t dt_dof; /* DOF generation buffers (see dt_dof.c) */
+ struct utsname dt_uts; /* uname(2) information for system */
+ dt_list_t dt_lib_dep; /* scratch linked-list of lib dependencies */
+ dt_list_t dt_lib_dep_sorted; /* dependency sorted library list */
+ dtrace_flowkind_t dt_flow; /* flow kind */
+ const char *dt_prefix; /* recommended flow prefix */
+ int dt_indent; /* recommended flow indent */
+ dtrace_epid_t dt_last_epid; /* most recently consumed EPID */
+ uint64_t dt_last_timestamp; /* most recently consumed timestamp */
+ boolean_t dt_has_sugar; /* syntactic sugar used? */
+};
+
+/*
+ * Values for the user arg of the ECB.
+ */
+#define DT_ECB_DEFAULT 0
+#define DT_ECB_ERROR 1
+
+/*
+ * Values for the dt_linkmode property, which is used by the assembler when
+ * processing external symbol references. User can set using -xlink=<mode>.
+ */
+#define DT_LINK_KERNEL 0 /* kernel syms static, user syms dynamic */
+#define DT_LINK_PRIMARY 1 /* primary kernel syms static, others dynamic */
+#define DT_LINK_DYNAMIC 2 /* all symbols dynamic */
+#define DT_LINK_STATIC 3 /* all symbols static */
+
+/*
+ * Values for the dt_linktype property, which is used by dtrace_program_link()
+ * to determine the type of output file that is desired by the client.
+ */
+#define DT_LTYP_ELF 0 /* produce ELF containing DOF */
+#define DT_LTYP_DOF 1 /* produce stand-alone DOF */
+
+/*
+ * Values for the dt_xlatemode property, which is used to determine whether
+ * references to dynamic translators are permitted. Set using -xlate=<mode>.
+ */
+#define DT_XL_STATIC 0 /* require xlators to be statically defined */
+#define DT_XL_DYNAMIC 1 /* produce references to dynamic translators */
+
+/*
+ * Values for the dt_stdcmode property, which is used by the compiler when
+ * running cpp to determine the presence and setting of the __STDC__ macro.
+ */
+#define DT_STDC_XA 0 /* ISO C + K&R C compat w/o ISO: __STDC__=0 */
+#define DT_STDC_XC 1 /* Strict ISO C: __STDC__=1 */
+#define DT_STDC_XS 2 /* K&R C: __STDC__ not defined */
+#define DT_STDC_XT 3 /* ISO C + K&R C compat with ISO: __STDC__=0 */
+
+/*
+ * Values for the dt_encoding property, which is used to force a particular
+ * character encoding (overriding default behavior and/or automatic detection).
+ */
+#define DT_ENCODING_UNSET 0
+#define DT_ENCODING_ASCII 1
+#define DT_ENCODING_UTF8 2
+
+/*
+ * Macro to test whether a given pass bit is set in the dt_treedump bit-vector.
+ * If the bit for pass 'p' is set, the D compiler displays the parse tree for
+ * the program by printing it to stderr at the end of compiler pass 'p'.
+ */
+#define DT_TREEDUMP_PASS(dtp, p) ((dtp)->dt_treedump & (1 << ((p) - 1)))
+
+/*
+ * Macros for accessing the cached CTF container and type ID for the common
+ * types "int", "string", and <DYN>, which we need to use frequently in the D
+ * compiler. The DT_INT_* macro relies upon "int" being at index 0 in the
+ * _dtrace_ints_* tables in dt_open.c; the others are also set up there.
+ */
+#define DT_INT_CTFP(dtp) ((dtp)->dt_ints[0].did_ctfp)
+#define DT_INT_TYPE(dtp) ((dtp)->dt_ints[0].did_type)
+
+#define DT_FUNC_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
+#define DT_FUNC_TYPE(dtp) ((dtp)->dt_type_func)
+
+#define DT_FPTR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
+#define DT_FPTR_TYPE(dtp) ((dtp)->dt_type_fptr)
+
+#define DT_STR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
+#define DT_STR_TYPE(dtp) ((dtp)->dt_type_str)
+
+#define DT_DYN_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
+#define DT_DYN_TYPE(dtp) ((dtp)->dt_type_dyn)
+
+#define DT_STACK_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
+#define DT_STACK_TYPE(dtp) ((dtp)->dt_type_stack)
+
+#define DT_SYMADDR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
+#define DT_SYMADDR_TYPE(dtp) ((dtp)->dt_type_symaddr)
+
+#define DT_USYMADDR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
+#define DT_USYMADDR_TYPE(dtp) ((dtp)->dt_type_usymaddr)
+
+/*
+ * Actions and subroutines are both DT_NODE_FUNC nodes; to avoid confusing
+ * an action for a subroutine (or vice versa), we assure that the DT_ACT_*
+ * constants and the DIF_SUBR_* constants occupy non-overlapping ranges by
+ * starting the DT_ACT_* constants at DIF_SUBR_MAX + 1.
+ */
+#define DT_ACT_BASE DIF_SUBR_MAX + 1
+#define DT_ACT(n) (DT_ACT_BASE + (n))
+
+#define DT_ACT_PRINTF DT_ACT(0) /* printf() action */
+#define DT_ACT_TRACE DT_ACT(1) /* trace() action */
+#define DT_ACT_TRACEMEM DT_ACT(2) /* tracemem() action */
+#define DT_ACT_STACK DT_ACT(3) /* stack() action */
+#define DT_ACT_STOP DT_ACT(4) /* stop() action */
+#define DT_ACT_BREAKPOINT DT_ACT(5) /* breakpoint() action */
+#define DT_ACT_PANIC DT_ACT(6) /* panic() action */
+#define DT_ACT_SPECULATE DT_ACT(7) /* speculate() action */
+#define DT_ACT_COMMIT DT_ACT(8) /* commit() action */
+#define DT_ACT_DISCARD DT_ACT(9) /* discard() action */
+#define DT_ACT_CHILL DT_ACT(10) /* chill() action */
+#define DT_ACT_EXIT DT_ACT(11) /* exit() action */
+#define DT_ACT_USTACK DT_ACT(12) /* ustack() action */
+#define DT_ACT_PRINTA DT_ACT(13) /* printa() action */
+#define DT_ACT_RAISE DT_ACT(14) /* raise() action */
+#define DT_ACT_CLEAR DT_ACT(15) /* clear() action */
+#define DT_ACT_NORMALIZE DT_ACT(16) /* normalize() action */
+#define DT_ACT_DENORMALIZE DT_ACT(17) /* denormalize() action */
+#define DT_ACT_TRUNC DT_ACT(18) /* trunc() action */
+#define DT_ACT_SYSTEM DT_ACT(19) /* system() action */
+#define DT_ACT_JSTACK DT_ACT(20) /* jstack() action */
+#define DT_ACT_FTRUNCATE DT_ACT(21) /* ftruncate() action */
+#define DT_ACT_FREOPEN DT_ACT(22) /* freopen() action */
+#define DT_ACT_SYM DT_ACT(23) /* sym()/func() actions */
+#define DT_ACT_MOD DT_ACT(24) /* mod() action */
+#define DT_ACT_USYM DT_ACT(25) /* usym()/ufunc() actions */
+#define DT_ACT_UMOD DT_ACT(26) /* umod() action */
+#define DT_ACT_UADDR DT_ACT(27) /* uaddr() action */
+#define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */
+#define DT_ACT_PRINT DT_ACT(29) /* print() action */
+#define DT_ACT_PRINTM DT_ACT(30) /* printm() action */
+
+/*
+ * Sentinel to tell freopen() to restore the saved stdout. This must not
+ * be ever valid for opening for write access via freopen(3C), which of
+ * course, "." never is.
+ */
+#define DT_FREOPEN_RESTORE "."
+
+#define EDT_BASE 1000 /* base value for libdtrace errnos */
+
+enum {
+ EDT_VERSION = EDT_BASE, /* client is requesting unsupported version */
+ EDT_VERSINVAL, /* version string is invalid or overflows */
+ EDT_VERSUNDEF, /* requested API version is not defined */
+ EDT_VERSREDUCED, /* requested API version has been reduced */
+ EDT_CTF, /* libctf called failed (dt_ctferr has more) */
+ EDT_COMPILER, /* error in D program compilation */
+ EDT_NOTUPREG, /* tuple register allocation failure */
+ EDT_NOMEM, /* memory allocation failure */
+ EDT_INT2BIG, /* integer limit exceeded */
+ EDT_STR2BIG, /* string limit exceeded */
+ EDT_NOMOD, /* unknown module name */
+ EDT_NOPROV, /* unknown provider name */
+ EDT_NOPROBE, /* unknown probe name */
+ EDT_NOSYM, /* unknown symbol name */
+ EDT_NOSYMADDR, /* no symbol corresponds to address */
+ EDT_NOTYPE, /* unknown type name */
+ EDT_NOVAR, /* unknown variable name */
+ EDT_NOAGG, /* unknown aggregation name */
+ EDT_BADSCOPE, /* improper use of type name scoping operator */
+ EDT_BADSPEC, /* overspecified probe description */
+ EDT_BADSPCV, /* bad macro variable in probe description */
+ EDT_BADID, /* invalid probe identifier */
+ EDT_NOTLOADED, /* module is not currently loaded */
+ EDT_NOCTF, /* module does not contain any CTF data */
+ EDT_DATAMODEL, /* module and program data models don't match */
+ EDT_DIFVERS, /* library has newer DIF version than driver */
+ EDT_BADAGG, /* unrecognized aggregating action */
+ EDT_FIO, /* file i/o error */
+ EDT_DIFINVAL, /* invalid DIF program */
+ EDT_DIFSIZE, /* invalid DIF size */
+ EDT_DIFFAULT, /* failed to copyin DIF program */
+ EDT_BADPROBE, /* bad probe description */
+ EDT_BADPGLOB, /* bad probe description globbing pattern */
+ EDT_NOSCOPE, /* declaration scope stack underflow */
+ EDT_NODECL, /* declaration stack underflow */
+ EDT_DMISMATCH, /* record list does not match statement */
+ EDT_DOFFSET, /* record data offset error */
+ EDT_DALIGN, /* record data alignment error */
+ EDT_BADOPTNAME, /* invalid dtrace_setopt option name */
+ EDT_BADOPTVAL, /* invalid dtrace_setopt option value */
+ EDT_BADOPTCTX, /* invalid dtrace_setopt option context */
+ EDT_CPPFORK, /* failed to fork preprocessor */
+ EDT_CPPEXEC, /* failed to exec preprocessor */
+ EDT_CPPENT, /* preprocessor not found */
+ EDT_CPPERR, /* unknown preprocessor error */
+ EDT_SYMOFLOW, /* external symbol table overflow */
+ EDT_ACTIVE, /* operation illegal when tracing is active */
+ EDT_DESTRUCTIVE, /* destructive actions not allowed */
+ EDT_NOANON, /* no anonymous tracing state */
+ EDT_ISANON, /* can't claim anon state and enable probes */
+ EDT_ENDTOOBIG, /* END enablings exceed size of prncpl buffer */
+ EDT_NOCONV, /* failed to load type for printf conversion */
+ EDT_BADCONV, /* incomplete printf conversion */
+ EDT_BADERROR, /* invalid library ERROR action */
+ EDT_ERRABORT, /* abort due to error */
+ EDT_DROPABORT, /* abort due to drop */
+ EDT_DIRABORT, /* abort explicitly directed */
+ EDT_BADRVAL, /* invalid return value from callback */
+ EDT_BADNORMAL, /* invalid normalization */
+ EDT_BUFTOOSMALL, /* enabling exceeds size of buffer */
+ EDT_BADTRUNC, /* invalid truncation */
+ EDT_BUSY, /* device busy (active kernel debugger) */
+ EDT_ACCESS, /* insufficient privileges to use DTrace */
+ EDT_NOENT, /* dtrace device not available */
+ EDT_BRICKED, /* abort due to systemic unresponsiveness */
+ EDT_HARDWIRE, /* failed to load hard-wired definitions */
+ EDT_ELFVERSION, /* libelf is out-of-date w.r.t libdtrace */
+ EDT_NOBUFFERED, /* attempt to buffer output without handler */
+ EDT_UNSTABLE, /* description matched unstable set of probes */
+ EDT_BADSETOPT, /* invalid setopt library action */
+ EDT_BADSTACKPC, /* invalid stack program counter size */
+ EDT_BADAGGVAR, /* invalid aggregation variable identifier */
+ EDT_OVERSION, /* client is requesting deprecated version */
+ EDT_ENABLING_ERR, /* failed to enable probe */
+ EDT_NOPROBES, /* no probes sites for declared provider */
+ EDT_CANTLOAD /* failed to load a module */
+};
+
+/*
+ * Interfaces for parsing and comparing DTrace attribute tuples, which describe
+ * stability and architectural binding information. The dtrace_attribute_t
+ * structure and associated constant definitions are found in <sys/dtrace.h>.
+ */
+extern dtrace_attribute_t dt_attr_min(dtrace_attribute_t, dtrace_attribute_t);
+extern dtrace_attribute_t dt_attr_max(dtrace_attribute_t, dtrace_attribute_t);
+extern char *dt_attr_str(dtrace_attribute_t, char *, size_t);
+extern int dt_attr_cmp(dtrace_attribute_t, dtrace_attribute_t);
+
+/*
+ * Interfaces for parsing and handling DTrace version strings. Version binding
+ * is a feature of the D compiler that is handled completely independently of
+ * the DTrace kernel infrastructure, so the definitions are here in libdtrace.
+ * Version strings are compiled into an encoded uint32_t which can be compared
+ * using C comparison operators. Version definitions are found in dt_open.c.
+ */
+#define DT_VERSION_STRMAX 16 /* enough for "255.4095.4095\0" */
+#define DT_VERSION_MAJMAX 0xFF /* maximum major version number */
+#define DT_VERSION_MINMAX 0xFFF /* maximum minor version number */
+#define DT_VERSION_MICMAX 0xFFF /* maximum micro version number */
+
+#define DT_VERSION_NUMBER(M, m, u) \
+ ((((M) & 0xFF) << 24) | (((m) & 0xFFF) << 12) | ((u) & 0xFFF))
+
+#define DT_VERSION_MAJOR(v) (((v) & 0xFF000000) >> 24)
+#define DT_VERSION_MINOR(v) (((v) & 0x00FFF000) >> 12)
+#define DT_VERSION_MICRO(v) ((v) & 0x00000FFF)
+
+extern char *dt_version_num2str(dt_version_t, char *, size_t);
+extern int dt_version_str2num(const char *, dt_version_t *);
+extern int dt_version_defined(dt_version_t);
+
+/*
+ * Miscellaneous internal libdtrace interfaces. The definitions below are for
+ * libdtrace routines that do not yet merit their own separate header file.
+ */
+extern char *dt_cpp_add_arg(dtrace_hdl_t *, const char *);
+extern char *dt_cpp_pop_arg(dtrace_hdl_t *);
+
+#ifdef illumos
+extern int dt_set_errno(dtrace_hdl_t *, int);
+#else
+int _dt_set_errno(dtrace_hdl_t *, int, const char *, int);
+void dt_get_errloc(dtrace_hdl_t *, const char **, int *);
+#define dt_set_errno(_a,_b) _dt_set_errno(_a,_b,__FILE__,__LINE__)
+#endif
+extern void dt_set_errmsg(dtrace_hdl_t *, const char *, const char *,
+ const char *, int, const char *, va_list);
+
+#ifdef illumos
+extern int dt_ioctl(dtrace_hdl_t *, int, void *);
+#else
+extern int dt_ioctl(dtrace_hdl_t *, u_long, void *);
+#endif
+extern int dt_status(dtrace_hdl_t *, processorid_t);
+extern long dt_sysconf(dtrace_hdl_t *, int);
+extern ssize_t dt_write(dtrace_hdl_t *, int, const void *, size_t);
+extern int dt_printf(dtrace_hdl_t *, FILE *, const char *, ...);
+
+extern void *dt_zalloc(dtrace_hdl_t *, size_t);
+extern void *dt_alloc(dtrace_hdl_t *, size_t);
+extern void dt_free(dtrace_hdl_t *, void *);
+extern void dt_difo_free(dtrace_hdl_t *, dtrace_difo_t *);
+
+extern int dt_gmatch(const char *, const char *);
+extern char *dt_basename(char *);
+
+extern ulong_t dt_popc(ulong_t);
+extern ulong_t dt_popcb(const ulong_t *, ulong_t);
+
+extern int dt_buffered_enable(dtrace_hdl_t *);
+extern int dt_buffered_flush(dtrace_hdl_t *, dtrace_probedata_t *,
+ const dtrace_recdesc_t *, const dtrace_aggdata_t *, uint32_t flags);
+extern void dt_buffered_disable(dtrace_hdl_t *);
+extern void dt_buffered_destroy(dtrace_hdl_t *);
+
+extern uint64_t dt_stddev(uint64_t *, uint64_t);
+
+extern int dt_rw_read_held(pthread_rwlock_t *);
+extern int dt_rw_write_held(pthread_rwlock_t *);
+extern int dt_mutex_held(pthread_mutex_t *);
+extern int dt_options_load(dtrace_hdl_t *);
+
+#define DT_RW_READ_HELD(x) dt_rw_read_held(x)
+#define DT_RW_WRITE_HELD(x) dt_rw_write_held(x)
+#define DT_RW_LOCK_HELD(x) (DT_RW_READ_HELD(x) || DT_RW_WRITE_HELD(x))
+#define DT_MUTEX_HELD(x) dt_mutex_held(x)
+
+extern void dt_dprintf(const char *, ...);
+
+extern void dt_setcontext(dtrace_hdl_t *, dtrace_probedesc_t *);
+extern void dt_endcontext(dtrace_hdl_t *);
+
+extern void dt_pragma(dt_node_t *);
+extern int dt_reduce(dtrace_hdl_t *, dt_version_t);
+extern void dt_cg(dt_pcb_t *, dt_node_t *);
+extern dtrace_difo_t *dt_as(dt_pcb_t *);
+extern void dt_dis(const dtrace_difo_t *, FILE *);
+
+extern int dt_aggregate_go(dtrace_hdl_t *);
+extern int dt_aggregate_init(dtrace_hdl_t *);
+extern void dt_aggregate_destroy(dtrace_hdl_t *);
+
+extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t,
+ dtrace_eprobedesc_t **, dtrace_probedesc_t **);
+extern void dt_epid_destroy(dtrace_hdl_t *);
+extern int dt_aggid_lookup(dtrace_hdl_t *, dtrace_aggid_t, dtrace_aggdesc_t **);
+extern void dt_aggid_destroy(dtrace_hdl_t *);
+
+extern void *dt_format_lookup(dtrace_hdl_t *, int);
+extern void dt_format_destroy(dtrace_hdl_t *);
+
+extern const char *dt_strdata_lookup(dtrace_hdl_t *, int);
+extern void dt_strdata_destroy(dtrace_hdl_t *);
+
+extern int dt_print_quantize(dtrace_hdl_t *, FILE *,
+ const void *, size_t, uint64_t);
+extern int dt_print_lquantize(dtrace_hdl_t *, FILE *,
+ const void *, size_t, uint64_t);
+extern int dt_print_llquantize(dtrace_hdl_t *, FILE *,
+ const void *, size_t, uint64_t);
+extern int dt_print_agg(const dtrace_aggdata_t *, void *);
+
+extern int dt_handle(dtrace_hdl_t *, dtrace_probedata_t *);
+extern int dt_handle_liberr(dtrace_hdl_t *,
+ const dtrace_probedata_t *, const char *);
+extern int dt_handle_cpudrop(dtrace_hdl_t *, processorid_t,
+ dtrace_dropkind_t, uint64_t);
+extern int dt_handle_status(dtrace_hdl_t *,
+ dtrace_status_t *, dtrace_status_t *);
+extern int dt_handle_setopt(dtrace_hdl_t *, dtrace_setoptdata_t *);
+
+extern int dt_lib_depend_add(dtrace_hdl_t *, dt_list_t *, const char *);
+extern dt_lib_depend_t *dt_lib_depend_lookup(dt_list_t *, const char *);
+
+extern dt_pcb_t *yypcb; /* pointer to current parser control block */
+extern char yyintprefix; /* int token prefix for macros (+/-) */
+extern char yyintsuffix[4]; /* int token suffix ([uUlL]*) */
+extern int yyintdecimal; /* int token is decimal (1) or octal/hex (0) */
+extern char yytext[]; /* lex input buffer */
+extern int yylineno; /* lex line number */
+extern int yydebug; /* lex debugging */
+extern dt_node_t *yypragma; /* lex token list for control lines */
+
+extern const dtrace_attribute_t _dtrace_maxattr; /* maximum attributes */
+extern const dtrace_attribute_t _dtrace_defattr; /* default attributes */
+extern const dtrace_attribute_t _dtrace_symattr; /* symbol ref attributes */
+extern const dtrace_attribute_t _dtrace_typattr; /* type ref attributes */
+extern const dtrace_attribute_t _dtrace_prvattr; /* provider attributes */
+extern const dtrace_pattr_t _dtrace_prvdesc; /* provider attribute bundle */
+
+extern const dt_version_t _dtrace_versions[]; /* array of valid versions */
+extern const char *const _dtrace_version; /* current version string */
+
+extern int _dtrace_strbuckets; /* number of hash buckets for strings */
+extern int _dtrace_intbuckets; /* number of hash buckets for ints */
+extern uint_t _dtrace_stkindent; /* default indent for stack/ustack */
+extern uint_t _dtrace_pidbuckets; /* number of hash buckets for pids */
+extern uint_t _dtrace_pidlrulim; /* number of proc handles to cache */
+extern int _dtrace_debug; /* debugging messages enabled */
+extern size_t _dtrace_bufsize; /* default dt_buf_create() size */
+extern int _dtrace_argmax; /* default maximum probe arguments */
+
+extern const char *_dtrace_libdir; /* default library directory */
+extern const char *_dtrace_moddir; /* default kernel module directory */
+
+#ifdef __FreeBSD__
+extern int gmatch(const char *, const char *);
+extern int yylex(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_IMPL_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.c
new file mode 100644
index 000000000000..a6ac589ff0dd
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.c
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <assert.h>
+
+#include <dt_inttab.h>
+#include <dt_impl.h>
+
+dt_inttab_t *
+dt_inttab_create(dtrace_hdl_t *dtp)
+{
+ uint_t len = _dtrace_intbuckets;
+ dt_inttab_t *ip;
+
+ assert((len & (len - 1)) == 0);
+
+ if ((ip = dt_zalloc(dtp, sizeof (dt_inttab_t))) == NULL ||
+ (ip->int_hash = dt_zalloc(dtp, sizeof (void *) * len)) == NULL) {
+ dt_free(dtp, ip);
+ return (NULL);
+ }
+
+ ip->int_hdl = dtp;
+ ip->int_hashlen = len;
+
+ return (ip);
+}
+
+void
+dt_inttab_destroy(dt_inttab_t *ip)
+{
+ dt_inthash_t *hp, *np;
+
+ for (hp = ip->int_head; hp != NULL; hp = np) {
+ np = hp->inh_next;
+ dt_free(ip->int_hdl, hp);
+ }
+
+ dt_free(ip->int_hdl, ip->int_hash);
+ dt_free(ip->int_hdl, ip);
+}
+
+int
+dt_inttab_insert(dt_inttab_t *ip, uint64_t value, uint_t flags)
+{
+ uint_t h = value & (ip->int_hashlen - 1);
+ dt_inthash_t *hp;
+
+ if (flags & DT_INT_SHARED) {
+ for (hp = ip->int_hash[h]; hp != NULL; hp = hp->inh_hash) {
+ if (hp->inh_value == value && hp->inh_flags == flags)
+ return (hp->inh_index);
+ }
+ }
+
+ if ((hp = dt_alloc(ip->int_hdl, sizeof (dt_inthash_t))) == NULL)
+ return (-1);
+
+ hp->inh_hash = ip->int_hash[h];
+ hp->inh_next = NULL;
+ hp->inh_value = value;
+ hp->inh_index = ip->int_index++;
+ hp->inh_flags = flags;
+
+ ip->int_hash[h] = hp;
+ ip->int_nelems++;
+
+ if (ip->int_head == NULL)
+ ip->int_head = hp;
+ else
+ ip->int_tail->inh_next = hp;
+
+ ip->int_tail = hp;
+ return (hp->inh_index);
+}
+
+uint_t
+dt_inttab_size(const dt_inttab_t *ip)
+{
+ return (ip->int_nelems);
+}
+
+void
+dt_inttab_write(const dt_inttab_t *ip, uint64_t *dst)
+{
+ const dt_inthash_t *hp;
+
+ for (hp = ip->int_head; hp != NULL; hp = hp->inh_next)
+ *dst++ = hp->inh_value;
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.h
new file mode 100644
index 000000000000..c1e86e3eca4e
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_INTTAB_H
+#define _DT_INTTAB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <dtrace.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct dt_inthash {
+ struct dt_inthash *inh_hash; /* next dt_inthash in hash chain */
+ struct dt_inthash *inh_next; /* next dt_inthash in output table */
+ uint64_t inh_value; /* value associated with this element */
+ uint_t inh_index; /* index associated with this element */
+ uint_t inh_flags; /* flags (see below) */
+} dt_inthash_t;
+
+typedef struct dt_inttab {
+ dtrace_hdl_t *int_hdl; /* pointer back to library handle */
+ dt_inthash_t **int_hash; /* array of hash buckets */
+ uint_t int_hashlen; /* size of hash bucket array */
+ uint_t int_nelems; /* number of elements hashed */
+ dt_inthash_t *int_head; /* head of table in index order */
+ dt_inthash_t *int_tail; /* tail of table in index order */
+ uint_t int_index; /* next index to hand out */
+} dt_inttab_t;
+
+#define DT_INT_PRIVATE 0 /* only a single ref for this entry */
+#define DT_INT_SHARED 1 /* multiple refs can share entry */
+
+extern dt_inttab_t *dt_inttab_create(dtrace_hdl_t *);
+extern void dt_inttab_destroy(dt_inttab_t *);
+extern int dt_inttab_insert(dt_inttab_t *, uint64_t, uint_t);
+extern uint_t dt_inttab_size(const dt_inttab_t *);
+extern void dt_inttab_write(const dt_inttab_t *, uint64_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_INTTAB_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l
new file mode 100644
index 000000000000..192e1e20d82c
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l
@@ -0,0 +1,884 @@
+%{
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <dt_impl.h>
+#include <dt_grammar.h>
+#include <dt_parser.h>
+#include <dt_string.h>
+
+/*
+ * We need to undefine lex's input and unput macros so that references to these
+ * call the functions provided at the end of this source file.
+ */
+#ifdef illumos
+#undef input
+#undef unput
+#else
+/*
+ * Define YY_INPUT for flex since input() can't be re-defined.
+ */
+#define YY_INPUT(buf,result,max_size) \
+ if (yypcb->pcb_fileptr != NULL) { \
+ if (((result = fread(buf, 1, max_size, yypcb->pcb_fileptr)) == 0) \
+ && ferror(yypcb->pcb_fileptr)) \
+ longjmp(yypcb->pcb_jmpbuf, EDT_FIO); \
+ } else { \
+ int n; \
+ for (n = 0; n < max_size && \
+ yypcb->pcb_strptr < yypcb->pcb_string + yypcb->pcb_strlen; n++) \
+ buf[n] = *yypcb->pcb_strptr++; \
+ result = n; \
+ }
+/*
+ * Do not EOF let tokens to be put back. This does not work with flex.
+ * On the other hand, leaving current buffer in same state it was when
+ * last EOF was received guarantees that input() will keep returning EOF
+ * for all subsequent invocations, which is the effect desired.
+ */
+#undef unput
+#define unput(c) \
+ do { \
+ int _c = c; \
+ if (_c != EOF) \
+ yyunput(_c, yytext_ptr); \
+ } while(0)
+#endif
+
+static int id_or_type(const char *);
+#ifdef illumos
+static int input(void);
+static void unput(int);
+#endif
+
+/*
+ * We first define a set of labeled states for use in the D lexer and then a
+ * set of regular expressions to simplify things below. The lexer states are:
+ *
+ * S0 - D program clause and expression lexing
+ * S1 - D comments (i.e. skip everything until end of comment)
+ * S2 - D program outer scope (probe specifiers and declarations)
+ * S3 - D control line parsing (i.e. after ^# is seen but before \n)
+ * S4 - D control line scan (locate control directives only and invoke S3)
+ */
+%}
+
+%e 1500 /* maximum nodes */
+%p 4900 /* maximum positions */
+%n 600 /* maximum states */
+%a 3000 /* maximum transitions */
+
+%s S0 S1 S2 S3 S4
+
+RGX_AGG "@"[a-zA-Z_][0-9a-zA-Z_]*
+RGX_PSPEC [-$:a-zA-Z_.?*\\\[\]!][-$:0-9a-zA-Z_.`?*\\\[\]!]*
+RGX_ALTIDENT [a-zA-Z_][0-9a-zA-Z_]*
+RGX_LMID LM[0-9a-fA-F]+`
+RGX_MOD_IDENT [a-zA-Z_`][0-9a-z.A-Z_`]*`
+RGX_IDENT [a-zA-Z_`][0-9a-zA-Z_`]*
+RGX_INT ([0-9]+|0[xX][0-9A-Fa-f]+)[uU]?[lL]?[lL]?
+RGX_FP ([0-9]+("."?)[0-9]*|"."[0-9]+)((e|E)("+"|-)?[0-9]+)?[fFlL]?
+RGX_WS [\f\n\r\t\v ]
+RGX_STR ([^"\\\n]|\\[^"\n]|\\\")*
+RGX_CHR ([^'\\\n]|\\[^'\n]|\\')*
+RGX_INTERP ^[\f\t\v ]*#!.*
+RGX_CTL ^[\f\t\v ]*#
+
+%%
+
+%{
+
+/*
+ * We insert a special prologue into yylex() itself: if the pcb contains a
+ * context token, we return that prior to running the normal lexer. This
+ * allows libdtrace to force yacc into one of our three parsing contexts: D
+ * expression (DT_CTX_DEXPR), D program (DT_CTX_DPROG) or D type (DT_CTX_DTYPE).
+ * Once the token is returned, we clear it so this only happens once.
+ */
+if (yypcb->pcb_token != 0) {
+ int tok = yypcb->pcb_token;
+ yypcb->pcb_token = 0;
+ return (tok);
+}
+
+%}
+
+<S0>auto return (DT_KEY_AUTO);
+<S0>break return (DT_KEY_BREAK);
+<S0>case return (DT_KEY_CASE);
+<S0>char return (DT_KEY_CHAR);
+<S0>const return (DT_KEY_CONST);
+<S0>continue return (DT_KEY_CONTINUE);
+<S0>counter return (DT_KEY_COUNTER);
+<S0>default return (DT_KEY_DEFAULT);
+<S0>do return (DT_KEY_DO);
+<S0>double return (DT_KEY_DOUBLE);
+<S0>else return (DT_KEY_ELSE);
+<S0>enum return (DT_KEY_ENUM);
+<S0>extern return (DT_KEY_EXTERN);
+<S0>float return (DT_KEY_FLOAT);
+<S0>for return (DT_KEY_FOR);
+<S0>goto return (DT_KEY_GOTO);
+<S0>if return (DT_KEY_IF);
+<S0>import return (DT_KEY_IMPORT);
+<S0>inline return (DT_KEY_INLINE);
+<S0>int return (DT_KEY_INT);
+<S0>long return (DT_KEY_LONG);
+<S0>offsetof return (DT_TOK_OFFSETOF);
+<S0>probe return (DT_KEY_PROBE);
+<S0>provider return (DT_KEY_PROVIDER);
+<S0>register return (DT_KEY_REGISTER);
+<S0>restrict return (DT_KEY_RESTRICT);
+<S0>return return (DT_KEY_RETURN);
+<S0>self return (DT_KEY_SELF);
+<S0>short return (DT_KEY_SHORT);
+<S0>signed return (DT_KEY_SIGNED);
+<S0>sizeof return (DT_TOK_SIZEOF);
+<S0>static return (DT_KEY_STATIC);
+<S0>string return (DT_KEY_STRING);
+<S0>stringof return (DT_TOK_STRINGOF);
+<S0>struct return (DT_KEY_STRUCT);
+<S0>switch return (DT_KEY_SWITCH);
+<S0>this return (DT_KEY_THIS);
+<S0>translator return (DT_KEY_XLATOR);
+<S0>typedef return (DT_KEY_TYPEDEF);
+<S0>union return (DT_KEY_UNION);
+<S0>unsigned return (DT_KEY_UNSIGNED);
+<S0>userland return (DT_KEY_USERLAND);
+<S0>void return (DT_KEY_VOID);
+<S0>volatile return (DT_KEY_VOLATILE);
+<S0>while return (DT_KEY_WHILE);
+<S0>xlate return (DT_TOK_XLATE);
+
+<S2>auto { yybegin(YYS_EXPR); return (DT_KEY_AUTO); }
+<S2>char { yybegin(YYS_EXPR); return (DT_KEY_CHAR); }
+<S2>const { yybegin(YYS_EXPR); return (DT_KEY_CONST); }
+<S2>counter { yybegin(YYS_DEFINE); return (DT_KEY_COUNTER); }
+<S2>double { yybegin(YYS_EXPR); return (DT_KEY_DOUBLE); }
+<S2>enum { yybegin(YYS_EXPR); return (DT_KEY_ENUM); }
+<S2>extern { yybegin(YYS_EXPR); return (DT_KEY_EXTERN); }
+<S2>float { yybegin(YYS_EXPR); return (DT_KEY_FLOAT); }
+<S2>import { yybegin(YYS_EXPR); return (DT_KEY_IMPORT); }
+<S2>inline { yybegin(YYS_DEFINE); return (DT_KEY_INLINE); }
+<S2>int { yybegin(YYS_EXPR); return (DT_KEY_INT); }
+<S2>long { yybegin(YYS_EXPR); return (DT_KEY_LONG); }
+<S2>provider { yybegin(YYS_DEFINE); return (DT_KEY_PROVIDER); }
+<S2>register { yybegin(YYS_EXPR); return (DT_KEY_REGISTER); }
+<S2>restrict { yybegin(YYS_EXPR); return (DT_KEY_RESTRICT); }
+<S2>self { yybegin(YYS_EXPR); return (DT_KEY_SELF); }
+<S2>short { yybegin(YYS_EXPR); return (DT_KEY_SHORT); }
+<S2>signed { yybegin(YYS_EXPR); return (DT_KEY_SIGNED); }
+<S2>static { yybegin(YYS_EXPR); return (DT_KEY_STATIC); }
+<S2>string { yybegin(YYS_EXPR); return (DT_KEY_STRING); }
+<S2>struct { yybegin(YYS_EXPR); return (DT_KEY_STRUCT); }
+<S2>this { yybegin(YYS_EXPR); return (DT_KEY_THIS); }
+<S2>translator { yybegin(YYS_DEFINE); return (DT_KEY_XLATOR); }
+<S2>typedef { yybegin(YYS_EXPR); return (DT_KEY_TYPEDEF); }
+<S2>union { yybegin(YYS_EXPR); return (DT_KEY_UNION); }
+<S2>unsigned { yybegin(YYS_EXPR); return (DT_KEY_UNSIGNED); }
+<S2>void { yybegin(YYS_EXPR); return (DT_KEY_VOID); }
+<S2>volatile { yybegin(YYS_EXPR); return (DT_KEY_VOLATILE); }
+
+<S0>"$$"[0-9]+ {
+ int i = atoi(yytext + 2);
+ char *v = "";
+
+ /*
+ * A macro argument reference substitutes the text of
+ * an argument in place of the current token. When we
+ * see $$<d> we fetch the saved string from pcb_sargv
+ * (or use the default argument if the option has been
+ * set and the argument hasn't been specified) and
+ * return a token corresponding to this string.
+ */
+ if (i < 0 || (i >= yypcb->pcb_sargc &&
+ !(yypcb->pcb_cflags & DTRACE_C_DEFARG))) {
+ xyerror(D_MACRO_UNDEF, "macro argument %s is "
+ "not defined\n", yytext);
+ }
+
+ if (i < yypcb->pcb_sargc) {
+ v = yypcb->pcb_sargv[i]; /* get val from pcb */
+ yypcb->pcb_sflagv[i] |= DT_IDFLG_REF;
+ }
+
+ if ((yylval.l_str = strdup(v)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ (void) stresc2chr(yylval.l_str);
+ return (DT_TOK_STRING);
+ }
+
+<S0>"$"[0-9]+ {
+ int i = atoi(yytext + 1);
+ char *p, *v = "0";
+
+ /*
+ * A macro argument reference substitutes the text of
+ * one identifier or integer pattern for another. When
+ * we see $<d> we fetch the saved string from pcb_sargv
+ * (or use the default argument if the option has been
+ * set and the argument hasn't been specified) and
+ * return a token corresponding to this string.
+ */
+ if (i < 0 || (i >= yypcb->pcb_sargc &&
+ !(yypcb->pcb_cflags & DTRACE_C_DEFARG))) {
+ xyerror(D_MACRO_UNDEF, "macro argument %s is "
+ "not defined\n", yytext);
+ }
+
+ if (i < yypcb->pcb_sargc) {
+ v = yypcb->pcb_sargv[i]; /* get val from pcb */
+ yypcb->pcb_sflagv[i] |= DT_IDFLG_REF;
+ }
+
+ /*
+ * If the macro text is not a valid integer or ident,
+ * then we treat it as a string. The string may be
+ * optionally enclosed in quotes, which we strip.
+ */
+ if (strbadidnum(v)) {
+ size_t len = strlen(v);
+
+ if (len != 1 && *v == '"' && v[len - 1] == '"')
+ yylval.l_str = strndup(v + 1, len - 2);
+ else
+ yylval.l_str = strndup(v, len);
+
+ if (yylval.l_str == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ (void) stresc2chr(yylval.l_str);
+ return (DT_TOK_STRING);
+ }
+
+ /*
+ * If the macro text is not a string an begins with a
+ * digit or a +/- sign, process it as an integer token.
+ */
+ if (isdigit(v[0]) || v[0] == '-' || v[0] == '+') {
+ if (isdigit(v[0]))
+ yyintprefix = 0;
+ else
+ yyintprefix = *v++;
+
+ errno = 0;
+ yylval.l_int = strtoull(v, &p, 0);
+ (void) strncpy(yyintsuffix, p,
+ sizeof (yyintsuffix));
+ yyintdecimal = *v != '0';
+
+ if (errno == ERANGE) {
+ xyerror(D_MACRO_OFLOW, "macro argument"
+ " %s constant %s results in integer"
+ " overflow\n", yytext, v);
+ }
+
+ return (DT_TOK_INT);
+ }
+
+ return (id_or_type(v));
+ }
+
+<S0>"$$"{RGX_IDENT} {
+ dt_ident_t *idp = dt_idhash_lookup(
+ yypcb->pcb_hdl->dt_macros, yytext + 2);
+
+ char s[16]; /* enough for UINT_MAX + \0 */
+
+ if (idp == NULL) {
+ xyerror(D_MACRO_UNDEF, "macro variable %s "
+ "is not defined\n", yytext);
+ }
+
+ /*
+ * For the moment, all current macro variables are of
+ * type id_t (refer to dtrace_update() for details).
+ */
+ (void) snprintf(s, sizeof (s), "%u", idp->di_id);
+ if ((yylval.l_str = strdup(s)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ return (DT_TOK_STRING);
+ }
+
+<S0>"$"{RGX_IDENT} {
+ dt_ident_t *idp = dt_idhash_lookup(
+ yypcb->pcb_hdl->dt_macros, yytext + 1);
+
+ if (idp == NULL) {
+ xyerror(D_MACRO_UNDEF, "macro variable %s "
+ "is not defined\n", yytext);
+ }
+
+ /*
+ * For the moment, all current macro variables are of
+ * type id_t (refer to dtrace_update() for details).
+ */
+ yylval.l_int = (intmax_t)(int)idp->di_id;
+ yyintprefix = 0;
+ yyintsuffix[0] = '\0';
+ yyintdecimal = 1;
+
+ return (DT_TOK_INT);
+ }
+
+<S0>{RGX_IDENT} |
+<S0>{RGX_MOD_IDENT}{RGX_IDENT} |
+<S0>{RGX_MOD_IDENT} {
+ return (id_or_type(yytext));
+ }
+
+<S0>{RGX_AGG} {
+ if ((yylval.l_str = strdup(yytext)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ return (DT_TOK_AGG);
+ }
+
+<S0>"@" {
+ if ((yylval.l_str = strdup("@_")) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ return (DT_TOK_AGG);
+ }
+
+<S0>{RGX_INT} |
+<S2>{RGX_INT} |
+<S3>{RGX_INT} {
+ char *p;
+
+ errno = 0;
+ yylval.l_int = strtoull(yytext, &p, 0);
+ yyintprefix = 0;
+ (void) strncpy(yyintsuffix, p, sizeof (yyintsuffix));
+ yyintdecimal = yytext[0] != '0';
+
+ if (errno == ERANGE) {
+ xyerror(D_INT_OFLOW, "constant %s results in "
+ "integer overflow\n", yytext);
+ }
+
+ if (*p != '\0' && strchr("uUlL", *p) == NULL) {
+ xyerror(D_INT_DIGIT, "constant %s contains "
+ "invalid digit %c\n", yytext, *p);
+ }
+
+ if ((YYSTATE) != S3)
+ return (DT_TOK_INT);
+
+ yypragma = dt_node_link(yypragma,
+ dt_node_int(yylval.l_int));
+ }
+
+<S0>{RGX_FP} yyerror("floating-point constants are not permitted\n");
+
+<S0>\"{RGX_STR}$ |
+<S3>\"{RGX_STR}$ xyerror(D_STR_NL, "newline encountered in string literal");
+
+<S0>\"{RGX_STR}\" |
+<S3>\"{RGX_STR}\" {
+ /*
+ * Quoted string -- convert C escape sequences and
+ * return the string as a token.
+ */
+ yylval.l_str = strndup(yytext + 1, yyleng - 2);
+
+ if (yylval.l_str == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ (void) stresc2chr(yylval.l_str);
+ if ((YYSTATE) != S3)
+ return (DT_TOK_STRING);
+
+ yypragma = dt_node_link(yypragma,
+ dt_node_string(yylval.l_str));
+ }
+
+<S0>'{RGX_CHR}$ xyerror(D_CHR_NL, "newline encountered in character constant");
+
+<S0>'{RGX_CHR}' {
+ char *s, *p, *q;
+ size_t nbytes;
+
+ /*
+ * Character constant -- convert C escape sequences and
+ * return the character as an integer immediate value.
+ */
+ if (yyleng == 2)
+ xyerror(D_CHR_NULL, "empty character constant");
+
+ s = yytext + 1;
+ yytext[yyleng - 1] = '\0';
+ nbytes = stresc2chr(s);
+ yylval.l_int = 0;
+ yyintprefix = 0;
+ yyintsuffix[0] = '\0';
+ yyintdecimal = 1;
+
+ if (nbytes > sizeof (yylval.l_int)) {
+ xyerror(D_CHR_OFLOW, "character constant is "
+ "too long");
+ }
+#if BYTE_ORDER == _LITTLE_ENDIAN
+ p = ((char *)&yylval.l_int) + nbytes - 1;
+ for (q = s; nbytes != 0; nbytes--)
+ *p-- = *q++;
+#else
+ bcopy(s, ((char *)&yylval.l_int) +
+ sizeof (yylval.l_int) - nbytes, nbytes);
+#endif
+ return (DT_TOK_INT);
+ }
+
+<S0>"/*" |
+<S2>"/*" {
+ yypcb->pcb_cstate = (YYSTATE);
+ BEGIN(S1);
+ }
+
+<S0>{RGX_INTERP} |
+<S2>{RGX_INTERP} ; /* discard any #! lines */
+
+<S0>{RGX_CTL} |
+<S2>{RGX_CTL} |
+<S4>{RGX_CTL} {
+ assert(yypragma == NULL);
+ yypcb->pcb_cstate = (YYSTATE);
+ BEGIN(S3);
+ }
+
+<S4>. ; /* discard */
+<S4>"\n" ; /* discard */
+
+<S0>"/" {
+ int c, tok;
+
+ /*
+ * The use of "/" as the predicate delimiter and as the
+ * integer division symbol requires special lookahead
+ * to avoid a shift/reduce conflict in the D grammar.
+ * We look ahead to the next non-whitespace character.
+ * If we encounter EOF, ";", "{", or "/", then this "/"
+ * closes the predicate and we return DT_TOK_EPRED.
+ * If we encounter anything else, it's DT_TOK_DIV.
+ */
+ while ((c = input()) != 0) {
+ if (strchr("\f\n\r\t\v ", c) == NULL)
+ break;
+ }
+
+ if (c == 0 || c == ';' || c == '{' || c == '/') {
+ if (yypcb->pcb_parens != 0) {
+ yyerror("closing ) expected in "
+ "predicate before /\n");
+ }
+ if (yypcb->pcb_brackets != 0) {
+ yyerror("closing ] expected in "
+ "predicate before /\n");
+ }
+ tok = DT_TOK_EPRED;
+ } else
+ tok = DT_TOK_DIV;
+
+ unput(c);
+ return (tok);
+ }
+
+<S0>"(" {
+ yypcb->pcb_parens++;
+ return (DT_TOK_LPAR);
+ }
+
+<S0>")" {
+ if (--yypcb->pcb_parens < 0)
+ yyerror("extra ) in input stream\n");
+ return (DT_TOK_RPAR);
+ }
+
+<S0>"[" {
+ yypcb->pcb_brackets++;
+ return (DT_TOK_LBRAC);
+ }
+
+<S0>"]" {
+ if (--yypcb->pcb_brackets < 0)
+ yyerror("extra ] in input stream\n");
+ return (DT_TOK_RBRAC);
+ }
+
+<S0>"{" |
+<S2>"{" {
+ yypcb->pcb_braces++;
+ return ('{');
+ }
+
+<S0>"}" {
+ if (--yypcb->pcb_braces < 0)
+ yyerror("extra } in input stream\n");
+ return ('}');
+ }
+
+<S0>"|" return (DT_TOK_BOR);
+<S0>"^" return (DT_TOK_XOR);
+<S0>"&" return (DT_TOK_BAND);
+<S0>"&&" return (DT_TOK_LAND);
+<S0>"^^" return (DT_TOK_LXOR);
+<S0>"||" return (DT_TOK_LOR);
+<S0>"==" return (DT_TOK_EQU);
+<S0>"!=" return (DT_TOK_NEQ);
+<S0>"<" return (DT_TOK_LT);
+<S0>"<=" return (DT_TOK_LE);
+<S0>">" return (DT_TOK_GT);
+<S0>">=" return (DT_TOK_GE);
+<S0>"<<" return (DT_TOK_LSH);
+<S0>">>" return (DT_TOK_RSH);
+<S0>"+" return (DT_TOK_ADD);
+<S0>"-" return (DT_TOK_SUB);
+<S0>"*" return (DT_TOK_MUL);
+<S0>"%" return (DT_TOK_MOD);
+<S0>"~" return (DT_TOK_BNEG);
+<S0>"!" return (DT_TOK_LNEG);
+<S0>"?" return (DT_TOK_QUESTION);
+<S0>":" return (DT_TOK_COLON);
+<S0>"." return (DT_TOK_DOT);
+<S0>"->" return (DT_TOK_PTR);
+<S0>"=" return (DT_TOK_ASGN);
+<S0>"+=" return (DT_TOK_ADD_EQ);
+<S0>"-=" return (DT_TOK_SUB_EQ);
+<S0>"*=" return (DT_TOK_MUL_EQ);
+<S0>"/=" return (DT_TOK_DIV_EQ);
+<S0>"%=" return (DT_TOK_MOD_EQ);
+<S0>"&=" return (DT_TOK_AND_EQ);
+<S0>"^=" return (DT_TOK_XOR_EQ);
+<S0>"|=" return (DT_TOK_OR_EQ);
+<S0>"<<=" return (DT_TOK_LSH_EQ);
+<S0>">>=" return (DT_TOK_RSH_EQ);
+<S0>"++" return (DT_TOK_ADDADD);
+<S0>"--" return (DT_TOK_SUBSUB);
+<S0>"..." return (DT_TOK_ELLIPSIS);
+<S0>"," return (DT_TOK_COMMA);
+<S0>";" return (';');
+<S0>{RGX_WS} ; /* discard */
+<S0>"\\"\n ; /* discard */
+<S0>. yyerror("syntax error near \"%c\"\n", yytext[0]);
+
+<S1>"/*" yyerror("/* encountered inside a comment\n");
+<S1>"*/" BEGIN(yypcb->pcb_cstate);
+<S1>.|\n ; /* discard */
+
+<S2>{RGX_PSPEC} {
+ /*
+ * S2 has an ambiguity because RGX_PSPEC includes '*'
+ * as a glob character and '*' also can be DT_TOK_STAR.
+ * Since lex always matches the longest token, this
+ * rule can be matched by an input string like "int*",
+ * which could begin a global variable declaration such
+ * as "int*x;" or could begin a RGX_PSPEC with globbing
+ * such as "int* { trace(timestamp); }". If C_PSPEC is
+ * not set, we must resolve the ambiguity in favor of
+ * the type and perform lexer pushback if the fragment
+ * before '*' or entire fragment matches a type name.
+ * If C_PSPEC is set, we always return a PSPEC token.
+ * If C_PSPEC is off, the user can avoid ambiguity by
+ * including a ':' delimiter in the specifier, which
+ * they should be doing anyway to specify the provider.
+ */
+ if (!(yypcb->pcb_cflags & DTRACE_C_PSPEC) &&
+ strchr(yytext, ':') == NULL) {
+
+ char *p = strchr(yytext, '*');
+ char *q = yytext + yyleng - 1;
+
+ if (p != NULL && p > yytext)
+ *p = '\0'; /* prune yytext */
+
+ if (dt_type_lookup(yytext, NULL) == 0) {
+ yylval.l_str = strdup(yytext);
+
+ if (yylval.l_str == NULL) {
+ longjmp(yypcb->pcb_jmpbuf,
+ EDT_NOMEM);
+ }
+
+ if (p != NULL && p > yytext) {
+ for (*p = '*'; q >= p; q--)
+ unput(*q);
+ }
+
+ yybegin(YYS_EXPR);
+ return (DT_TOK_TNAME);
+ }
+
+ if (p != NULL && p > yytext)
+ *p = '*'; /* restore yytext */
+ }
+
+ if ((yylval.l_str = strdup(yytext)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ return (DT_TOK_PSPEC);
+ }
+
+<S2>"/" return (DT_TOK_DIV);
+<S2>"," return (DT_TOK_COMMA);
+
+<S2>{RGX_WS} ; /* discard */
+<S2>. yyerror("syntax error near \"%c\"\n", yytext[0]);
+
+<S3>\n {
+ dt_pragma(yypragma);
+ yypragma = NULL;
+ BEGIN(yypcb->pcb_cstate);
+ }
+
+<S3>[\f\t\v ]+ ; /* discard */
+
+<S3>[^\f\n\t\v "]+ {
+ dt_node_t *dnp;
+
+ if ((yylval.l_str = strdup(yytext)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ /*
+ * We want to call dt_node_ident() here, but we can't
+ * because it will expand inlined identifiers, which we
+ * don't want to do from #pragma context in order to
+ * support pragmas that apply to the ident itself. We
+ * call dt_node_string() and then reset dn_op instead.
+ */
+ dnp = dt_node_string(yylval.l_str);
+ dnp->dn_kind = DT_NODE_IDENT;
+ dnp->dn_op = DT_TOK_IDENT;
+ yypragma = dt_node_link(yypragma, dnp);
+ }
+
+<S3>. yyerror("syntax error near \"%c\"\n", yytext[0]);
+
+%%
+
+/*
+ * yybegin provides a wrapper for use from C code around the lex BEGIN() macro.
+ * We use two main states for lexing because probe descriptions use a syntax
+ * that is incompatible with the normal D tokens (e.g. names can contain "-").
+ * yybegin also handles the job of switching between two lists of dt_nodes
+ * as we allocate persistent definitions, like inlines, and transient nodes
+ * that will be freed once we are done parsing the current program file.
+ */
+void
+yybegin(yystate_t state)
+{
+#ifdef YYDEBUG
+ yydebug = _dtrace_debug;
+#endif
+ if (yypcb->pcb_yystate == state)
+ return; /* nothing to do if we're in the state already */
+
+ if (yypcb->pcb_yystate == YYS_DEFINE) {
+ yypcb->pcb_list = yypcb->pcb_hold;
+ yypcb->pcb_hold = NULL;
+ }
+
+ switch (state) {
+ case YYS_CLAUSE:
+ BEGIN(S2);
+ break;
+ case YYS_DEFINE:
+ assert(yypcb->pcb_hold == NULL);
+ yypcb->pcb_hold = yypcb->pcb_list;
+ yypcb->pcb_list = NULL;
+ /*FALLTHRU*/
+ case YYS_EXPR:
+ BEGIN(S0);
+ break;
+ case YYS_DONE:
+ break;
+ case YYS_CONTROL:
+ BEGIN(S4);
+ break;
+ default:
+ xyerror(D_UNKNOWN, "internal error -- bad yystate %d\n", state);
+ }
+
+ yypcb->pcb_yystate = state;
+}
+
+void
+yyinit(dt_pcb_t *pcb)
+{
+ yypcb = pcb;
+ yylineno = 1;
+ yypragma = NULL;
+#ifdef illumos
+ yysptr = yysbuf;
+#endif
+ YY_FLUSH_BUFFER;
+}
+
+/*
+ * Given a lexeme 's' (typically yytext), set yylval and return an appropriate
+ * token to the parser indicating either an identifier or a typedef name.
+ * User-defined global variables always take precedence over types, but we do
+ * use some heuristics because D programs can look at an ever-changing set of
+ * kernel types and also can implicitly instantiate variables by assignment,
+ * unlike in C. The code here is ordered carefully as lookups are not cheap.
+ */
+static int
+id_or_type(const char *s)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_decl_t *ddp = yypcb->pcb_dstack.ds_decl;
+ int c0, c1, ttok = DT_TOK_TNAME;
+ dt_ident_t *idp;
+
+ if ((s = yylval.l_str = strdup(s)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ /*
+ * If the lexeme is a global variable or likely identifier or *not* a
+ * type_name, then it is an identifier token.
+ */
+ if (dt_idstack_lookup(&yypcb->pcb_globals, s) != NULL ||
+ dt_idhash_lookup(yypcb->pcb_idents, s) != NULL ||
+ dt_type_lookup(s, NULL) != 0)
+ return (DT_TOK_IDENT);
+
+ /*
+ * If we're in the midst of parsing a declaration and a type_specifier
+ * has already been shifted, then return DT_TOK_IDENT instead of TNAME.
+ * This semantic is necessary to permit valid ISO C code such as:
+ *
+ * typedef int foo;
+ * struct s { foo foo; };
+ *
+ * without causing shift/reduce conflicts in the direct_declarator part
+ * of the grammar. The result is that we must check for conflicting
+ * redeclarations of the same identifier as part of dt_node_decl().
+ */
+ if (ddp != NULL && ddp->dd_name != NULL)
+ return (DT_TOK_IDENT);
+
+ /*
+ * If the lexeme is a type name and we are not in a program clause,
+ * then always interpret it as a type and return DT_TOK_TNAME.
+ */
+ if ((YYSTATE) != S0)
+ return (DT_TOK_TNAME);
+
+ /*
+ * If the lexeme matches a type name but is in a program clause, then
+ * it could be a type or it could be an undefined variable. Peek at
+ * the next token to decide. If we see ++, --, [, or =, we know there
+ * might be an assignment that is trying to create a global variable,
+ * so we optimistically return DT_TOK_IDENT. There is no harm in being
+ * wrong: a type_name followed by ++, --, [, or = is a syntax error.
+ */
+ while ((c0 = input()) != 0) {
+ if (strchr("\f\n\r\t\v ", c0) == NULL)
+ break;
+ }
+
+ switch (c0) {
+ case '+':
+ case '-':
+ if ((c1 = input()) == c0)
+ ttok = DT_TOK_IDENT;
+ unput(c1);
+ break;
+
+ case '=':
+ if ((c1 = input()) != c0)
+ ttok = DT_TOK_IDENT;
+ unput(c1);
+ break;
+ case '[':
+ ttok = DT_TOK_IDENT;
+ break;
+ }
+
+ if (ttok == DT_TOK_IDENT) {
+ idp = dt_idhash_insert(yypcb->pcb_idents, s, DT_IDENT_SCALAR, 0,
+ 0, _dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
+
+ if (idp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ unput(c0);
+ return (ttok);
+}
+
+#ifdef illumos
+static int
+input(void)
+{
+ int c;
+
+ if (yysptr > yysbuf)
+ c = *--yysptr;
+ else if (yypcb->pcb_fileptr != NULL)
+ c = fgetc(yypcb->pcb_fileptr);
+ else if (yypcb->pcb_strptr < yypcb->pcb_string + yypcb->pcb_strlen)
+ c = *(unsigned char *)(yypcb->pcb_strptr++);
+ else
+ c = EOF;
+
+ if (c == '\n')
+ yylineno++;
+
+ if (c != EOF)
+ return (c);
+
+ if ((YYSTATE) == S1)
+ yyerror("end-of-file encountered before matching */\n");
+
+ if ((YYSTATE) == S3)
+ yyerror("end-of-file encountered before end of control line\n");
+
+ if (yypcb->pcb_fileptr != NULL && ferror(yypcb->pcb_fileptr))
+ longjmp(yypcb->pcb_jmpbuf, EDT_FIO);
+
+ return (0); /* EOF */
+}
+
+static void
+unput(int c)
+{
+ if (c == '\n')
+ yylineno--;
+
+ *yysptr++ = c;
+ yytchar = c;
+}
+#endif /* illumos */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
new file mode 100644
index 000000000000..8dad7428722e
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -0,0 +1,1964 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2017-2018 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define ELF_TARGET_ALL
+#include <elf.h>
+
+#include <sys/types.h>
+#ifdef illumos
+#include <sys/sysmacros.h>
+#else
+#define P2ROUNDUP(x, align) (-(-(x) & -(align)))
+#endif
+
+#include <unistd.h>
+#include <strings.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef illumos
+#include <wait.h>
+#else
+#include <sys/wait.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <sys/mman.h>
+#endif
+#include <assert.h>
+#include <sys/ipc.h>
+
+#include <dt_impl.h>
+#include <dt_provider.h>
+#include <dt_program.h>
+#include <dt_string.h>
+
+#define ESHDR_NULL 0
+#define ESHDR_SHSTRTAB 1
+#define ESHDR_DOF 2
+#define ESHDR_STRTAB 3
+#define ESHDR_SYMTAB 4
+#define ESHDR_REL 5
+#define ESHDR_NUM 6
+
+#define PWRITE_SCN(index, data) \
+ (lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \
+ (off64_t)elf_file.shdr[(index)].sh_offset || \
+ dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \
+ elf_file.shdr[(index)].sh_size)
+
+static const char DTRACE_SHSTRTAB32[] = "\0"
+".shstrtab\0" /* 1 */
+".SUNW_dof\0" /* 11 */
+".strtab\0" /* 21 */
+".symtab\0" /* 29 */
+#ifdef __sparc
+".rela.SUNW_dof"; /* 37 */
+#else
+".rel.SUNW_dof"; /* 37 */
+#endif
+
+static const char DTRACE_SHSTRTAB64[] = "\0"
+".shstrtab\0" /* 1 */
+".SUNW_dof\0" /* 11 */
+".strtab\0" /* 21 */
+".symtab\0" /* 29 */
+".rela.SUNW_dof"; /* 37 */
+
+static const char DOFSTR[] = "__SUNW_dof";
+static const char DOFLAZYSTR[] = "___SUNW_dof";
+
+typedef struct dt_link_pair {
+ struct dt_link_pair *dlp_next; /* next pair in linked list */
+ void *dlp_str; /* buffer for string table */
+ void *dlp_sym; /* buffer for symbol table */
+} dt_link_pair_t;
+
+typedef struct dof_elf32 {
+ uint32_t de_nrel; /* relocation count */
+#ifdef __sparc
+ Elf32_Rela *de_rel; /* array of relocations for sparc */
+#else
+ Elf32_Rel *de_rel; /* array of relocations for x86 */
+#endif
+ uint32_t de_nsym; /* symbol count */
+ Elf32_Sym *de_sym; /* array of symbols */
+ uint32_t de_strlen; /* size of of string table */
+ char *de_strtab; /* string table */
+ uint32_t de_global; /* index of the first global symbol */
+} dof_elf32_t;
+
+static int
+prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep)
+{
+ dof_sec_t *dofs, *s;
+ dof_relohdr_t *dofrh;
+ dof_relodesc_t *dofr;
+ char *strtab;
+ int i, j, nrel;
+ size_t strtabsz = 1;
+ uint32_t count = 0;
+ size_t base;
+ Elf32_Sym *sym;
+#ifdef __sparc
+ Elf32_Rela *rel;
+#else
+ Elf32_Rel *rel;
+#endif
+
+ /*LINTED*/
+ dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff);
+
+ /*
+ * First compute the size of the string table and the number of
+ * relocations present in the DOF.
+ */
+ for (i = 0; i < dof->dofh_secnum; i++) {
+ if (dofs[i].dofs_type != DOF_SECT_URELHDR)
+ continue;
+
+ /*LINTED*/
+ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);
+
+ s = &dofs[dofrh->dofr_strtab];
+ strtab = (char *)dof + s->dofs_offset;
+ assert(strtab[0] == '\0');
+ strtabsz += s->dofs_size - 1;
+
+ s = &dofs[dofrh->dofr_relsec];
+ /*LINTED*/
+ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);
+ count += s->dofs_size / s->dofs_entsize;
+ }
+
+ dep->de_strlen = strtabsz;
+ dep->de_nrel = count;
+ dep->de_nsym = count + 1; /* the first symbol is always null */
+
+ if (dtp->dt_lazyload) {
+ dep->de_strlen += sizeof (DOFLAZYSTR);
+ dep->de_nsym++;
+ } else {
+ dep->de_strlen += sizeof (DOFSTR);
+ dep->de_nsym++;
+ }
+
+ if ((dep->de_rel = calloc(dep->de_nrel,
+ sizeof (dep->de_rel[0]))) == NULL) {
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) {
+ free(dep->de_rel);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) {
+ free(dep->de_rel);
+ free(dep->de_sym);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ count = 0;
+ strtabsz = 1;
+ dep->de_strtab[0] = '\0';
+ rel = dep->de_rel;
+ sym = dep->de_sym;
+ dep->de_global = 1;
+
+ /*
+ * The first symbol table entry must be zeroed and is always ignored.
+ */
+ bzero(sym, sizeof (Elf32_Sym));
+ sym++;
+
+ /*
+ * Take a second pass through the DOF sections filling in the
+ * memory we allocated.
+ */
+ for (i = 0; i < dof->dofh_secnum; i++) {
+ if (dofs[i].dofs_type != DOF_SECT_URELHDR)
+ continue;
+
+ /*LINTED*/
+ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);
+
+ s = &dofs[dofrh->dofr_strtab];
+ strtab = (char *)dof + s->dofs_offset;
+ bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size);
+ base = strtabsz;
+ strtabsz += s->dofs_size - 1;
+
+ s = &dofs[dofrh->dofr_relsec];
+ /*LINTED*/
+ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);
+ nrel = s->dofs_size / s->dofs_entsize;
+
+ s = &dofs[dofrh->dofr_tgtsec];
+
+ for (j = 0; j < nrel; j++) {
+#if defined(__aarch64__)
+/* XXX */
+ printf("%s:%s(%d): aarch64 not implemented\n",
+ __FUNCTION__, __FILE__, __LINE__);
+#elif defined(__arm__)
+/* XXX */
+ printf("%s:%s(%d): arm not implemented\n",
+ __FUNCTION__, __FILE__, __LINE__);
+#elif defined(__i386) || defined(__amd64)
+ rel->r_offset = s->dofs_offset +
+ dofr[j].dofr_offset;
+ rel->r_info = ELF32_R_INFO(count + dep->de_global,
+ R_386_PC32);
+#elif defined(__mips__)
+/* XXX */
+ printf("%s:%s(%d): MIPS not implemented\n",
+ __FUNCTION__, __FILE__, __LINE__);
+#elif defined(__powerpc__)
+ /*
+ * Add 4 bytes to hit the low half of this 64-bit
+ * big-endian address.
+ */
+ rel->r_offset = s->dofs_offset +
+ dofr[j].dofr_offset + 4;
+ rel->r_info = ELF32_R_INFO(count + dep->de_global,
+ R_PPC_REL32);
+#elif defined(__riscv)
+/* XXX */
+ printf("%s:%s(%d): RISC-V not implemented\n",
+ __FUNCTION__, __FILE__, __LINE__);
+#else
+#error unknown ISA
+#endif
+
+ sym->st_name = base + dofr[j].dofr_name - 1;
+ sym->st_value = 0;
+ sym->st_size = 0;
+ sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC);
+ sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN);
+ sym->st_shndx = SHN_UNDEF;
+
+ rel++;
+ sym++;
+ count++;
+ }
+ }
+
+ /*
+ * Add a symbol for the DOF itself. We use a different symbol for
+ * lazily and actively loaded DOF to make them easy to distinguish.
+ */
+ sym->st_name = strtabsz;
+ sym->st_value = 0;
+ sym->st_size = dof->dofh_filesz;
+ sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT);
+ sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN);
+ sym->st_shndx = ESHDR_DOF;
+ sym++;
+
+ if (dtp->dt_lazyload) {
+ bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz,
+ sizeof (DOFLAZYSTR));
+ strtabsz += sizeof (DOFLAZYSTR);
+ } else {
+ bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR));
+ strtabsz += sizeof (DOFSTR);
+ }
+
+ assert(count == dep->de_nrel);
+ assert(strtabsz == dep->de_strlen);
+
+ return (0);
+}
+
+
+typedef struct dof_elf64 {
+ uint32_t de_nrel;
+ Elf64_Rela *de_rel;
+ uint32_t de_nsym;
+ Elf64_Sym *de_sym;
+
+ uint32_t de_strlen;
+ char *de_strtab;
+
+ uint32_t de_global;
+} dof_elf64_t;
+
+static int
+prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
+{
+ dof_sec_t *dofs, *s;
+ dof_relohdr_t *dofrh;
+ dof_relodesc_t *dofr;
+ char *strtab;
+ int i, j, nrel;
+ size_t strtabsz = 1;
+#ifdef illumos
+ uint32_t count = 0;
+#else
+ uint64_t count = 0;
+#endif
+ size_t base;
+ Elf64_Sym *sym;
+ Elf64_Rela *rel;
+
+ /*LINTED*/
+ dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff);
+
+ /*
+ * First compute the size of the string table and the number of
+ * relocations present in the DOF.
+ */
+ for (i = 0; i < dof->dofh_secnum; i++) {
+ if (dofs[i].dofs_type != DOF_SECT_URELHDR)
+ continue;
+
+ /*LINTED*/
+ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);
+
+ s = &dofs[dofrh->dofr_strtab];
+ strtab = (char *)dof + s->dofs_offset;
+ assert(strtab[0] == '\0');
+ strtabsz += s->dofs_size - 1;
+
+ s = &dofs[dofrh->dofr_relsec];
+ /*LINTED*/
+ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);
+ count += s->dofs_size / s->dofs_entsize;
+ }
+
+ dep->de_strlen = strtabsz;
+ dep->de_nrel = count;
+ dep->de_nsym = count + 1; /* the first symbol is always null */
+
+ if (dtp->dt_lazyload) {
+ dep->de_strlen += sizeof (DOFLAZYSTR);
+ dep->de_nsym++;
+ } else {
+ dep->de_strlen += sizeof (DOFSTR);
+ dep->de_nsym++;
+ }
+
+ if ((dep->de_rel = calloc(dep->de_nrel,
+ sizeof (dep->de_rel[0]))) == NULL) {
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) {
+ free(dep->de_rel);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) {
+ free(dep->de_rel);
+ free(dep->de_sym);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ count = 0;
+ strtabsz = 1;
+ dep->de_strtab[0] = '\0';
+ rel = dep->de_rel;
+ sym = dep->de_sym;
+ dep->de_global = 1;
+
+ /*
+ * The first symbol table entry must be zeroed and is always ignored.
+ */
+ bzero(sym, sizeof (Elf64_Sym));
+ sym++;
+
+ /*
+ * Take a second pass through the DOF sections filling in the
+ * memory we allocated.
+ */
+ for (i = 0; i < dof->dofh_secnum; i++) {
+ if (dofs[i].dofs_type != DOF_SECT_URELHDR)
+ continue;
+
+ /*LINTED*/
+ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);
+
+ s = &dofs[dofrh->dofr_strtab];
+ strtab = (char *)dof + s->dofs_offset;
+ bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size);
+ base = strtabsz;
+ strtabsz += s->dofs_size - 1;
+
+ s = &dofs[dofrh->dofr_relsec];
+ /*LINTED*/
+ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);
+ nrel = s->dofs_size / s->dofs_entsize;
+
+ s = &dofs[dofrh->dofr_tgtsec];
+
+ for (j = 0; j < nrel; j++) {
+#if defined(__aarch64__)
+/* XXX */
+#elif defined(__arm__)
+/* XXX */
+#elif defined(__mips__)
+/* XXX */
+#elif defined(__powerpc__)
+ rel->r_offset = s->dofs_offset +
+ dofr[j].dofr_offset;
+ rel->r_info = ELF64_R_INFO(count + dep->de_global,
+ R_PPC64_REL64);
+#elif defined(__riscv)
+/* XXX */
+#elif defined(__i386) || defined(__amd64)
+ rel->r_offset = s->dofs_offset +
+ dofr[j].dofr_offset;
+ rel->r_info = ELF64_R_INFO(count + dep->de_global,
+ R_X86_64_PC64);
+#else
+#error unknown ISA
+#endif
+
+ sym->st_name = base + dofr[j].dofr_name - 1;
+ sym->st_value = 0;
+ sym->st_size = 0;
+ sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC);
+ sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN);
+ sym->st_shndx = SHN_UNDEF;
+
+ rel++;
+ sym++;
+ count++;
+ }
+ }
+
+ /*
+ * Add a symbol for the DOF itself. We use a different symbol for
+ * lazily and actively loaded DOF to make them easy to distinguish.
+ */
+ sym->st_name = strtabsz;
+ sym->st_value = 0;
+ sym->st_size = dof->dofh_filesz;
+ sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
+ sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN);
+ sym->st_shndx = ESHDR_DOF;
+ sym++;
+
+ if (dtp->dt_lazyload) {
+ bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz,
+ sizeof (DOFLAZYSTR));
+ strtabsz += sizeof (DOFLAZYSTR);
+ } else {
+ bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR));
+ strtabsz += sizeof (DOFSTR);
+ }
+
+ assert(count == dep->de_nrel);
+ assert(strtabsz == dep->de_strlen);
+
+ return (0);
+}
+
+/*
+ * Write out an ELF32 file prologue consisting of a header, section headers,
+ * and a section header string table. The DOF data will follow this prologue
+ * and complete the contents of the given ELF file.
+ */
+static int
+dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
+{
+ struct {
+ Elf32_Ehdr ehdr;
+ Elf32_Shdr shdr[ESHDR_NUM];
+ } elf_file;
+
+ Elf32_Shdr *shp;
+ Elf32_Off off;
+ dof_elf32_t de;
+ int ret = 0;
+ uint_t nshdr;
+
+ if (prepare_elf32(dtp, dof, &de) != 0)
+ return (-1); /* errno is set for us */
+
+ /*
+ * If there are no relocations, we only need enough sections for
+ * the shstrtab and the DOF.
+ */
+ nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM;
+
+ bzero(&elf_file, sizeof (elf_file));
+
+ elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0;
+ elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1;
+ elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2;
+ elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3;
+ elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+#if BYTE_ORDER == _BIG_ENDIAN
+ elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
+#else
+ elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+#endif
+#if defined(__FreeBSD__)
+ elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+#endif
+ elf_file.ehdr.e_type = ET_REL;
+#if defined(__arm__)
+ elf_file.ehdr.e_machine = EM_ARM;
+#elif defined(__mips__)
+ elf_file.ehdr.e_machine = EM_MIPS;
+#elif defined(__powerpc__)
+ elf_file.ehdr.e_machine = EM_PPC;
+#elif defined(__sparc)
+ elf_file.ehdr.e_machine = EM_SPARC;
+#elif defined(__i386) || defined(__amd64)
+ elf_file.ehdr.e_machine = EM_386;
+#endif
+ elf_file.ehdr.e_version = EV_CURRENT;
+ elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr);
+ elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr);
+ elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr);
+ elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr);
+ elf_file.ehdr.e_shnum = nshdr;
+ elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB;
+ off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr);
+
+ shp = &elf_file.shdr[ESHDR_SHSTRTAB];
+ shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */
+ shp->sh_type = SHT_STRTAB;
+ shp->sh_offset = off;
+ shp->sh_size = sizeof (DTRACE_SHSTRTAB32);
+ shp->sh_addralign = sizeof (char);
+ off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8);
+
+ shp = &elf_file.shdr[ESHDR_DOF];
+ shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */
+ shp->sh_flags = SHF_ALLOC;
+ shp->sh_type = SHT_SUNW_dof;
+ shp->sh_offset = off;
+ shp->sh_size = dof->dofh_filesz;
+ shp->sh_addralign = 8;
+ off = shp->sh_offset + shp->sh_size;
+
+ shp = &elf_file.shdr[ESHDR_STRTAB];
+ shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */
+ shp->sh_flags = SHF_ALLOC;
+ shp->sh_type = SHT_STRTAB;
+ shp->sh_offset = off;
+ shp->sh_size = de.de_strlen;
+ shp->sh_addralign = sizeof (char);
+ off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4);
+
+ shp = &elf_file.shdr[ESHDR_SYMTAB];
+ shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */
+ shp->sh_flags = SHF_ALLOC;
+ shp->sh_type = SHT_SYMTAB;
+ shp->sh_entsize = sizeof (Elf32_Sym);
+ shp->sh_link = ESHDR_STRTAB;
+ shp->sh_offset = off;
+ shp->sh_info = de.de_global;
+ shp->sh_size = de.de_nsym * sizeof (Elf32_Sym);
+ shp->sh_addralign = 4;
+ off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4);
+
+ if (de.de_nrel == 0) {
+ if (dt_write(dtp, fd, &elf_file,
+ sizeof (elf_file)) != sizeof (elf_file) ||
+ PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) ||
+ PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||
+ PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||
+ PWRITE_SCN(ESHDR_DOF, dof)) {
+ ret = dt_set_errno(dtp, errno);
+ }
+ } else {
+ shp = &elf_file.shdr[ESHDR_REL];
+ shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */
+ shp->sh_flags = SHF_ALLOC;
+#ifdef __sparc
+ shp->sh_type = SHT_RELA;
+#else
+ shp->sh_type = SHT_REL;
+#endif
+ shp->sh_entsize = sizeof (de.de_rel[0]);
+ shp->sh_link = ESHDR_SYMTAB;
+ shp->sh_info = ESHDR_DOF;
+ shp->sh_offset = off;
+ shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]);
+ shp->sh_addralign = 4;
+
+ if (dt_write(dtp, fd, &elf_file,
+ sizeof (elf_file)) != sizeof (elf_file) ||
+ PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) ||
+ PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||
+ PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||
+ PWRITE_SCN(ESHDR_REL, de.de_rel) ||
+ PWRITE_SCN(ESHDR_DOF, dof)) {
+ ret = dt_set_errno(dtp, errno);
+ }
+ }
+
+ free(de.de_strtab);
+ free(de.de_sym);
+ free(de.de_rel);
+
+ return (ret);
+}
+
+/*
+ * Write out an ELF64 file prologue consisting of a header, section headers,
+ * and a section header string table. The DOF data will follow this prologue
+ * and complete the contents of the given ELF file.
+ */
+static int
+dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
+{
+ struct {
+ Elf64_Ehdr ehdr;
+ Elf64_Shdr shdr[ESHDR_NUM];
+ } elf_file;
+
+ Elf64_Shdr *shp;
+ Elf64_Off off;
+ dof_elf64_t de;
+ int ret = 0;
+ uint_t nshdr;
+
+ if (prepare_elf64(dtp, dof, &de) != 0)
+ return (-1); /* errno is set for us */
+
+ /*
+ * If there are no relocations, we only need enough sections for
+ * the shstrtab and the DOF.
+ */
+ nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM;
+
+ bzero(&elf_file, sizeof (elf_file));
+
+ elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0;
+ elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1;
+ elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2;
+ elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3;
+ elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64;
+#if BYTE_ORDER == _BIG_ENDIAN
+ elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
+#else
+ elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+#endif
+#if defined(__FreeBSD__)
+ elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+#endif
+ elf_file.ehdr.e_type = ET_REL;
+#if defined(__arm__)
+ elf_file.ehdr.e_machine = EM_ARM;
+#elif defined(__mips__)
+ elf_file.ehdr.e_machine = EM_MIPS;
+#elif defined(__powerpc64__)
+ elf_file.ehdr.e_machine = EM_PPC64;
+#elif defined(__sparc)
+ elf_file.ehdr.e_machine = EM_SPARCV9;
+#elif defined(__i386) || defined(__amd64)
+ elf_file.ehdr.e_machine = EM_AMD64;
+#endif
+ elf_file.ehdr.e_version = EV_CURRENT;
+ elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr);
+ elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr);
+ elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr);
+ elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr);
+ elf_file.ehdr.e_shnum = nshdr;
+ elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB;
+ off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr);
+
+ shp = &elf_file.shdr[ESHDR_SHSTRTAB];
+ shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */
+ shp->sh_type = SHT_STRTAB;
+ shp->sh_offset = off;
+ shp->sh_size = sizeof (DTRACE_SHSTRTAB64);
+ shp->sh_addralign = sizeof (char);
+ off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8);
+
+ shp = &elf_file.shdr[ESHDR_DOF];
+ shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */
+ shp->sh_flags = SHF_ALLOC;
+ shp->sh_type = SHT_SUNW_dof;
+ shp->sh_offset = off;
+ shp->sh_size = dof->dofh_filesz;
+ shp->sh_addralign = 8;
+ off = shp->sh_offset + shp->sh_size;
+
+ shp = &elf_file.shdr[ESHDR_STRTAB];
+ shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */
+ shp->sh_flags = SHF_ALLOC;
+ shp->sh_type = SHT_STRTAB;
+ shp->sh_offset = off;
+ shp->sh_size = de.de_strlen;
+ shp->sh_addralign = sizeof (char);
+ off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8);
+
+ shp = &elf_file.shdr[ESHDR_SYMTAB];
+ shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */
+ shp->sh_flags = SHF_ALLOC;
+ shp->sh_type = SHT_SYMTAB;
+ shp->sh_entsize = sizeof (Elf64_Sym);
+ shp->sh_link = ESHDR_STRTAB;
+ shp->sh_offset = off;
+ shp->sh_info = de.de_global;
+ shp->sh_size = de.de_nsym * sizeof (Elf64_Sym);
+ shp->sh_addralign = 8;
+ off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8);
+
+ if (de.de_nrel == 0) {
+ if (dt_write(dtp, fd, &elf_file,
+ sizeof (elf_file)) != sizeof (elf_file) ||
+ PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) ||
+ PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||
+ PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||
+ PWRITE_SCN(ESHDR_DOF, dof)) {
+ ret = dt_set_errno(dtp, errno);
+ }
+ } else {
+ shp = &elf_file.shdr[ESHDR_REL];
+ shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */
+ shp->sh_flags = SHF_ALLOC;
+ shp->sh_type = SHT_RELA;
+ shp->sh_entsize = sizeof (de.de_rel[0]);
+ shp->sh_link = ESHDR_SYMTAB;
+ shp->sh_info = ESHDR_DOF;
+ shp->sh_offset = off;
+ shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]);
+ shp->sh_addralign = 8;
+
+ if (dt_write(dtp, fd, &elf_file,
+ sizeof (elf_file)) != sizeof (elf_file) ||
+ PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) ||
+ PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||
+ PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||
+ PWRITE_SCN(ESHDR_REL, de.de_rel) ||
+ PWRITE_SCN(ESHDR_DOF, dof)) {
+ ret = dt_set_errno(dtp, errno);
+ }
+ }
+
+ free(de.de_strtab);
+ free(de.de_sym);
+ free(de.de_rel);
+
+ return (ret);
+}
+
+static int
+dt_symtab_lookup(Elf_Data *data_sym, int start, int end, uintptr_t addr,
+ uint_t shn, GElf_Sym *sym, int uses_funcdesc, Elf *elf)
+{
+ Elf64_Addr symval;
+ Elf_Scn *opd_scn;
+ Elf_Data *opd_desc;
+ int i;
+
+ for (i = start; i < end && gelf_getsym(data_sym, i, sym) != NULL; i++) {
+ if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
+ symval = sym->st_value;
+ if (uses_funcdesc) {
+ opd_scn = elf_getscn(elf, sym->st_shndx);
+ opd_desc = elf_rawdata(opd_scn, NULL);
+ symval =
+ *(uint64_t*)((char *)opd_desc->d_buf + symval);
+ }
+ if ((uses_funcdesc || shn == sym->st_shndx) &&
+ symval <= addr && addr < symval + sym->st_size)
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+#if defined(__aarch64__)
+/* XXX */
+static int
+dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
+ uint32_t *off)
+{
+ printf("%s:%s(%d): aarch64 not implemented\n", __FUNCTION__, __FILE__,
+ __LINE__);
+ return (-1);
+}
+#elif defined(__arm__)
+/* XXX */
+static int
+dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
+ uint32_t *off)
+{
+ printf("%s:%s(%d): arm not implemented\n", __FUNCTION__, __FILE__,
+ __LINE__);
+ return (-1);
+}
+#elif defined(__mips__)
+/* XXX */
+static int
+dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
+ uint32_t *off)
+{
+ printf("%s:%s(%d): MIPS not implemented\n", __FUNCTION__, __FILE__,
+ __LINE__);
+ return (-1);
+}
+#elif defined(__powerpc__)
+/* The sentinel is 'xor r3,r3,r3'. */
+#define DT_OP_XOR_R3 0x7c631a78
+
+#define DT_OP_NOP 0x60000000
+#define DT_OP_BLR 0x4e800020
+
+/* This captures all forms of branching to address. */
+#define DT_IS_BRANCH(inst) ((inst & 0xfc000000) == 0x48000000)
+#define DT_IS_BL(inst) (DT_IS_BRANCH(inst) && (inst & 0x01))
+
+/* XXX */
+static int
+dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
+ uint32_t *off)
+{
+ uint32_t *ip;
+
+ if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0)
+ return (-1);
+
+ /*LINTED*/
+ ip = (uint32_t *)(p + rela->r_offset);
+
+ /*
+ * We only know about some specific relocation types.
+ */
+ if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 &&
+ GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24)
+ return (-1);
+
+ /*
+ * 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 below.
+ */
+ if (isenabled) {
+ if (ip[0] == DT_OP_XOR_R3) {
+ (*off) += sizeof (ip[0]);
+ return (0);
+ }
+ } else {
+ if (ip[0] == DT_OP_NOP) {
+ (*off) += sizeof (ip[0]);
+ return (0);
+ }
+ }
+
+ /*
+ * We only expect branch to address instructions.
+ */
+ if (!DT_IS_BRANCH(ip[0])) {
+ dt_dprintf("found %x instead of a branch instruction at %llx\n",
+ ip[0], (u_longlong_t)rela->r_offset);
+ return (-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_BL(ip[0])) {
+ dt_dprintf("tail call to is-enabled probe at %llx\n",
+ (u_longlong_t)rela->r_offset);
+ return (-1);
+ }
+
+ ip[0] = DT_OP_XOR_R3;
+ (*off) += sizeof (ip[0]);
+ } else {
+ if (DT_IS_BL(ip[0]))
+ ip[0] = DT_OP_NOP;
+ else
+ ip[0] = DT_OP_BLR;
+ }
+
+ return (0);
+}
+#elif defined(__riscv)
+/* XXX */
+static int
+dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
+ uint32_t *off)
+{
+ printf("%s:%s(%d): RISC-V implementation required\n", __FUNCTION__,
+ __FILE__, __LINE__);
+ return (-1);
+}
+#elif defined(__sparc)
+
+#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)
+#define DT_IS_RETL(inst) (((inst) & 0xfff83fff) == 0x81c02008)
+
+#define DT_RS2(inst) ((inst) & 0x1f)
+#define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14))
+
+/*ARGSUSED*/
+static int
+dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
+ uint32_t *off)
+{
+ uint32_t *ip;
+
+ if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0)
+ return (-1);
+
+ /*LINTED*/
+ ip = (uint32_t *)(p + rela->r_offset);
+
+ /*
+ * We only know about some specific relocation types.
+ */
+ if (GELF_R_TYPE(rela->r_info) != R_SPARC_WDISP30 &&
+ GELF_R_TYPE(rela->r_info) != R_SPARC_WPLT30)
+ return (-1);
+
+ /*
+ * 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 below.
+ */
+ if (isenabled) {
+ if (ip[0] == DT_OP_NOP) {
+ (*off) += sizeof (ip[0]);
+ return (0);
+ }
+ } else {
+ if (DT_IS_RESTORE(ip[1])) {
+ if (ip[0] == DT_OP_RET) {
+ (*off) += sizeof (ip[0]);
+ 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);
+ }
+ }
+ }
+
+ /*
+ * We only expect call instructions with a displacement of 0.
+ */
+ if (ip[0] != DT_OP_CALL) {
+ dt_dprintf("found %x instead of a call instruction at %llx\n",
+ ip[0], (u_longlong_t)rela->r_offset);
+ return (-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);
+ }
+
+
+ /*
+ * On SPARC, we take advantage of the fact that the first
+ * argument shares the same register as for the return value.
+ * The macro handles the work of zeroing that register so we
+ * don't need to do anything special here. We instrument the
+ * instruction in the delay slot as we'll need to modify the
+ * return register after that instruction has been emulated.
+ */
+ ip[0] = DT_OP_NOP;
+ (*off) += sizeof (ip[0]);
+ } else {
+ /*
+ * 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); the delay slot instruction is left, but should have no
+ * effect. Otherwise we change the call to be a nop. We
+ * identify the subsequent instruction as the probe point in
+ * all but the leaf tail-call case to ensure that arguments to
+ * the probe are complete and consistent. An astute, though
+ * largely hypothetical, observer would note that there is the
+ * possibility of a false-positive probe firing if the function
+ * contained a branch to the instruction in the delay slot of
+ * the call. Fixing this would require significant in-kernel
+ * modifications, and isn't worth doing until we see it in the
+ * wild.
+ */
+ if (DT_IS_RESTORE(ip[1])) {
+ ip[0] = DT_OP_RET;
+ (*off) += sizeof (ip[0]);
+ } 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);
+}
+
+#elif defined(__i386) || defined(__amd64)
+
+#define DT_OP_NOP 0x90
+#define DT_OP_RET 0xc3
+#define DT_OP_CALL 0xe8
+#define DT_OP_JMP32 0xe9
+#define DT_OP_REX_RAX 0x48
+#define DT_OP_XOR_EAX_0 0x33
+#define DT_OP_XOR_EAX_1 0xc0
+
+static int
+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);
+ uint8_t ret;
+
+ /*
+ * 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 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;
+
+ /*
+ * We only know about some specific relocation types. Luckily
+ * these types have the same values on both 32-bit and 64-bit
+ * x86 architectures.
+ */
+ if (GELF_R_TYPE(rela->r_info) != R_386_PC32 &&
+ GELF_R_TYPE(rela->r_info) != R_386_PLT32)
+ return (-1);
+
+ /*
+ * 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 to match the
+ * text modification code below.
+ */
+ if (!isenabled) {
+ if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) &&
+ 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[3] == DT_OP_RET) &&
+ 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[2] == DT_OP_RET) &&
+ ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) {
+ (*off) += 2;
+ return (0);
+ }
+ }
+
+ /*
+ * We expect either a call instrution with a 32-bit displacement or a
+ * jmp instruction with a 32-bit displacement acting as a tail-call.
+ */
+ if (ip[0] != DT_OP_CALL && ip[0] != DT_OP_JMP32) {
+ dt_dprintf("found %x instead of a call or jmp instruction at "
+ "%llx\n", ip[0], (u_longlong_t)rela->r_offset);
+ return (-1);
+ }
+
+ ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : 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] = ret;
+ 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] = ret;
+ ip[4] = DT_OP_NOP;
+ (*off) += 3;
+ } else {
+ ip[0] = DT_OP_XOR_EAX_0;
+ ip[1] = DT_OP_XOR_EAX_1;
+ ip[2] = ret;
+ ip[3] = DT_OP_NOP;
+ ip[4] = DT_OP_NOP;
+ (*off) += 2;
+ }
+
+ return (0);
+}
+
+#else
+#error unknown ISA
+#endif
+
+/*PRINTFLIKE5*/
+static int
+dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs,
+ const char *format, ...)
+{
+ va_list ap;
+ dt_link_pair_t *pair;
+
+ va_start(ap, format);
+ dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap);
+ va_end(ap);
+
+ if (elf != NULL)
+ (void) elf_end(elf);
+
+ if (fd >= 0)
+ (void) close(fd);
+
+ while ((pair = bufs) != NULL) {
+ bufs = pair->dlp_next;
+ dt_free(dtp, pair->dlp_str);
+ dt_free(dtp, pair->dlp_sym);
+ dt_free(dtp, pair);
+ }
+
+ return (dt_set_errno(dtp, EDT_COMPILER));
+}
+
+static int
+process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
+{
+ static const char dt_prefix[] = "__dtrace";
+ static const char dt_enabled[] = "enabled";
+ static const char dt_symprefix[] = "$dtrace";
+ static const char dt_symfmt[] = "%s%ld.%s";
+ static const char dt_weaksymfmt[] = "%s.%s";
+ char probename[DTRACE_NAMELEN];
+ int fd, i, ndx, eprobe, mod = 0;
+ Elf *elf = NULL;
+ GElf_Ehdr ehdr;
+ Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt;
+ Elf_Data *data_rel, *data_sym, *data_str, *data_tgt;
+ GElf_Shdr shdr_rel, shdr_sym, shdr_str, shdr_tgt;
+ GElf_Sym rsym, fsym, dsym;
+ GElf_Rela rela;
+ char *s, *p, *r;
+ char pname[DTRACE_PROVNAMELEN];
+ dt_provider_t *pvp;
+ dt_probe_t *prp;
+ uint32_t off, eclass, emachine1, emachine2;
+ size_t symsize, osym, nsym, isym, istr, len;
+ key_t objkey;
+ dt_link_pair_t *pair, *bufs = NULL;
+ dt_strtab_t *strtab;
+ void *tmp;
+
+ if ((fd = open64(obj, O_RDWR)) == -1) {
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "failed to open %s: %s", obj, strerror(errno)));
+ }
+
+ if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) {
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "failed to process %s: %s", obj, elf_errmsg(elf_errno())));
+ }
+
+ switch (elf_kind(elf)) {
+ case ELF_K_ELF:
+ break;
+ case ELF_K_AR:
+ return (dt_link_error(dtp, elf, fd, bufs, "archives are not "
+ "permitted; use the contents of the archive instead: %s",
+ obj));
+ default:
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "invalid file type: %s", obj));
+ }
+
+ if (gelf_getehdr(elf, &ehdr) == NULL) {
+ return (dt_link_error(dtp, elf, fd, bufs, "corrupt file: %s",
+ obj));
+ }
+
+ if (dtp->dt_oflags & DTRACE_O_LP64) {
+ eclass = ELFCLASS64;
+#if defined(__mips__)
+ emachine1 = emachine2 = EM_MIPS;
+#elif defined(__powerpc__)
+ emachine1 = emachine2 = EM_PPC64;
+#elif defined(__sparc)
+ emachine1 = emachine2 = EM_SPARCV9;
+#elif defined(__i386) || defined(__amd64)
+ emachine1 = emachine2 = EM_AMD64;
+#endif
+ symsize = sizeof (Elf64_Sym);
+ } else {
+ eclass = ELFCLASS32;
+#if defined(__arm__)
+ emachine1 = emachine2 = EM_ARM;
+#elif defined(__mips__)
+ emachine1 = emachine2 = EM_MIPS;
+#elif defined(__powerpc__)
+ emachine1 = emachine2 = EM_PPC;
+#elif defined(__sparc)
+ emachine1 = EM_SPARC;
+ emachine2 = EM_SPARC32PLUS;
+#elif defined(__i386) || defined(__amd64)
+ emachine1 = emachine2 = EM_386;
+#endif
+ symsize = sizeof (Elf32_Sym);
+ }
+
+ if (ehdr.e_ident[EI_CLASS] != eclass) {
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "incorrect ELF class for object file: %s", obj));
+ }
+
+ if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) {
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "incorrect ELF machine type for object file: %s", obj));
+ }
+
+ /*
+ * We use this token as a relatively unique handle for this file on the
+ * system in order to disambiguate potential conflicts between files of
+ * the same name which contain identially named local symbols.
+ */
+ if ((objkey = ftok(obj, 0)) == (key_t)-1) {
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "failed to generate unique key for object file: %s", obj));
+ }
+
+ scn_rel = NULL;
+ while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) {
+ if (gelf_getshdr(scn_rel, &shdr_rel) == NULL)
+ goto err;
+
+ /*
+ * Skip any non-relocation sections.
+ */
+ if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL)
+ continue;
+
+ if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL)
+ goto err;
+
+ /*
+ * Grab the section, section header and section data for the
+ * symbol table that this relocation section references.
+ */
+ if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL ||
+ gelf_getshdr(scn_sym, &shdr_sym) == NULL ||
+ (data_sym = elf_getdata(scn_sym, NULL)) == NULL)
+ goto err;
+
+ /*
+ * Ditto for that symbol table's string table.
+ */
+ if ((scn_str = elf_getscn(elf, shdr_sym.sh_link)) == NULL ||
+ gelf_getshdr(scn_str, &shdr_str) == NULL ||
+ (data_str = elf_getdata(scn_str, NULL)) == NULL)
+ goto err;
+
+ /*
+ * Grab the section, section header and section data for the
+ * target section for the relocations. For the relocations
+ * we're looking for -- this will typically be the text of the
+ * object file.
+ */
+ if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL ||
+ gelf_getshdr(scn_tgt, &shdr_tgt) == NULL ||
+ (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL)
+ goto err;
+
+ /*
+ * We're looking for relocations to symbols matching this form:
+ *
+ * __dtrace[enabled]_<prov>___<probe>
+ *
+ * For the generated object, we need to record the location
+ * identified by the relocation, and create a new relocation
+ * in the generated object that will be resolved at link time
+ * to the location of the function in which the probe is
+ * embedded. In the target object, we change the matched symbol
+ * so that it will be ignored at link time, and we modify the
+ * target (text) section to replace the call instruction with
+ * one or more nops.
+ *
+ * To avoid runtime overhead, the relocations added to the
+ * generated object should be resolved at static link time. We
+ * therefore create aliases for the functions that contain
+ * probes. An alias is global (so that the relocation from the
+ * generated object can be resolved), and hidden (so that its
+ * address is known at static link time). Such aliases have this
+ * form:
+ *
+ * $dtrace<key>.<function>
+ *
+ * We take a first pass through all the relocations to
+ * populate our string table and count the number of extra
+ * symbols we'll require.
+ */
+ strtab = dt_strtab_create(1);
+ nsym = 0;
+ isym = data_sym->d_size / symsize;
+ istr = data_str->d_size;
+
+ for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) {
+
+ if (shdr_rel.sh_type == SHT_RELA) {
+ if (gelf_getrela(data_rel, i, &rela) == NULL)
+ continue;
+ } else {
+ GElf_Rel rel;
+ if (gelf_getrel(data_rel, i, &rel) == NULL)
+ continue;
+ rela.r_offset = rel.r_offset;
+ rela.r_info = rel.r_info;
+ rela.r_addend = 0;
+ }
+
+ if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info),
+ &rsym) == NULL) {
+ dt_strtab_destroy(strtab);
+ goto err;
+ }
+
+ s = (char *)data_str->d_buf + rsym.st_name;
+
+ if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0)
+ continue;
+
+ if (dt_symtab_lookup(data_sym, 0, isym, rela.r_offset,
+ shdr_rel.sh_info, &fsym, (emachine1 == EM_PPC64),
+ elf) != 0) {
+ dt_strtab_destroy(strtab);
+ goto err;
+ }
+
+ if (fsym.st_name > data_str->d_size) {
+ dt_strtab_destroy(strtab);
+ goto err;
+ }
+
+ s = (char *)data_str->d_buf + fsym.st_name;
+
+ /*
+ * If this symbol isn't of type function, we've really
+ * driven off the rails or the object file is corrupt.
+ */
+ if (GELF_ST_TYPE(fsym.st_info) != STT_FUNC) {
+ dt_strtab_destroy(strtab);
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "expected %s to be of type function", s));
+ }
+
+ /*
+ * Aliases of weak symbols don't get a uniquifier.
+ */
+ if (GELF_ST_BIND(fsym.st_info) == STB_WEAK)
+ len = snprintf(NULL, 0, dt_weaksymfmt,
+ dt_symprefix, s) + 1;
+ else
+ len = snprintf(NULL, 0, dt_symfmt, dt_symprefix,
+ objkey, s) + 1;
+ if ((p = dt_alloc(dtp, len)) == NULL) {
+ dt_strtab_destroy(strtab);
+ goto err;
+ }
+ (void) snprintf(p, len, dt_symfmt, dt_symprefix,
+ objkey, s);
+
+ if (dt_strtab_index(strtab, p) == -1) {
+ nsym++;
+ (void) dt_strtab_insert(strtab, p);
+ }
+
+ dt_free(dtp, p);
+ }
+
+ /*
+ * If any probes were found, allocate the additional space for
+ * the symbol table and string table, copying the old data into
+ * the new buffers, and marking the buffers as dirty. We inject
+ * those newly allocated buffers into the libelf data
+ * structures, but are still responsible for freeing them once
+ * we're done with the elf handle.
+ */
+ if (nsym > 0) {
+ /*
+ * The first byte of the string table is reserved for
+ * the \0 entry.
+ */
+ len = dt_strtab_size(strtab) - 1;
+
+ assert(len > 0);
+ assert(dt_strtab_index(strtab, "") == 0);
+
+ dt_strtab_destroy(strtab);
+
+ if ((pair = dt_alloc(dtp, sizeof (*pair))) == NULL)
+ goto err;
+
+ if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size +
+ len)) == NULL) {
+ dt_free(dtp, pair);
+ goto err;
+ }
+
+ if ((pair->dlp_sym = dt_alloc(dtp, data_sym->d_size +
+ nsym * symsize)) == NULL) {
+ dt_free(dtp, pair->dlp_str);
+ dt_free(dtp, pair);
+ goto err;
+ }
+
+ pair->dlp_next = bufs;
+ bufs = pair;
+
+ bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size);
+ tmp = data_str->d_buf;
+ data_str->d_buf = pair->dlp_str;
+ pair->dlp_str = tmp;
+ data_str->d_size += len;
+ (void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY);
+
+ shdr_str.sh_size += len;
+ (void) gelf_update_shdr(scn_str, &shdr_str);
+
+ bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size);
+ tmp = data_sym->d_buf;
+ data_sym->d_buf = pair->dlp_sym;
+ pair->dlp_sym = tmp;
+ data_sym->d_size += nsym * symsize;
+ (void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY);
+
+ shdr_sym.sh_size += nsym * symsize;
+ (void) gelf_update_shdr(scn_sym, &shdr_sym);
+
+ osym = isym;
+ nsym += isym;
+ } else {
+ dt_strtab_destroy(strtab);
+ continue;
+ }
+
+ /*
+ * Now that the tables have been allocated, perform the
+ * modifications described above.
+ */
+ for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) {
+
+ if (shdr_rel.sh_type == SHT_RELA) {
+ if (gelf_getrela(data_rel, i, &rela) == NULL)
+ continue;
+ } else {
+ GElf_Rel rel;
+ if (gelf_getrel(data_rel, i, &rel) == NULL)
+ continue;
+ rela.r_offset = rel.r_offset;
+ rela.r_info = rel.r_info;
+ rela.r_addend = 0;
+ }
+
+ ndx = GELF_R_SYM(rela.r_info);
+
+ if (gelf_getsym(data_sym, ndx, &rsym) == NULL ||
+ rsym.st_name > data_str->d_size)
+ goto err;
+
+ s = (char *)data_str->d_buf + rsym.st_name;
+
+ if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0)
+ 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;
+
+ bcopy(s, pname, p - s);
+ pname[p - s] = '\0';
+
+ if (dt_symtab_lookup(data_sym, osym, isym,
+ rela.r_offset, shdr_rel.sh_info, &fsym,
+ (emachine1 == EM_PPC64), elf) == 0) {
+ if (fsym.st_name > data_str->d_size)
+ goto err;
+
+ r = s = (char *) data_str->d_buf + fsym.st_name;
+ assert(strstr(s, dt_symprefix) == s);
+ s = strchr(s, '.') + 1;
+ } else if (dt_symtab_lookup(data_sym, 0, osym,
+ rela.r_offset, shdr_rel.sh_info, &fsym,
+ (emachine1 == EM_PPC64), elf) == 0) {
+ u_int bind;
+
+ bind = GELF_ST_BIND(fsym.st_info) == STB_WEAK ?
+ STB_WEAK : STB_GLOBAL;
+
+ /*
+ * Emit an alias for the symbol. It needs to be
+ * non-preemptible so that .SUNW_dof relocations
+ * may be resolved at static link time. Aliases
+ * of weak symbols are given a non-unique name
+ * so that they may be merged by the linker.
+ */
+ dsym = fsym;
+ dsym.st_name = istr;
+ dsym.st_info = GELF_ST_INFO(bind, STT_FUNC);
+ dsym.st_other = GELF_ST_VISIBILITY(STV_HIDDEN);
+ (void) gelf_update_sym(data_sym, isym, &dsym);
+ r = (char *) data_str->d_buf + istr;
+ s = (char *) data_str->d_buf + fsym.st_name;
+ if (bind == STB_WEAK)
+ istr += sprintf(r, dt_weaksymfmt,
+ dt_symprefix, s);
+ else
+ istr += sprintf(r, dt_symfmt,
+ dt_symprefix, objkey, s);
+ istr++;
+ isym++;
+ assert(isym <= nsym);
+ } else
+ goto err;
+
+ if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) {
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "no such provider %s", pname));
+ }
+
+ if (strlcpy(probename, p + 3, sizeof (probename)) >=
+ sizeof (probename))
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "invalid probe name %s", probename));
+ (void) strhyphenate(probename);
+ if ((prp = dt_probe_lookup(pvp, probename)) == NULL)
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "no such probe %s", probename));
+
+ assert(fsym.st_value <= rela.r_offset);
+
+ off = rela.r_offset - fsym.st_value;
+ if (dt_modtext(dtp, data_tgt->d_buf, eprobe,
+ &rela, &off) != 0)
+ goto err;
+
+ 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"));
+ }
+#ifndef illumos
+ /*
+ * Our linker doesn't understand the SUNW_IGNORE ndx and
+ * will try to use this relocation when we build the
+ * final executable. Since we are done processing this
+ * relocation, mark it as inexistant and let libelf
+ * remove it from the file.
+ * If this wasn't done, we would have garbage added to
+ * the executable file as the symbol is going to be
+ * change from UND to ABS.
+ */
+ if (shdr_rel.sh_type == SHT_RELA) {
+ rela.r_offset = 0;
+ rela.r_info = 0;
+ rela.r_addend = 0;
+ (void) gelf_update_rela(data_rel, i, &rela);
+ } else {
+ GElf_Rel rel;
+ rel.r_offset = 0;
+ rel.r_info = 0;
+ (void) gelf_update_rel(data_rel, i, &rel);
+ }
+#endif
+
+ mod = 1;
+ (void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY);
+
+ /*
+ * This symbol may already have been marked to
+ * be ignored by another relocation referencing
+ * the same symbol or if this object file has
+ * already been processed by an earlier link
+ * invocation.
+ */
+#ifndef illumos
+#define SHN_SUNW_IGNORE SHN_ABS
+#endif
+ if (rsym.st_shndx != SHN_SUNW_IGNORE) {
+ rsym.st_shndx = SHN_SUNW_IGNORE;
+ (void) gelf_update_sym(data_sym, ndx, &rsym);
+ }
+ }
+ }
+
+ if (mod && elf_update(elf, ELF_C_WRITE) == -1)
+ goto err;
+
+ (void) elf_end(elf);
+ (void) close(fd);
+
+ while ((pair = bufs) != NULL) {
+ bufs = pair->dlp_next;
+ dt_free(dtp, pair->dlp_str);
+ dt_free(dtp, pair->dlp_sym);
+ dt_free(dtp, pair);
+ }
+
+ return (0);
+
+err:
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "an error was encountered while processing %s", obj));
+}
+
+int
+dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
+ const char *file, int objc, char *const objv[])
+{
+#ifndef illumos
+ char tfile[PATH_MAX];
+#endif
+ char drti[PATH_MAX];
+ dof_hdr_t *dof;
+ int fd, status, i, cur;
+ char *cmd, tmp;
+ size_t len;
+ int eprobes = 0, ret = 0;
+
+#ifndef illumos
+ if (access(file, R_OK) == 0) {
+ fprintf(stderr, "dtrace: target object (%s) already exists. "
+ "Please remove the target\ndtrace: object and rebuild all "
+ "the source objects if you wish to run the DTrace\n"
+ "dtrace: linking process again\n", file);
+ /*
+ * Several build infrastructures run DTrace twice (e.g.
+ * postgres) and we don't want the build to fail. Return
+ * 0 here since this isn't really a fatal error.
+ */
+ return (0);
+ }
+#endif
+
+ /*
+ * A NULL program indicates a special use in which we just link
+ * together a bunch of object files specified in objv and then
+ * unlink(2) those object files.
+ */
+ if (pgp == NULL) {
+ const char *fmt = "%s -o %s -r";
+
+ len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1;
+
+ for (i = 0; i < objc; i++)
+ len += strlen(objv[i]) + 1;
+
+ cmd = alloca(len);
+
+ cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file);
+
+ for (i = 0; i < objc; i++)
+ cur += snprintf(cmd + cur, len - cur, " %s", objv[i]);
+
+ if ((status = system(cmd)) == -1) {
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to run %s: %s", dtp->dt_ld_path,
+ strerror(errno)));
+ }
+
+ if (WIFSIGNALED(status)) {
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to link %s: %s failed due to signal %d",
+ file, dtp->dt_ld_path, WTERMSIG(status)));
+ }
+
+ if (WEXITSTATUS(status) != 0) {
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to link %s: %s exited with status %d\n",
+ file, dtp->dt_ld_path, WEXITSTATUS(status)));
+ }
+
+ for (i = 0; i < objc; i++) {
+ if (strcmp(objv[i], file) != 0)
+ (void) unlink(objv[i]);
+ }
+
+ return (0);
+ }
+
+ for (i = 0; i < objc; i++) {
+ 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 */
+
+#ifdef illumos
+ /*
+ * Create a temporary file and then unlink it if we're going to
+ * combine it with drti.o later. We can still refer to it in child
+ * processes as /dev/fd/<fd>.
+ */
+ if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) {
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to open %s: %s", file, strerror(errno)));
+ }
+#else
+ snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file);
+ if ((fd = mkostemp(tfile, O_CLOEXEC)) == -1)
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to create temporary file %s: %s",
+ tfile, strerror(errno)));
+#endif
+
+ /*
+ * If -xlinktype=DOF has been selected, just write out the DOF.
+ * Otherwise proceed to the default of generating and linking ELF.
+ */
+ switch (dtp->dt_linktype) {
+ case DT_LTYP_DOF:
+ if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz)
+ ret = errno;
+
+ if (close(fd) != 0 && ret == 0)
+ ret = errno;
+
+ if (ret != 0) {
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to write %s: %s", file, strerror(ret)));
+ }
+
+ return (0);
+
+ case DT_LTYP_ELF:
+ break; /* fall through to the rest of dtrace_program_link() */
+
+ default:
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "invalid link type %u\n", dtp->dt_linktype));
+ }
+
+
+#ifdef illumos
+ if (!dtp->dt_lazyload)
+ (void) unlink(file);
+#endif
+
+ if (dtp->dt_oflags & DTRACE_O_LP64)
+ status = dump_elf64(dtp, dof, fd);
+ else
+ status = dump_elf32(dtp, dof, fd);
+
+#ifdef illumos
+ if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) {
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to write %s: %s", file, strerror(errno)));
+ }
+#else
+ if (status != 0)
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to write %s: %s", tfile,
+ strerror(dtrace_errno(dtp))));
+#endif
+
+ if (!dtp->dt_lazyload) {
+#ifdef illumos
+ const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s";
+
+ if (dtp->dt_oflags & DTRACE_O_LP64) {
+ (void) snprintf(drti, sizeof (drti),
+ "%s/64/drti.o", _dtrace_libdir);
+ } else {
+ (void) snprintf(drti, sizeof (drti),
+ "%s/drti.o", _dtrace_libdir);
+ }
+
+ len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, fd,
+ drti) + 1;
+
+ cmd = alloca(len);
+
+ (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti);
+#else
+ const char *fmt = "%s -o %s -r %s %s";
+ dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
+
+ (void) snprintf(drti, sizeof (drti), "%s/drti.o", dp->dir_path);
+
+ len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
+ drti) + 1;
+
+ cmd = alloca(len);
+
+ (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile,
+ drti);
+#endif
+ if ((status = system(cmd)) == -1) {
+ ret = dt_link_error(dtp, NULL, fd, NULL,
+ "failed to run %s: %s", dtp->dt_ld_path,
+ strerror(errno));
+ goto done;
+ }
+
+ if (WIFSIGNALED(status)) {
+ ret = dt_link_error(dtp, NULL, fd, NULL,
+ "failed to link %s: %s failed due to signal %d",
+ file, dtp->dt_ld_path, WTERMSIG(status));
+ goto done;
+ }
+
+ if (WEXITSTATUS(status) != 0) {
+ ret = dt_link_error(dtp, NULL, fd, NULL,
+ "failed to link %s: %s exited with status %d\n",
+ file, dtp->dt_ld_path, WEXITSTATUS(status));
+ goto done;
+ }
+ (void) close(fd); /* release temporary file */
+
+#ifdef __FreeBSD__
+ /*
+ * Now that we've linked drti.o, reduce the global __SUNW_dof
+ * symbol to a local symbol. This is needed to so that multiple
+ * generated object files (for different providers, for
+ * instance) can be linked together. This is accomplished using
+ * the -Blocal flag with Sun's linker, but GNU ld doesn't appear
+ * to have an equivalent option.
+ */
+ asprintf(&cmd, "%s --localize-hidden %s", dtp->dt_objcopy_path,
+ file);
+ if ((status = system(cmd)) == -1) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to run %s: %s", dtp->dt_objcopy_path,
+ strerror(errno));
+ free(cmd);
+ goto done;
+ }
+ free(cmd);
+
+ if (WIFSIGNALED(status)) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to link %s: %s failed due to signal %d",
+ file, dtp->dt_objcopy_path, WTERMSIG(status));
+ goto done;
+ }
+
+ if (WEXITSTATUS(status) != 0) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to link %s: %s exited with status %d\n",
+ file, dtp->dt_objcopy_path, WEXITSTATUS(status));
+ goto done;
+ }
+#endif
+ } else {
+#ifdef __FreeBSD__
+ if (rename(tfile, file) != 0) {
+ ret = dt_link_error(dtp, NULL, fd, NULL,
+ "failed to rename %s to %s: %s", tfile, file,
+ strerror(errno));
+ goto done;
+ }
+#endif
+ (void) close(fd);
+ }
+
+done:
+ dtrace_dof_destroy(dtp, dof);
+
+#ifdef __FreeBSD__
+ if (!dtp->dt_lazyload)
+ (void) unlink(tfile);
+#endif
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.c
new file mode 100644
index 000000000000..32279e9bd274
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.c
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Simple doubly-linked list implementation. This implementation assumes that
+ * each list element contains an embedded dt_list_t (previous and next
+ * pointers), which is typically the first member of the element struct.
+ * An additional dt_list_t is used to store the head (dl_next) and tail
+ * (dl_prev) pointers. The current head and tail list elements have their
+ * previous and next pointers set to NULL, respectively.
+ */
+
+#include <unistd.h>
+#include <assert.h>
+#include <dt_list.h>
+
+void
+dt_list_append(dt_list_t *dlp, void *new)
+{
+ dt_list_t *p = dlp->dl_prev; /* p = tail list element */
+ dt_list_t *q = new; /* q = new list element */
+
+ dlp->dl_prev = q;
+ q->dl_prev = p;
+ q->dl_next = NULL;
+
+ if (p != NULL) {
+ assert(p->dl_next == NULL);
+ p->dl_next = q;
+ } else {
+ assert(dlp->dl_next == NULL);
+ dlp->dl_next = q;
+ }
+}
+
+void
+dt_list_prepend(dt_list_t *dlp, void *new)
+{
+ dt_list_t *p = new; /* p = new list element */
+ dt_list_t *q = dlp->dl_next; /* q = head list element */
+
+ dlp->dl_next = p;
+ p->dl_prev = NULL;
+ p->dl_next = q;
+
+ if (q != NULL) {
+ assert(q->dl_prev == NULL);
+ q->dl_prev = p;
+ } else {
+ assert(dlp->dl_prev == NULL);
+ dlp->dl_prev = p;
+ }
+}
+
+void
+dt_list_insert(dt_list_t *dlp, void *after_me, void *new)
+{
+ dt_list_t *p = after_me;
+ dt_list_t *q = new;
+
+ if (p == NULL || p->dl_next == NULL) {
+ dt_list_append(dlp, new);
+ return;
+ }
+
+ q->dl_next = p->dl_next;
+ q->dl_prev = p;
+ p->dl_next = q;
+ q->dl_next->dl_prev = q;
+}
+
+void
+dt_list_delete(dt_list_t *dlp, void *existing)
+{
+ dt_list_t *p = existing;
+
+ if (p->dl_prev != NULL)
+ p->dl_prev->dl_next = p->dl_next;
+ else
+ dlp->dl_next = p->dl_next;
+
+ if (p->dl_next != NULL)
+ p->dl_next->dl_prev = p->dl_prev;
+ else
+ dlp->dl_prev = p->dl_prev;
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.h
new file mode 100644
index 000000000000..348d18aa399d
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_LIST_H
+#define _DT_LIST_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct dt_list {
+ struct dt_list *dl_prev;
+ struct dt_list *dl_next;
+} dt_list_t;
+
+#define dt_list_prev(elem) ((void *)(((dt_list_t *)(elem))->dl_prev))
+#define dt_list_next(elem) ((void *)(((dt_list_t *)(elem))->dl_next))
+
+extern void dt_list_append(dt_list_t *, void *);
+extern void dt_list_prepend(dt_list_t *, void *);
+extern void dt_list_insert(dt_list_t *, void *, void *);
+extern void dt_list_delete(dt_list_t *, void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_LIST_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c
new file mode 100644
index 000000000000..20081edfe75a
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c
@@ -0,0 +1,493 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <dt_impl.h>
+#include <dt_printf.h>
+
+static int
+dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max)
+{
+ int maxformat, rval;
+ dtrace_fmtdesc_t fmt;
+ void *result;
+
+ if (rec->dtrd_format == 0)
+ return (0);
+
+ if (rec->dtrd_format <= *max &&
+ (*data)[rec->dtrd_format - 1] != NULL) {
+ return (0);
+ }
+
+ bzero(&fmt, sizeof (fmt));
+ fmt.dtfd_format = rec->dtrd_format;
+ fmt.dtfd_string = NULL;
+ fmt.dtfd_length = 0;
+
+ if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
+ rval = dt_set_errno(dtp, errno);
+ free(fmt.dtfd_string);
+ return (rval);
+ }
+
+ while (rec->dtrd_format > (maxformat = *max)) {
+ int new_max = maxformat ? (maxformat << 1) : 1;
+ size_t nsize = new_max * sizeof (void *);
+ size_t osize = maxformat * sizeof (void *);
+ void **new_data = dt_zalloc(dtp, nsize);
+
+ if (new_data == NULL) {
+ dt_free(dtp, fmt.dtfd_string);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ bcopy(*data, new_data, osize);
+ free(*data);
+
+ *data = new_data;
+ *max = new_max;
+ }
+
+ switch (rec->dtrd_action) {
+ case DTRACEACT_DIFEXPR:
+ result = fmt.dtfd_string;
+ break;
+ case DTRACEACT_PRINTA:
+ result = dtrace_printa_create(dtp, fmt.dtfd_string);
+ dt_free(dtp, fmt.dtfd_string);
+ break;
+ default:
+ result = dtrace_printf_create(dtp, fmt.dtfd_string);
+ dt_free(dtp, fmt.dtfd_string);
+ break;
+ }
+
+ if (result == NULL)
+ return (-1);
+
+ (*data)[rec->dtrd_format - 1] = result;
+
+ return (0);
+}
+
+static int
+dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
+{
+ dtrace_id_t max;
+ int rval, i;
+ dtrace_eprobedesc_t *enabled, *nenabled;
+ dtrace_probedesc_t *probe;
+
+ while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) {
+ dtrace_id_t new_max = max ? (max << 1) : 1;
+ size_t nsize = new_max * sizeof (void *);
+ dtrace_probedesc_t **new_pdesc;
+ dtrace_eprobedesc_t **new_edesc;
+
+ if ((new_pdesc = malloc(nsize)) == NULL ||
+ (new_edesc = malloc(nsize)) == NULL) {
+ free(new_pdesc);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ bzero(new_pdesc, nsize);
+ bzero(new_edesc, nsize);
+
+ if (dtp->dt_pdesc != NULL) {
+ size_t osize = max * sizeof (void *);
+
+ bcopy(dtp->dt_pdesc, new_pdesc, osize);
+ free(dtp->dt_pdesc);
+
+ bcopy(dtp->dt_edesc, new_edesc, osize);
+ free(dtp->dt_edesc);
+ }
+
+ dtp->dt_pdesc = new_pdesc;
+ dtp->dt_edesc = new_edesc;
+ dtp->dt_maxprobe = new_max;
+ }
+
+ if (dtp->dt_pdesc[id] != NULL)
+ return (0);
+
+ if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ bzero(enabled, sizeof (dtrace_eprobedesc_t));
+ enabled->dtepd_epid = id;
+ enabled->dtepd_nrecs = 1;
+
+#ifdef illumos
+ if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
+#else
+ if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {
+#endif
+ rval = dt_set_errno(dtp, errno);
+ free(enabled);
+ return (rval);
+ }
+
+ if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
+ /*
+ * There must be more than one action. Allocate the
+ * appropriate amount of space and try again.
+ */
+ if ((nenabled =
+ malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
+ bcopy(enabled, nenabled, sizeof (*enabled));
+
+ free(enabled);
+
+ if ((enabled = nenabled) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+#ifdef illumos
+ rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
+#else
+ rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);
+#endif
+
+ if (rval == -1) {
+ rval = dt_set_errno(dtp, errno);
+ free(enabled);
+ return (rval);
+ }
+ }
+
+ if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
+ free(enabled);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ probe->dtpd_id = enabled->dtepd_probeid;
+
+ if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
+ rval = dt_set_errno(dtp, errno);
+ goto err;
+ }
+
+ for (i = 0; i < enabled->dtepd_nrecs; i++) {
+ dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
+
+ if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {
+ if (dt_strdata_add(dtp, rec, &dtp->dt_formats,
+ &dtp->dt_maxformat) != 0) {
+ rval = -1;
+ goto err;
+ }
+ } else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {
+ if (dt_strdata_add(dtp, rec,
+ (void ***)&dtp->dt_strdata,
+ &dtp->dt_maxstrdata) != 0) {
+ rval = -1;
+ goto err;
+ }
+ }
+
+ }
+
+ dtp->dt_pdesc[id] = probe;
+ dtp->dt_edesc[id] = enabled;
+
+ return (0);
+
+err:
+ /*
+ * If we failed, free our allocated probes. Note that if we failed
+ * while allocating formats, we aren't going to free formats that
+ * we have already allocated. This is okay; these formats are
+ * hanging off of dt_formats and will therefore not be leaked.
+ */
+ free(enabled);
+ free(probe);
+ return (rval);
+}
+
+int
+dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
+ dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
+{
+ int rval;
+
+ if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
+ if ((rval = dt_epid_add(dtp, epid)) != 0)
+ return (rval);
+ }
+
+ assert(epid < dtp->dt_maxprobe);
+ assert(dtp->dt_edesc[epid] != NULL);
+ assert(dtp->dt_pdesc[epid] != NULL);
+ *epdp = dtp->dt_edesc[epid];
+ *pdp = dtp->dt_pdesc[epid];
+
+ return (0);
+}
+
+void
+dt_epid_destroy(dtrace_hdl_t *dtp)
+{
+ size_t i;
+
+ assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&
+ dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
+ dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));
+
+ if (dtp->dt_pdesc == NULL)
+ return;
+
+ for (i = 0; i < dtp->dt_maxprobe; i++) {
+ if (dtp->dt_edesc[i] == NULL) {
+ assert(dtp->dt_pdesc[i] == NULL);
+ continue;
+ }
+
+ assert(dtp->dt_pdesc[i] != NULL);
+ free(dtp->dt_edesc[i]);
+ free(dtp->dt_pdesc[i]);
+ }
+
+ free(dtp->dt_pdesc);
+ dtp->dt_pdesc = NULL;
+
+ free(dtp->dt_edesc);
+ dtp->dt_edesc = NULL;
+ dtp->dt_maxprobe = 0;
+}
+
+void *
+dt_format_lookup(dtrace_hdl_t *dtp, int format)
+{
+ if (format == 0 || format > dtp->dt_maxformat)
+ return (NULL);
+
+ if (dtp->dt_formats == NULL)
+ return (NULL);
+
+ return (dtp->dt_formats[format - 1]);
+}
+
+void
+dt_format_destroy(dtrace_hdl_t *dtp)
+{
+ int i;
+
+ for (i = 0; i < dtp->dt_maxformat; i++) {
+ if (dtp->dt_formats[i] != NULL)
+ dt_printf_destroy(dtp->dt_formats[i]);
+ }
+
+ free(dtp->dt_formats);
+ dtp->dt_formats = NULL;
+}
+
+static int
+dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
+{
+ dtrace_id_t max;
+ dtrace_epid_t epid;
+ int rval;
+
+ while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
+ dtrace_id_t new_max = max ? (max << 1) : 1;
+ size_t nsize = new_max * sizeof (void *);
+ dtrace_aggdesc_t **new_aggdesc;
+
+ if ((new_aggdesc = malloc(nsize)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ bzero(new_aggdesc, nsize);
+
+ if (dtp->dt_aggdesc != NULL) {
+ bcopy(dtp->dt_aggdesc, new_aggdesc,
+ max * sizeof (void *));
+ free(dtp->dt_aggdesc);
+ }
+
+ dtp->dt_aggdesc = new_aggdesc;
+ dtp->dt_maxagg = new_max;
+ }
+
+ if (dtp->dt_aggdesc[id] == NULL) {
+ dtrace_aggdesc_t *agg, *nagg;
+
+ if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ bzero(agg, sizeof (dtrace_aggdesc_t));
+ agg->dtagd_id = id;
+ agg->dtagd_nrecs = 1;
+
+#ifdef illumos
+ if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
+#else
+ if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {
+#endif
+ rval = dt_set_errno(dtp, errno);
+ free(agg);
+ return (rval);
+ }
+
+ if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
+ /*
+ * There must be more than one action. Allocate the
+ * appropriate amount of space and try again.
+ */
+ if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
+ bcopy(agg, nagg, sizeof (*agg));
+
+ free(agg);
+
+ if ((agg = nagg) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+#ifdef illumos
+ rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
+#else
+ rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);
+#endif
+
+ if (rval == -1) {
+ rval = dt_set_errno(dtp, errno);
+ free(agg);
+ return (rval);
+ }
+ }
+
+ /*
+ * If we have a uarg, it's a pointer to the compiler-generated
+ * statement; we'll use this value to get the name and
+ * compiler-generated variable ID for the aggregation. If
+ * we're grabbing an anonymous enabling, this pointer value
+ * is obviously meaningless -- and in this case, we can't
+ * provide the compiler-generated aggregation information.
+ */
+ if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&
+ agg->dtagd_rec[0].dtrd_uarg != 0) {
+ dtrace_stmtdesc_t *sdp;
+ dt_ident_t *aid;
+
+ sdp = (dtrace_stmtdesc_t *)(uintptr_t)
+ agg->dtagd_rec[0].dtrd_uarg;
+ aid = sdp->dtsd_aggdata;
+ agg->dtagd_name = aid->di_name;
+ agg->dtagd_varid = aid->di_id;
+ } else {
+ agg->dtagd_varid = DTRACE_AGGVARIDNONE;
+ }
+
+ if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||
+ dtp->dt_pdesc[epid] == NULL) {
+ if ((rval = dt_epid_add(dtp, epid)) != 0) {
+ free(agg);
+ return (rval);
+ }
+ }
+
+ dtp->dt_aggdesc[id] = agg;
+ }
+
+ return (0);
+}
+
+int
+dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,
+ dtrace_aggdesc_t **adp)
+{
+ int rval;
+
+ if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {
+ if ((rval = dt_aggid_add(dtp, aggid)) != 0)
+ return (rval);
+ }
+
+ assert(aggid < dtp->dt_maxagg);
+ assert(dtp->dt_aggdesc[aggid] != NULL);
+ *adp = dtp->dt_aggdesc[aggid];
+
+ return (0);
+}
+
+void
+dt_aggid_destroy(dtrace_hdl_t *dtp)
+{
+ size_t i;
+
+ assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) ||
+ (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0));
+
+ if (dtp->dt_aggdesc == NULL)
+ return;
+
+ for (i = 0; i < dtp->dt_maxagg; i++) {
+ if (dtp->dt_aggdesc[i] != NULL)
+ free(dtp->dt_aggdesc[i]);
+ }
+
+ free(dtp->dt_aggdesc);
+ dtp->dt_aggdesc = NULL;
+ dtp->dt_maxagg = 0;
+}
+
+const char *
+dt_strdata_lookup(dtrace_hdl_t *dtp, int idx)
+{
+ if (idx == 0 || idx > dtp->dt_maxstrdata)
+ return (NULL);
+
+ if (dtp->dt_strdata == NULL)
+ return (NULL);
+
+ return (dtp->dt_strdata[idx - 1]);
+}
+
+void
+dt_strdata_destroy(dtrace_hdl_t *dtp)
+{
+ int i;
+
+ for (i = 0; i < dtp->dt_maxstrdata; i++) {
+ free(dtp->dt_strdata[i]);
+ }
+
+ free(dtp->dt_strdata);
+ dtp->dt_strdata = NULL;
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
new file mode 100644
index 000000000000..b9408944f8c5
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
@@ -0,0 +1,1782 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2016, Pedro Giffuni. All rights reserved.
+ */
+
+#include <sys/types.h>
+#ifdef illumos
+#include <sys/modctl.h>
+#include <sys/kobj.h>
+#include <sys/kobj_impl.h>
+#include <sys/sysmacros.h>
+#include <sys/elf.h>
+#include <sys/task.h>
+#else
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/stat.h>
+#endif
+
+#include <unistd.h>
+#ifdef illumos
+#include <project.h>
+#endif
+#include <strings.h>
+#include <stdlib.h>
+#include <libelf.h>
+#include <limits.h>
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#ifndef illumos
+#include <fcntl.h>
+#include <libproc_compat.h>
+#endif
+
+#include <dt_strtab.h>
+#include <dt_module.h>
+#include <dt_impl.h>
+
+static const char *dt_module_strtab; /* active strtab for qsort callbacks */
+
+static void
+dt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id)
+{
+ dt_sym_t *dsp = &dmp->dm_symchains[dmp->dm_symfree];
+ uint_t h;
+
+ assert(dmp->dm_symfree < dmp->dm_nsymelems + 1);
+
+ dsp->ds_symid = id;
+ h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
+ dsp->ds_next = dmp->dm_symbuckets[h];
+ dmp->dm_symbuckets[h] = dmp->dm_symfree++;
+}
+
+static uint_t
+dt_module_syminit32(dt_module_t *dmp)
+{
+#if STT_NUM != (STT_TLS + 1)
+#error "STT_NUM has grown. update dt_module_syminit32()"
+#endif
+
+ Elf32_Sym *sym = dmp->dm_symtab.cts_data;
+ const char *base = dmp->dm_strtab.cts_data;
+ size_t ss_size = dmp->dm_strtab.cts_size;
+ uint_t i, n = dmp->dm_nsymelems;
+ uint_t asrsv = 0;
+
+#if defined(__FreeBSD__)
+ GElf_Ehdr ehdr;
+ int is_elf_obj;
+
+ gelf_getehdr(dmp->dm_elf, &ehdr);
+ is_elf_obj = (ehdr.e_type == ET_REL);
+#endif
+
+ for (i = 0; i < n; i++, sym++) {
+ const char *name = base + sym->st_name;
+ uchar_t type = ELF32_ST_TYPE(sym->st_info);
+
+ if (type >= STT_NUM || type == STT_SECTION)
+ continue; /* skip sections and unknown types */
+
+ if (sym->st_name == 0 || sym->st_name >= ss_size)
+ continue; /* skip null or invalid names */
+
+ if (sym->st_value != 0 &&
+ (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
+ asrsv++; /* reserve space in the address map */
+
+#if defined(__FreeBSD__)
+ sym->st_value += (Elf_Addr) dmp->dm_reloc_offset;
+ if (is_elf_obj && sym->st_shndx != SHN_UNDEF &&
+ sym->st_shndx < ehdr.e_shnum)
+ sym->st_value +=
+ dmp->dm_sec_offsets[sym->st_shndx];
+#endif
+ }
+
+ dt_module_symhash_insert(dmp, name, i);
+ }
+
+ return (asrsv);
+}
+
+static uint_t
+dt_module_syminit64(dt_module_t *dmp)
+{
+#if STT_NUM != (STT_TLS + 1)
+#error "STT_NUM has grown. update dt_module_syminit64()"
+#endif
+
+ Elf64_Sym *sym = dmp->dm_symtab.cts_data;
+ const char *base = dmp->dm_strtab.cts_data;
+ size_t ss_size = dmp->dm_strtab.cts_size;
+ uint_t i, n = dmp->dm_nsymelems;
+ uint_t asrsv = 0;
+
+#if defined(__FreeBSD__)
+ GElf_Ehdr ehdr;
+ int is_elf_obj;
+
+ gelf_getehdr(dmp->dm_elf, &ehdr);
+ is_elf_obj = (ehdr.e_type == ET_REL);
+#endif
+
+ for (i = 0; i < n; i++, sym++) {
+ const char *name = base + sym->st_name;
+ uchar_t type = ELF64_ST_TYPE(sym->st_info);
+
+ if (type >= STT_NUM || type == STT_SECTION)
+ continue; /* skip sections and unknown types */
+
+ if (sym->st_name == 0 || sym->st_name >= ss_size)
+ continue; /* skip null or invalid names */
+
+ if (sym->st_value != 0 &&
+ (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
+ asrsv++; /* reserve space in the address map */
+#if defined(__FreeBSD__)
+ sym->st_value += (Elf_Addr) dmp->dm_reloc_offset;
+ if (is_elf_obj && sym->st_shndx != SHN_UNDEF &&
+ sym->st_shndx < ehdr.e_shnum)
+ sym->st_value +=
+ dmp->dm_sec_offsets[sym->st_shndx];
+#endif
+ }
+
+ dt_module_symhash_insert(dmp, name, i);
+ }
+
+ return (asrsv);
+}
+
+/*
+ * Sort comparison function for 32-bit symbol address-to-name lookups. We sort
+ * symbols by value. If values are equal, we prefer the symbol that is
+ * non-zero sized, typed, not weak, or lexically first, in that order.
+ */
+static int
+dt_module_symcomp32(const void *lp, const void *rp)
+{
+ Elf32_Sym *lhs = *((Elf32_Sym **)lp);
+ Elf32_Sym *rhs = *((Elf32_Sym **)rp);
+
+ if (lhs->st_value != rhs->st_value)
+ return (lhs->st_value > rhs->st_value ? 1 : -1);
+
+ if ((lhs->st_size == 0) != (rhs->st_size == 0))
+ return (lhs->st_size == 0 ? 1 : -1);
+
+ if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
+ (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE))
+ return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
+
+ if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) !=
+ (ELF32_ST_BIND(rhs->st_info) == STB_WEAK))
+ return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
+
+ return (strcmp(dt_module_strtab + lhs->st_name,
+ dt_module_strtab + rhs->st_name));
+}
+
+/*
+ * Sort comparison function for 64-bit symbol address-to-name lookups. We sort
+ * symbols by value. If values are equal, we prefer the symbol that is
+ * non-zero sized, typed, not weak, or lexically first, in that order.
+ */
+static int
+dt_module_symcomp64(const void *lp, const void *rp)
+{
+ Elf64_Sym *lhs = *((Elf64_Sym **)lp);
+ Elf64_Sym *rhs = *((Elf64_Sym **)rp);
+
+ if (lhs->st_value != rhs->st_value)
+ return (lhs->st_value > rhs->st_value ? 1 : -1);
+
+ if ((lhs->st_size == 0) != (rhs->st_size == 0))
+ return (lhs->st_size == 0 ? 1 : -1);
+
+ if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
+ (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE))
+ return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
+
+ if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) !=
+ (ELF64_ST_BIND(rhs->st_info) == STB_WEAK))
+ return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
+
+ return (strcmp(dt_module_strtab + lhs->st_name,
+ dt_module_strtab + rhs->st_name));
+}
+
+static void
+dt_module_symsort32(dt_module_t *dmp)
+{
+ Elf32_Sym *symtab = (Elf32_Sym *)dmp->dm_symtab.cts_data;
+ Elf32_Sym **sympp = (Elf32_Sym **)dmp->dm_asmap;
+ const dt_sym_t *dsp = dmp->dm_symchains + 1;
+ uint_t i, n = dmp->dm_symfree;
+
+ for (i = 1; i < n; i++, dsp++) {
+ Elf32_Sym *sym = symtab + dsp->ds_symid;
+ if (sym->st_value != 0 &&
+ (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
+ *sympp++ = sym;
+ }
+
+ dmp->dm_aslen = (uint_t)(sympp - (Elf32_Sym **)dmp->dm_asmap);
+ assert(dmp->dm_aslen <= dmp->dm_asrsv);
+
+ dt_module_strtab = dmp->dm_strtab.cts_data;
+ qsort(dmp->dm_asmap, dmp->dm_aslen,
+ sizeof (Elf32_Sym *), dt_module_symcomp32);
+ dt_module_strtab = NULL;
+}
+
+static void
+dt_module_symsort64(dt_module_t *dmp)
+{
+ Elf64_Sym *symtab = (Elf64_Sym *)dmp->dm_symtab.cts_data;
+ Elf64_Sym **sympp = (Elf64_Sym **)dmp->dm_asmap;
+ const dt_sym_t *dsp = dmp->dm_symchains + 1;
+ uint_t i, n = dmp->dm_symfree;
+
+ for (i = 1; i < n; i++, dsp++) {
+ Elf64_Sym *sym = symtab + dsp->ds_symid;
+ if (sym->st_value != 0 &&
+ (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
+ *sympp++ = sym;
+ }
+
+ dmp->dm_aslen = (uint_t)(sympp - (Elf64_Sym **)dmp->dm_asmap);
+ assert(dmp->dm_aslen <= dmp->dm_asrsv);
+
+ dt_module_strtab = dmp->dm_strtab.cts_data;
+ qsort(dmp->dm_asmap, dmp->dm_aslen,
+ sizeof (Elf64_Sym *), dt_module_symcomp64);
+ dt_module_strtab = NULL;
+}
+
+static GElf_Sym *
+dt_module_symgelf32(const Elf32_Sym *src, GElf_Sym *dst)
+{
+ if (dst != NULL) {
+ dst->st_name = src->st_name;
+ dst->st_info = src->st_info;
+ dst->st_other = src->st_other;
+ dst->st_shndx = src->st_shndx;
+ dst->st_value = src->st_value;
+ dst->st_size = src->st_size;
+ }
+
+ return (dst);
+}
+
+static GElf_Sym *
+dt_module_symgelf64(const Elf64_Sym *src, GElf_Sym *dst)
+{
+ if (dst != NULL)
+ bcopy(src, dst, sizeof (GElf_Sym));
+
+ return (dst);
+}
+
+static GElf_Sym *
+dt_module_symname32(dt_module_t *dmp, const char *name,
+ GElf_Sym *symp, uint_t *idp)
+{
+ const Elf32_Sym *symtab = dmp->dm_symtab.cts_data;
+ const char *strtab = dmp->dm_strtab.cts_data;
+
+ const Elf32_Sym *sym;
+ const dt_sym_t *dsp;
+ uint_t i, h;
+
+ if (dmp->dm_nsymelems == 0)
+ return (NULL);
+
+ h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
+
+ for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) {
+ dsp = &dmp->dm_symchains[i];
+ sym = symtab + dsp->ds_symid;
+
+ if (strcmp(name, strtab + sym->st_name) == 0) {
+ if (idp != NULL)
+ *idp = dsp->ds_symid;
+ return (dt_module_symgelf32(sym, symp));
+ }
+ }
+
+ return (NULL);
+}
+
+static GElf_Sym *
+dt_module_symname64(dt_module_t *dmp, const char *name,
+ GElf_Sym *symp, uint_t *idp)
+{
+ const Elf64_Sym *symtab = dmp->dm_symtab.cts_data;
+ const char *strtab = dmp->dm_strtab.cts_data;
+
+ const Elf64_Sym *sym;
+ const dt_sym_t *dsp;
+ uint_t i, h;
+
+ if (dmp->dm_nsymelems == 0)
+ return (NULL);
+
+ h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
+
+ for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) {
+ dsp = &dmp->dm_symchains[i];
+ sym = symtab + dsp->ds_symid;
+
+ if (strcmp(name, strtab + sym->st_name) == 0) {
+ if (idp != NULL)
+ *idp = dsp->ds_symid;
+ return (dt_module_symgelf64(sym, symp));
+ }
+ }
+
+ return (NULL);
+}
+
+static GElf_Sym *
+dt_module_symaddr32(dt_module_t *dmp, GElf_Addr addr,
+ GElf_Sym *symp, uint_t *idp)
+{
+ const Elf32_Sym **asmap = (const Elf32_Sym **)dmp->dm_asmap;
+ const Elf32_Sym *symtab = dmp->dm_symtab.cts_data;
+ const Elf32_Sym *sym;
+
+ uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1;
+ Elf32_Addr v;
+
+ if (dmp->dm_aslen == 0)
+ return (NULL);
+
+ while (hi - lo > 1) {
+ mid = (lo + hi) / 2;
+ if (addr >= asmap[mid]->st_value)
+ lo = mid;
+ else
+ hi = mid;
+ }
+
+ i = addr < asmap[hi]->st_value ? lo : hi;
+ sym = asmap[i];
+ v = sym->st_value;
+
+ /*
+ * If the previous entry has the same value, improve our choice. The
+ * order of equal-valued symbols is determined by the comparison func.
+ */
+ while (i-- != 0 && asmap[i]->st_value == v)
+ sym = asmap[i];
+
+ if (addr - sym->st_value < MAX(sym->st_size, 1)) {
+ if (idp != NULL)
+ *idp = (uint_t)(sym - symtab);
+ return (dt_module_symgelf32(sym, symp));
+ }
+
+ return (NULL);
+}
+
+static GElf_Sym *
+dt_module_symaddr64(dt_module_t *dmp, GElf_Addr addr,
+ GElf_Sym *symp, uint_t *idp)
+{
+ const Elf64_Sym **asmap = (const Elf64_Sym **)dmp->dm_asmap;
+ const Elf64_Sym *symtab = dmp->dm_symtab.cts_data;
+ const Elf64_Sym *sym;
+
+ uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1;
+ Elf64_Addr v;
+
+ if (dmp->dm_aslen == 0)
+ return (NULL);
+
+ while (hi - lo > 1) {
+ mid = (lo + hi) / 2;
+ if (addr >= asmap[mid]->st_value)
+ lo = mid;
+ else
+ hi = mid;
+ }
+
+ i = addr < asmap[hi]->st_value ? lo : hi;
+ sym = asmap[i];
+ v = sym->st_value;
+
+ /*
+ * If the previous entry has the same value, improve our choice. The
+ * order of equal-valued symbols is determined by the comparison func.
+ */
+ while (i-- != 0 && asmap[i]->st_value == v)
+ sym = asmap[i];
+
+ if (addr - sym->st_value < MAX(sym->st_size, 1)) {
+ if (idp != NULL)
+ *idp = (uint_t)(sym - symtab);
+ return (dt_module_symgelf64(sym, symp));
+ }
+
+ return (NULL);
+}
+
+static const dt_modops_t dt_modops_32 = {
+ dt_module_syminit32,
+ dt_module_symsort32,
+ dt_module_symname32,
+ dt_module_symaddr32
+};
+
+static const dt_modops_t dt_modops_64 = {
+ dt_module_syminit64,
+ dt_module_symsort64,
+ dt_module_symname64,
+ dt_module_symaddr64
+};
+
+dt_module_t *
+dt_module_create(dtrace_hdl_t *dtp, const char *name)
+{
+ long pid;
+ char *eptr;
+ dt_ident_t *idp;
+ uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
+ dt_module_t *dmp;
+
+ for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) {
+ if (strcmp(dmp->dm_name, name) == 0)
+ return (dmp);
+ }
+
+ if ((dmp = malloc(sizeof (dt_module_t))) == NULL)
+ return (NULL); /* caller must handle allocation failure */
+
+ bzero(dmp, sizeof (dt_module_t));
+ (void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name));
+ dt_list_append(&dtp->dt_modlist, dmp);
+ dmp->dm_next = dtp->dt_mods[h];
+ dtp->dt_mods[h] = dmp;
+ dtp->dt_nmods++;
+
+ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
+ dmp->dm_ops = &dt_modops_64;
+ else
+ dmp->dm_ops = &dt_modops_32;
+
+ /*
+ * Modules for userland processes are special. They always refer to a
+ * specific process and have a copy of their CTF data from a specific
+ * instant in time. Any dt_module_t that begins with 'pid' is a module
+ * for a specific process, much like how any probe description that
+ * begins with 'pid' is special. pid123 refers to process 123. A module
+ * that is just 'pid' refers specifically to pid$target. This is
+ * generally done as D does not currently allow for macros to be
+ * evaluated when working with types.
+ */
+ if (strncmp(dmp->dm_name, "pid", 3) == 0) {
+ errno = 0;
+ if (dmp->dm_name[3] == '\0') {
+ idp = dt_idhash_lookup(dtp->dt_macros, "target");
+ if (idp != NULL && idp->di_id != 0)
+ dmp->dm_pid = idp->di_id;
+ } else {
+ pid = strtol(dmp->dm_name + 3, &eptr, 10);
+ if (errno == 0 && *eptr == '\0')
+ dmp->dm_pid = (pid_t)pid;
+ else
+ dt_dprintf("encountered malformed pid "
+ "module: %s\n", dmp->dm_name);
+ }
+ }
+
+ return (dmp);
+}
+
+dt_module_t *
+dt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name)
+{
+ uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
+ dt_module_t *dmp;
+
+ for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) {
+ if (strcmp(dmp->dm_name, name) == 0)
+ return (dmp);
+ }
+
+ return (NULL);
+}
+
+/*ARGSUSED*/
+dt_module_t *
+dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp)
+{
+ return (ctfp ? ctf_getspecific(ctfp) : NULL);
+}
+
+#ifdef __FreeBSD__
+dt_kmodule_t *
+dt_kmodule_lookup(dtrace_hdl_t *dtp, const char *name)
+{
+ uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
+ dt_kmodule_t *dkmp;
+
+ for (dkmp = dtp->dt_kmods[h]; dkmp != NULL; dkmp = dkmp->dkm_next) {
+ if (strcmp(dkmp->dkm_name, name) == 0)
+ return (dkmp);
+ }
+
+ return (NULL);
+}
+#endif
+
+static int
+dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp)
+{
+ const char *s;
+ size_t shstrs;
+ GElf_Shdr sh;
+ Elf_Data *dp;
+ Elf_Scn *sp;
+
+ if (elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1)
+ return (dt_set_errno(dtp, EDT_NOTLOADED));
+
+ for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
+ if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
+ (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
+ continue; /* skip any malformed sections */
+
+ if (sh.sh_type == ctsp->cts_type &&
+ sh.sh_entsize == ctsp->cts_entsize &&
+ strcmp(s, ctsp->cts_name) == 0)
+ break; /* section matches specification */
+ }
+
+ /*
+ * If the section isn't found, return success but leave cts_data set
+ * to NULL and cts_size set to zero for our caller.
+ */
+ if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL)
+ return (0);
+
+#ifdef illumos
+ ctsp->cts_data = dp->d_buf;
+#else
+ if ((ctsp->cts_data = malloc(dp->d_size)) == NULL)
+ return (0);
+ memcpy(ctsp->cts_data, dp->d_buf, dp->d_size);
+#endif
+ ctsp->cts_size = dp->d_size;
+
+ dt_dprintf("loaded %s [%s] (%lu bytes)\n",
+ dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size);
+
+ return (0);
+}
+
+typedef struct dt_module_cb_arg {
+ struct ps_prochandle *dpa_proc;
+ dtrace_hdl_t *dpa_dtp;
+ dt_module_t *dpa_dmp;
+ uint_t dpa_count;
+} dt_module_cb_arg_t;
+
+/* ARGSUSED */
+static int
+dt_module_load_proc_count(void *arg, const prmap_t *prmap, const char *obj)
+{
+ ctf_file_t *fp;
+ dt_module_cb_arg_t *dcp = arg;
+
+ /* Try to grab a ctf container if it exists */
+ fp = Pname_to_ctf(dcp->dpa_proc, obj);
+ if (fp != NULL)
+ dcp->dpa_count++;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+dt_module_load_proc_build(void *arg, const prmap_t *prmap, const char *obj)
+{
+ ctf_file_t *fp;
+ char buf[MAXPATHLEN], *p;
+ dt_module_cb_arg_t *dcp = arg;
+ int count = dcp->dpa_count;
+ Lmid_t lmid;
+
+ fp = Pname_to_ctf(dcp->dpa_proc, obj);
+ if (fp == NULL)
+ return (0);
+ fp = ctf_dup(fp);
+ if (fp == NULL)
+ return (0);
+ dcp->dpa_dmp->dm_libctfp[count] = fp;
+ /*
+ * While it'd be nice to simply use objname here, because of our prior
+ * actions we'll always get a resolved object name to its on disk file.
+ * Like the pid provider, we need to tell a bit of a lie here. The type
+ * that the user thinks of is in terms of the libraries they requested,
+ * eg. libc.so.1, they don't care about the fact that it's
+ * libc_hwcap.so.1.
+ */
+ (void) Pobjname(dcp->dpa_proc, prmap->pr_vaddr, buf, sizeof (buf));
+ if ((p = strrchr(buf, '/')) == NULL)
+ p = buf;
+ else
+ p++;
+
+ /*
+ * If for some reason we can't find a link map id for this module, which
+ * would be really quite weird. We instead just say the link map id is
+ * zero.
+ */
+ if (Plmid(dcp->dpa_proc, prmap->pr_vaddr, &lmid) != 0)
+ lmid = 0;
+
+ if (lmid == 0)
+ dcp->dpa_dmp->dm_libctfn[count] = strdup(p);
+ else
+ (void) asprintf(&dcp->dpa_dmp->dm_libctfn[count],
+ "LM%x`%s", lmid, p);
+ if (dcp->dpa_dmp->dm_libctfn[count] == NULL)
+ return (1);
+ ctf_setspecific(fp, dcp->dpa_dmp);
+ dcp->dpa_count++;
+ return (0);
+}
+
+/*
+ * We've been asked to load data that belongs to another process. As such we're
+ * going to pgrab it at this instant, load everything that we might ever care
+ * about, and then drive on. The reason for this is that the process that we're
+ * interested in might be changing. As long as we have grabbed it, then this
+ * can't be a problem for us.
+ *
+ * For now, we're actually going to punt on most things and just try to get CTF
+ * data, nothing else. Basically this is only useful as a source of type
+ * information, we can't go and do the stacktrace lookups, etc.
+ */
+static int
+dt_module_load_proc(dtrace_hdl_t *dtp, dt_module_t *dmp)
+{
+ struct ps_prochandle *p;
+ dt_module_cb_arg_t arg;
+
+ /*
+ * Note that on success we do not release this hold. We must hold this
+ * for our life time.
+ */
+ p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE);
+ if (p == NULL) {
+ dt_dprintf("failed to grab pid: %d\n", (int)dmp->dm_pid);
+ return (dt_set_errno(dtp, EDT_CANTLOAD));
+ }
+ dt_proc_lock(dtp, p);
+
+ arg.dpa_proc = p;
+ arg.dpa_dtp = dtp;
+ arg.dpa_dmp = dmp;
+ arg.dpa_count = 0;
+ if (Pobject_iter_resolved(p, dt_module_load_proc_count, &arg) != 0) {
+ dt_dprintf("failed to iterate objects\n");
+ dt_proc_unlock(dtp, p);
+ dt_proc_release(dtp, p);
+ return (dt_set_errno(dtp, EDT_CANTLOAD));
+ }
+
+ if (arg.dpa_count == 0) {
+ dt_dprintf("no ctf data present\n");
+ dt_proc_unlock(dtp, p);
+ dt_proc_release(dtp, p);
+ return (dt_set_errno(dtp, EDT_CANTLOAD));
+ }
+
+ dmp->dm_libctfp = calloc(arg.dpa_count, sizeof (ctf_file_t *));
+ if (dmp->dm_libctfp == NULL) {
+ dt_proc_unlock(dtp, p);
+ dt_proc_release(dtp, p);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ dmp->dm_libctfn = calloc(arg.dpa_count, sizeof (char *));
+ if (dmp->dm_libctfn == NULL) {
+ free(dmp->dm_libctfp);
+ dt_proc_unlock(dtp, p);
+ dt_proc_release(dtp, p);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ dmp->dm_nctflibs = arg.dpa_count;
+
+ arg.dpa_count = 0;
+ if (Pobject_iter_resolved(p, dt_module_load_proc_build, &arg) != 0) {
+ dt_proc_unlock(dtp, p);
+ dt_module_unload(dtp, dmp);
+ dt_proc_release(dtp, p);
+ return (dt_set_errno(dtp, EDT_CANTLOAD));
+ }
+ assert(arg.dpa_count == dmp->dm_nctflibs);
+ dt_dprintf("loaded %d ctf modules for pid %d\n", arg.dpa_count,
+ (int)dmp->dm_pid);
+
+ dt_proc_unlock(dtp, p);
+ dt_proc_release(dtp, p);
+ dmp->dm_flags |= DT_DM_LOADED;
+
+ return (0);
+}
+
+int
+dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
+{
+ if (dmp->dm_flags & DT_DM_LOADED)
+ return (0); /* module is already loaded */
+
+ if (dmp->dm_pid != 0)
+ return (dt_module_load_proc(dtp, dmp));
+
+ dmp->dm_ctdata.cts_name = ".SUNW_ctf";
+ dmp->dm_ctdata.cts_type = SHT_PROGBITS;
+ dmp->dm_ctdata.cts_flags = 0;
+ dmp->dm_ctdata.cts_data = NULL;
+ dmp->dm_ctdata.cts_size = 0;
+ dmp->dm_ctdata.cts_entsize = 0;
+ dmp->dm_ctdata.cts_offset = 0;
+
+ dmp->dm_symtab.cts_name = ".symtab";
+ dmp->dm_symtab.cts_type = SHT_SYMTAB;
+ dmp->dm_symtab.cts_flags = 0;
+ dmp->dm_symtab.cts_data = NULL;
+ dmp->dm_symtab.cts_size = 0;
+ dmp->dm_symtab.cts_entsize = dmp->dm_ops == &dt_modops_64 ?
+ sizeof (Elf64_Sym) : sizeof (Elf32_Sym);
+ dmp->dm_symtab.cts_offset = 0;
+
+ dmp->dm_strtab.cts_name = ".strtab";
+ dmp->dm_strtab.cts_type = SHT_STRTAB;
+ dmp->dm_strtab.cts_flags = 0;
+ dmp->dm_strtab.cts_data = NULL;
+ dmp->dm_strtab.cts_size = 0;
+ dmp->dm_strtab.cts_entsize = 0;
+ dmp->dm_strtab.cts_offset = 0;
+
+ /*
+ * Attempt to load the module's CTF section, symbol table section, and
+ * string table section. Note that modules may not contain CTF data:
+ * this will result in a successful load_sect but data of size zero.
+ * We will then fail if dt_module_getctf() is called, as shown below.
+ */
+ if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1 ||
+ dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 ||
+ dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) {
+ dt_module_unload(dtp, dmp);
+ return (-1); /* dt_errno is set for us */
+ }
+
+ /*
+ * Allocate the hash chains and hash buckets for symbol name lookup.
+ * This is relatively simple since the symbol table is of fixed size
+ * and is known in advance. We allocate one extra element since we
+ * use element indices instead of pointers and zero is our sentinel.
+ */
+ dmp->dm_nsymelems =
+ dmp->dm_symtab.cts_size / dmp->dm_symtab.cts_entsize;
+
+ dmp->dm_nsymbuckets = _dtrace_strbuckets;
+ dmp->dm_symfree = 1; /* first free element is index 1 */
+
+ dmp->dm_symbuckets = calloc(dmp->dm_nsymbuckets, sizeof (uint_t));
+ dmp->dm_symchains = calloc(dmp->dm_nsymelems + 1, sizeof (dt_sym_t));
+
+ if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) {
+ dt_module_unload(dtp, dmp);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ /*
+ * Iterate over the symbol table data buffer and insert each symbol
+ * name into the name hash if the name and type are valid. Then
+ * allocate the address map, fill it in, and sort it.
+ */
+ dmp->dm_asrsv = dmp->dm_ops->do_syminit(dmp);
+
+ dt_dprintf("hashed %s [%s] (%u symbols)\n",
+ dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_symfree - 1);
+
+ if ((dmp->dm_asmap = malloc(sizeof (void *) * dmp->dm_asrsv)) == NULL) {
+ dt_module_unload(dtp, dmp);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ dmp->dm_ops->do_symsort(dmp);
+
+ dt_dprintf("sorted %s [%s] (%u symbols)\n",
+ dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_aslen);
+
+ dmp->dm_flags |= DT_DM_LOADED;
+ return (0);
+}
+
+int
+dt_module_hasctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
+{
+ if (dmp->dm_pid != 0 && dmp->dm_nctflibs > 0)
+ return (1);
+ return (dt_module_getctf(dtp, dmp) != NULL);
+}
+
+ctf_file_t *
+dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
+{
+ const char *parent;
+ dt_module_t *pmp;
+ ctf_file_t *pfp;
+ int model;
+
+ if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0)
+ return (dmp->dm_ctfp);
+
+ if (dmp->dm_ops == &dt_modops_64)
+ model = CTF_MODEL_LP64;
+ else
+ model = CTF_MODEL_ILP32;
+
+ /*
+ * If the data model of the module does not match our program data
+ * model, then do not permit CTF from this module to be opened and
+ * returned to the compiler. If we support mixed data models in the
+ * future for combined kernel/user tracing, this can be removed.
+ */
+ if (dtp->dt_conf.dtc_ctfmodel != model) {
+ (void) dt_set_errno(dtp, EDT_DATAMODEL);
+ return (NULL);
+ }
+
+ if (dmp->dm_ctdata.cts_size == 0) {
+ (void) dt_set_errno(dtp, EDT_NOCTF);
+ return (NULL);
+ }
+
+ dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata,
+ &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr);
+
+ if (dmp->dm_ctfp == NULL) {
+ (void) dt_set_errno(dtp, EDT_CTF);
+ return (NULL);
+ }
+
+ (void) ctf_setmodel(dmp->dm_ctfp, model);
+ ctf_setspecific(dmp->dm_ctfp, dmp);
+
+ if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) {
+ if ((pmp = dt_module_create(dtp, parent)) == NULL ||
+ (pfp = dt_module_getctf(dtp, pmp)) == NULL) {
+ if (pmp == NULL)
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+ goto err;
+ }
+
+ if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) {
+ dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp);
+ (void) dt_set_errno(dtp, EDT_CTF);
+ goto err;
+ }
+ }
+
+ dt_dprintf("loaded CTF container for %s (%p)\n",
+ dmp->dm_name, (void *)dmp->dm_ctfp);
+
+ return (dmp->dm_ctfp);
+
+err:
+ ctf_close(dmp->dm_ctfp);
+ dmp->dm_ctfp = NULL;
+ return (NULL);
+}
+
+/*ARGSUSED*/
+void
+dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
+{
+ int i;
+
+ ctf_close(dmp->dm_ctfp);
+ dmp->dm_ctfp = NULL;
+
+#ifndef illumos
+ if (dmp->dm_ctdata.cts_data != NULL) {
+ free(dmp->dm_ctdata.cts_data);
+ }
+ if (dmp->dm_symtab.cts_data != NULL) {
+ free(dmp->dm_symtab.cts_data);
+ }
+ if (dmp->dm_strtab.cts_data != NULL) {
+ free(dmp->dm_strtab.cts_data);
+ }
+#endif
+
+ if (dmp->dm_libctfp != NULL) {
+ for (i = 0; i < dmp->dm_nctflibs; i++) {
+ ctf_close(dmp->dm_libctfp[i]);
+ free(dmp->dm_libctfn[i]);
+ }
+ free(dmp->dm_libctfp);
+ free(dmp->dm_libctfn);
+ dmp->dm_libctfp = NULL;
+ dmp->dm_nctflibs = 0;
+ }
+
+ bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t));
+ bzero(&dmp->dm_symtab, sizeof (ctf_sect_t));
+ bzero(&dmp->dm_strtab, sizeof (ctf_sect_t));
+
+ if (dmp->dm_symbuckets != NULL) {
+ free(dmp->dm_symbuckets);
+ dmp->dm_symbuckets = NULL;
+ }
+
+ if (dmp->dm_symchains != NULL) {
+ free(dmp->dm_symchains);
+ dmp->dm_symchains = NULL;
+ }
+
+ if (dmp->dm_asmap != NULL) {
+ free(dmp->dm_asmap);
+ dmp->dm_asmap = NULL;
+ }
+#if defined(__FreeBSD__)
+ if (dmp->dm_sec_offsets != NULL) {
+ free(dmp->dm_sec_offsets);
+ dmp->dm_sec_offsets = NULL;
+ }
+#endif
+ dmp->dm_symfree = 0;
+ dmp->dm_nsymbuckets = 0;
+ dmp->dm_nsymelems = 0;
+ dmp->dm_asrsv = 0;
+ dmp->dm_aslen = 0;
+
+ dmp->dm_text_va = 0;
+ dmp->dm_text_size = 0;
+ dmp->dm_data_va = 0;
+ dmp->dm_data_size = 0;
+ dmp->dm_bss_va = 0;
+ dmp->dm_bss_size = 0;
+
+ if (dmp->dm_extern != NULL) {
+ dt_idhash_destroy(dmp->dm_extern);
+ dmp->dm_extern = NULL;
+ }
+
+ (void) elf_end(dmp->dm_elf);
+ dmp->dm_elf = NULL;
+
+ dmp->dm_pid = 0;
+
+ dmp->dm_flags &= ~DT_DM_LOADED;
+}
+
+void
+dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp)
+{
+ uint_t h = dt_strtab_hash(dmp->dm_name, NULL) % dtp->dt_modbuckets;
+ dt_module_t **dmpp = &dtp->dt_mods[h];
+
+ dt_list_delete(&dtp->dt_modlist, dmp);
+ assert(dtp->dt_nmods != 0);
+ dtp->dt_nmods--;
+
+ /*
+ * Now remove this module from its hash chain. We expect to always
+ * find the module on its hash chain, so in this loop we assert that
+ * we don't run off the end of the list.
+ */
+ while (*dmpp != dmp) {
+ dmpp = &((*dmpp)->dm_next);
+ assert(*dmpp != NULL);
+ }
+
+ *dmpp = dmp->dm_next;
+
+ dt_module_unload(dtp, dmp);
+ free(dmp);
+}
+
+/*
+ * Insert a new external symbol reference into the specified module. The new
+ * symbol will be marked as undefined and is assigned a symbol index beyond
+ * any existing cached symbols from this module. We use the ident's di_data
+ * field to store a pointer to a copy of the dtrace_syminfo_t for this symbol.
+ */
+dt_ident_t *
+dt_module_extern(dtrace_hdl_t *dtp, dt_module_t *dmp,
+ const char *name, const dtrace_typeinfo_t *tip)
+{
+ dtrace_syminfo_t *sip;
+ dt_ident_t *idp;
+ uint_t id;
+
+ if (dmp->dm_extern == NULL && (dmp->dm_extern = dt_idhash_create(
+ "extern", NULL, dmp->dm_nsymelems, UINT_MAX)) == NULL) {
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+ return (NULL);
+ }
+
+ if (dt_idhash_nextid(dmp->dm_extern, &id) == -1) {
+ (void) dt_set_errno(dtp, EDT_SYMOFLOW);
+ return (NULL);
+ }
+
+ if ((sip = malloc(sizeof (dtrace_syminfo_t))) == NULL) {
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+ return (NULL);
+ }
+
+ idp = dt_idhash_insert(dmp->dm_extern, name, DT_IDENT_SYMBOL, 0, id,
+ _dtrace_symattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
+
+ if (idp == NULL) {
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+ free(sip);
+ return (NULL);
+ }
+
+ sip->dts_object = dmp->dm_name;
+ sip->dts_name = idp->di_name;
+ sip->dts_id = idp->di_id;
+
+ idp->di_data = sip;
+ idp->di_ctfp = tip->dtt_ctfp;
+ idp->di_type = tip->dtt_type;
+
+ return (idp);
+}
+
+const char *
+dt_module_modelname(dt_module_t *dmp)
+{
+ if (dmp->dm_ops == &dt_modops_64)
+ return ("64-bit");
+ else
+ return ("32-bit");
+}
+
+/* ARGSUSED */
+int
+dt_module_getlibid(dtrace_hdl_t *dtp, dt_module_t *dmp, const ctf_file_t *fp)
+{
+ int i;
+
+ for (i = 0; i < dmp->dm_nctflibs; i++) {
+ if (dmp->dm_libctfp[i] == fp)
+ return (i);
+ }
+
+ return (-1);
+}
+
+/* ARGSUSED */
+ctf_file_t *
+dt_module_getctflib(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name)
+{
+ int i;
+
+ for (i = 0; i < dmp->dm_nctflibs; i++) {
+ if (strcmp(dmp->dm_libctfn[i], name) == 0)
+ return (dmp->dm_libctfp[i]);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Update our module cache by adding an entry for the specified module 'name'.
+ * We create the dt_module_t and populate it using /system/object/<name>/.
+ *
+ * On FreeBSD, the module name is passed as the full module file name,
+ * including the path.
+ */
+static void
+#ifdef illumos
+dt_module_update(dtrace_hdl_t *dtp, const char *name)
+#else
+dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat)
+#endif
+{
+ char fname[MAXPATHLEN];
+ struct stat64 st;
+ int fd, err, bits;
+#ifdef __FreeBSD__
+ struct module_stat ms;
+ dt_kmodule_t *dkmp;
+ uint_t h;
+ int modid;
+#endif
+
+ dt_module_t *dmp;
+ const char *s;
+ size_t shstrs;
+ GElf_Shdr sh;
+ Elf_Data *dp;
+ Elf_Scn *sp;
+
+#ifdef illumos
+ (void) snprintf(fname, sizeof (fname),
+ "%s/%s/object", OBJFS_ROOT, name);
+#else
+ GElf_Ehdr ehdr;
+ GElf_Phdr ph;
+ char name[MAXPATHLEN];
+ uintptr_t mapbase, alignmask;
+ int i = 0;
+ int is_elf_obj;
+
+ (void) strlcpy(name, k_stat->name, sizeof(name));
+ (void) strlcpy(fname, k_stat->pathname, sizeof(fname));
+#endif
+
+ if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 ||
+ (dmp = dt_module_create(dtp, name)) == NULL) {
+ dt_dprintf("failed to open %s: %s\n", fname, strerror(errno));
+ (void) close(fd);
+ return;
+ }
+
+ /*
+ * Since the module can unload out from under us (and /system/object
+ * will return ENOENT), tell libelf to cook the entire file now and
+ * then close the underlying file descriptor immediately. If this
+ * succeeds, we know that we can continue safely using dmp->dm_elf.
+ */
+ dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL);
+ err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD);
+ (void) close(fd);
+
+ if (dmp->dm_elf == NULL || err == -1 ||
+ elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) {
+ dt_dprintf("failed to load %s: %s\n",
+ fname, elf_errmsg(elf_errno()));
+ dt_module_destroy(dtp, dmp);
+ return;
+ }
+
+ switch (gelf_getclass(dmp->dm_elf)) {
+ case ELFCLASS32:
+ dmp->dm_ops = &dt_modops_32;
+ bits = 32;
+ break;
+ case ELFCLASS64:
+ dmp->dm_ops = &dt_modops_64;
+ bits = 64;
+ break;
+ default:
+ dt_dprintf("failed to load %s: unknown ELF class\n", fname);
+ dt_module_destroy(dtp, dmp);
+ return;
+ }
+#if defined(__FreeBSD__)
+ mapbase = (uintptr_t)k_stat->address;
+ gelf_getehdr(dmp->dm_elf, &ehdr);
+ is_elf_obj = (ehdr.e_type == ET_REL);
+ if (is_elf_obj) {
+ dmp->dm_sec_offsets =
+ malloc(ehdr.e_shnum * sizeof(*dmp->dm_sec_offsets));
+ if (dmp->dm_sec_offsets == NULL) {
+ dt_dprintf("failed to allocate memory\n");
+ dt_module_destroy(dtp, dmp);
+ return;
+ }
+ }
+#endif
+ /*
+ * Iterate over the section headers locating various sections of
+ * interest and use their attributes to flesh out the dt_module_t.
+ */
+ for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
+ if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
+ (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
+ continue; /* skip any malformed sections */
+#if defined(__FreeBSD__)
+ if (sh.sh_size == 0)
+ continue;
+ if (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) {
+ alignmask = sh.sh_addralign - 1;
+ mapbase += alignmask;
+ mapbase &= ~alignmask;
+ sh.sh_addr = mapbase;
+ if (is_elf_obj)
+ dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr;
+ mapbase += sh.sh_size;
+ }
+#endif
+ if (strcmp(s, ".text") == 0) {
+ dmp->dm_text_size = sh.sh_size;
+ dmp->dm_text_va = sh.sh_addr;
+ } else if (strcmp(s, ".data") == 0) {
+ dmp->dm_data_size = sh.sh_size;
+ dmp->dm_data_va = sh.sh_addr;
+ } else if (strcmp(s, ".bss") == 0) {
+ dmp->dm_bss_size = sh.sh_size;
+ dmp->dm_bss_va = sh.sh_addr;
+ } else if (strcmp(s, ".info") == 0 &&
+ (dp = elf_getdata(sp, NULL)) != NULL) {
+ bcopy(dp->d_buf, &dmp->dm_info,
+ MIN(sh.sh_size, sizeof (dmp->dm_info)));
+ } else if (strcmp(s, ".filename") == 0 &&
+ (dp = elf_getdata(sp, NULL)) != NULL) {
+ (void) strlcpy(dmp->dm_file,
+ dp->d_buf, sizeof (dmp->dm_file));
+ }
+ }
+
+ dmp->dm_flags |= DT_DM_KERNEL;
+#ifdef illumos
+ dmp->dm_modid = (int)OBJFS_MODID(st.st_ino);
+#else
+ /*
+ * Include .rodata and special sections into .text.
+ * This depends on default section layout produced by GNU ld
+ * for ELF objects and libraries:
+ * [Text][R/O data][R/W data][Dynamic][BSS][Non loadable]
+ */
+ dmp->dm_text_size = dmp->dm_data_va - dmp->dm_text_va;
+#if defined(__i386__)
+ /*
+ * Find the first load section and figure out the relocation
+ * offset for the symbols. The kernel module will not need
+ * relocation, but the kernel linker modules will.
+ */
+ for (i = 0; gelf_getphdr(dmp->dm_elf, i, &ph) != NULL; i++) {
+ if (ph.p_type == PT_LOAD) {
+ dmp->dm_reloc_offset = k_stat->address - ph.p_vaddr;
+ break;
+ }
+ }
+#endif
+#endif /* illumos */
+
+ if (dmp->dm_info.objfs_info_primary)
+ dmp->dm_flags |= DT_DM_PRIMARY;
+
+#ifdef __FreeBSD__
+ ms.version = sizeof(ms);
+ for (modid = kldfirstmod(k_stat->id); modid > 0;
+ modid = modnext(modid)) {
+ if (modstat(modid, &ms) != 0) {
+ dt_dprintf("modstat failed for id %d in %s: %s\n",
+ modid, k_stat->name, strerror(errno));
+ continue;
+ }
+ if (dt_kmodule_lookup(dtp, ms.name) != NULL)
+ continue;
+
+ dkmp = malloc(sizeof (*dkmp));
+ if (dkmp == NULL) {
+ dt_dprintf("failed to allocate memory\n");
+ dt_module_destroy(dtp, dmp);
+ return;
+ }
+
+ h = dt_strtab_hash(ms.name, NULL) % dtp->dt_modbuckets;
+ dkmp->dkm_next = dtp->dt_kmods[h];
+ dkmp->dkm_name = strdup(ms.name);
+ dkmp->dkm_module = dmp;
+ dtp->dt_kmods[h] = dkmp;
+ }
+#endif
+
+ dt_dprintf("opened %d-bit module %s (%s) [%d]\n",
+ bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid);
+}
+
+/*
+ * Unload all the loaded modules and then refresh the module cache with the
+ * latest list of loaded modules and their address ranges.
+ */
+void
+dtrace_update(dtrace_hdl_t *dtp)
+{
+ dt_module_t *dmp;
+ DIR *dirp;
+#if defined(__FreeBSD__)
+ int fileid;
+#endif
+
+ for (dmp = dt_list_next(&dtp->dt_modlist);
+ dmp != NULL; dmp = dt_list_next(dmp))
+ dt_module_unload(dtp, dmp);
+
+#ifdef illumos
+ /*
+ * Open /system/object and attempt to create a libdtrace module for
+ * each kernel module that is loaded on the current system.
+ */
+ if (!(dtp->dt_oflags & DTRACE_O_NOSYS) &&
+ (dirp = opendir(OBJFS_ROOT)) != NULL) {
+ struct dirent *dp;
+
+ while ((dp = readdir(dirp)) != NULL) {
+ if (dp->d_name[0] != '.')
+ dt_module_update(dtp, dp->d_name);
+ }
+
+ (void) closedir(dirp);
+ }
+#elif defined(__FreeBSD__)
+ /*
+ * Use FreeBSD's kernel loader interface to discover what kernel
+ * modules are loaded and create a libdtrace module for each one.
+ */
+ for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
+ struct kld_file_stat k_stat;
+ k_stat.version = sizeof(k_stat);
+ if (kldstat(fileid, &k_stat) == 0)
+ dt_module_update(dtp, &k_stat);
+ }
+#endif
+
+ /*
+ * Look up all the macro identifiers and set di_id to the latest value.
+ * This code collaborates with dt_lex.l on the use of di_id. We will
+ * need to implement something fancier if we need to support non-ints.
+ */
+ dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid();
+ dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid();
+ dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid();
+ dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid();
+ dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0);
+ dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid();
+#ifdef illumos
+ dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid();
+#endif
+ dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0);
+#ifdef illumos
+ dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid();
+#endif
+ dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid();
+
+ /*
+ * Cache the pointers to the modules representing the base executable
+ * and the run-time linker in the dtrace client handle. Note that on
+ * x86 krtld is folded into unix, so if we don't find it, use unix
+ * instead.
+ */
+ dtp->dt_exec = dt_module_lookup_by_name(dtp, "genunix");
+ dtp->dt_rtld = dt_module_lookup_by_name(dtp, "krtld");
+ if (dtp->dt_rtld == NULL)
+ dtp->dt_rtld = dt_module_lookup_by_name(dtp, "unix");
+
+ /*
+ * If this is the first time we are initializing the module list,
+ * remove the module for genunix from the module list and then move it
+ * to the front of the module list. We do this so that type and symbol
+ * queries encounter genunix and thereby optimize for the common case
+ * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below.
+ */
+ if (dtp->dt_exec != NULL &&
+ dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) {
+ dt_list_delete(&dtp->dt_modlist, dtp->dt_exec);
+ dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec);
+ }
+}
+
+static dt_module_t *
+dt_module_from_object(dtrace_hdl_t *dtp, const char *object)
+{
+ int err = EDT_NOMOD;
+ dt_module_t *dmp;
+
+ switch ((uintptr_t)object) {
+ case (uintptr_t)DTRACE_OBJ_EXEC:
+ dmp = dtp->dt_exec;
+ break;
+ case (uintptr_t)DTRACE_OBJ_RTLD:
+ dmp = dtp->dt_rtld;
+ break;
+ case (uintptr_t)DTRACE_OBJ_CDEFS:
+ dmp = dtp->dt_cdefs;
+ break;
+ case (uintptr_t)DTRACE_OBJ_DDEFS:
+ dmp = dtp->dt_ddefs;
+ break;
+ default:
+ dmp = dt_module_create(dtp, object);
+ err = EDT_NOMEM;
+ }
+
+ if (dmp == NULL)
+ (void) dt_set_errno(dtp, err);
+
+ return (dmp);
+}
+
+/*
+ * Exported interface to look up a symbol by name. We return the GElf_Sym and
+ * complete symbol information for the matching symbol.
+ */
+int
+dtrace_lookup_by_name(dtrace_hdl_t *dtp, const char *object, const char *name,
+ GElf_Sym *symp, dtrace_syminfo_t *sip)
+{
+ dt_module_t *dmp;
+ dt_ident_t *idp;
+ uint_t n, id;
+ GElf_Sym sym;
+
+ uint_t mask = 0; /* mask of dt_module flags to match */
+ uint_t bits = 0; /* flag bits that must be present */
+
+ if (object != DTRACE_OBJ_EVERY &&
+ object != DTRACE_OBJ_KMODS &&
+ object != DTRACE_OBJ_UMODS) {
+ if ((dmp = dt_module_from_object(dtp, object)) == NULL)
+ return (-1); /* dt_errno is set for us */
+
+ if (dt_module_load(dtp, dmp) == -1)
+ return (-1); /* dt_errno is set for us */
+ n = 1;
+
+ } else {
+ if (object == DTRACE_OBJ_KMODS)
+ mask = bits = DT_DM_KERNEL;
+ else if (object == DTRACE_OBJ_UMODS)
+ mask = DT_DM_KERNEL;
+
+ dmp = dt_list_next(&dtp->dt_modlist);
+ n = dtp->dt_nmods;
+ }
+
+ if (symp == NULL)
+ symp = &sym;
+
+ for (; n > 0; n--, dmp = dt_list_next(dmp)) {
+ if ((dmp->dm_flags & mask) != bits)
+ continue; /* failed to match required attributes */
+
+ if (dt_module_load(dtp, dmp) == -1)
+ continue; /* failed to load symbol table */
+
+ if (dmp->dm_ops->do_symname(dmp, name, symp, &id) != NULL) {
+ if (sip != NULL) {
+ sip->dts_object = dmp->dm_name;
+ sip->dts_name = (const char *)
+ dmp->dm_strtab.cts_data + symp->st_name;
+ sip->dts_id = id;
+ }
+ return (0);
+ }
+
+ if (dmp->dm_extern != NULL &&
+ (idp = dt_idhash_lookup(dmp->dm_extern, name)) != NULL) {
+ if (symp != &sym) {
+ symp->st_name = (uintptr_t)idp->di_name;
+ symp->st_info =
+ GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
+ symp->st_other = 0;
+ symp->st_shndx = SHN_UNDEF;
+ symp->st_value = 0;
+ symp->st_size =
+ ctf_type_size(idp->di_ctfp, idp->di_type);
+ }
+
+ if (sip != NULL) {
+ sip->dts_object = dmp->dm_name;
+ sip->dts_name = idp->di_name;
+ sip->dts_id = idp->di_id;
+ }
+
+ return (0);
+ }
+ }
+
+ return (dt_set_errno(dtp, EDT_NOSYM));
+}
+
+/*
+ * Exported interface to look up a symbol by address. We return the GElf_Sym
+ * and complete symbol information for the matching symbol.
+ */
+int
+dtrace_lookup_by_addr(dtrace_hdl_t *dtp, GElf_Addr addr,
+ GElf_Sym *symp, dtrace_syminfo_t *sip)
+{
+ dt_module_t *dmp;
+ uint_t id;
+ const dtrace_vector_t *v = dtp->dt_vector;
+
+ if (v != NULL)
+ return (v->dtv_lookup_by_addr(dtp->dt_varg, addr, symp, sip));
+
+ for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL;
+ dmp = dt_list_next(dmp)) {
+ if (addr - dmp->dm_text_va < dmp->dm_text_size ||
+ addr - dmp->dm_data_va < dmp->dm_data_size ||
+ addr - dmp->dm_bss_va < dmp->dm_bss_size)
+ break;
+ }
+
+ if (dmp == NULL)
+ return (dt_set_errno(dtp, EDT_NOSYMADDR));
+
+ if (dt_module_load(dtp, dmp) == -1)
+ return (-1); /* dt_errno is set for us */
+
+ if (symp != NULL) {
+ if (dmp->dm_ops->do_symaddr(dmp, addr, symp, &id) == NULL)
+ return (dt_set_errno(dtp, EDT_NOSYMADDR));
+ }
+
+ if (sip != NULL) {
+ sip->dts_object = dmp->dm_name;
+
+ if (symp != NULL) {
+ sip->dts_name = (const char *)
+ dmp->dm_strtab.cts_data + symp->st_name;
+ sip->dts_id = id;
+ } else {
+ sip->dts_name = NULL;
+ sip->dts_id = 0;
+ }
+ }
+
+ return (0);
+}
+
+int
+dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
+ dtrace_typeinfo_t *tip)
+{
+ dtrace_typeinfo_t ti;
+ dt_module_t *dmp;
+ int found = 0;
+ ctf_id_t id;
+ uint_t n, i;
+ int justone;
+ ctf_file_t *fp;
+ char *buf, *p, *q;
+
+ uint_t mask = 0; /* mask of dt_module flags to match */
+ uint_t bits = 0; /* flag bits that must be present */
+
+ if (object != DTRACE_OBJ_EVERY &&
+ object != DTRACE_OBJ_KMODS &&
+ object != DTRACE_OBJ_UMODS) {
+ if ((dmp = dt_module_from_object(dtp, object)) == NULL)
+ return (-1); /* dt_errno is set for us */
+
+ if (dt_module_load(dtp, dmp) == -1)
+ return (-1); /* dt_errno is set for us */
+ n = 1;
+ justone = 1;
+ } else {
+ if (object == DTRACE_OBJ_KMODS)
+ mask = bits = DT_DM_KERNEL;
+ else if (object == DTRACE_OBJ_UMODS)
+ mask = DT_DM_KERNEL;
+
+ dmp = dt_list_next(&dtp->dt_modlist);
+ n = dtp->dt_nmods;
+ justone = 0;
+ }
+
+ if (tip == NULL)
+ tip = &ti;
+
+ for (; n > 0; n--, dmp = dt_list_next(dmp)) {
+ if ((dmp->dm_flags & mask) != bits)
+ continue; /* failed to match required attributes */
+
+ /*
+ * If we can't load the CTF container, continue on to the next
+ * module. If our search was scoped to only one module then
+ * return immediately leaving dt_errno unmodified.
+ */
+ if (dt_module_hasctf(dtp, dmp) == 0) {
+ if (justone)
+ return (-1);
+ continue;
+ }
+
+ /*
+ * Look up the type in the module's CTF container. If our
+ * match is a forward declaration tag, save this choice in
+ * 'tip' and keep going in the hope that we will locate the
+ * underlying structure definition. Otherwise just return.
+ */
+ if (dmp->dm_pid == 0) {
+ id = ctf_lookup_by_name(dmp->dm_ctfp, name);
+ fp = dmp->dm_ctfp;
+ } else {
+ if ((p = strchr(name, '`')) != NULL) {
+ buf = strdup(name);
+ if (buf == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ p = strchr(buf, '`');
+ if ((q = strchr(p + 1, '`')) != NULL)
+ p = q;
+ *p = '\0';
+ fp = dt_module_getctflib(dtp, dmp, buf);
+ if (fp == NULL || (id = ctf_lookup_by_name(fp,
+ p + 1)) == CTF_ERR)
+ id = CTF_ERR;
+ free(buf);
+ } else {
+ for (i = 0; i < dmp->dm_nctflibs; i++) {
+ fp = dmp->dm_libctfp[i];
+ id = ctf_lookup_by_name(fp, name);
+ if (id != CTF_ERR)
+ break;
+ }
+ }
+ }
+ if (id != CTF_ERR) {
+ tip->dtt_object = dmp->dm_name;
+ tip->dtt_ctfp = fp;
+ tip->dtt_type = id;
+ if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) !=
+ CTF_K_FORWARD)
+ return (0);
+
+ found++;
+ }
+ }
+
+ if (found == 0)
+ return (dt_set_errno(dtp, EDT_NOTYPE));
+
+ return (0);
+}
+
+int
+dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp,
+ const dtrace_syminfo_t *sip, dtrace_typeinfo_t *tip)
+{
+ dt_module_t *dmp;
+
+ tip->dtt_object = NULL;
+ tip->dtt_ctfp = NULL;
+ tip->dtt_type = CTF_ERR;
+ tip->dtt_flags = 0;
+
+ if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMOD));
+
+ if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) {
+ dt_ident_t *idp =
+ dt_idhash_lookup(dmp->dm_extern, sip->dts_name);
+
+ if (idp == NULL)
+ return (dt_set_errno(dtp, EDT_NOSYM));
+
+ tip->dtt_ctfp = idp->di_ctfp;
+ tip->dtt_type = idp->di_type;
+
+ } else if (GELF_ST_TYPE(symp->st_info) != STT_FUNC) {
+ if (dt_module_getctf(dtp, dmp) == NULL)
+ return (-1); /* errno is set for us */
+
+ tip->dtt_ctfp = dmp->dm_ctfp;
+ tip->dtt_type = ctf_lookup_by_symbol(dmp->dm_ctfp, sip->dts_id);
+
+ if (tip->dtt_type == CTF_ERR) {
+ dtp->dt_ctferr = ctf_errno(tip->dtt_ctfp);
+ return (dt_set_errno(dtp, EDT_CTF));
+ }
+
+ } else {
+ tip->dtt_ctfp = DT_FPTR_CTFP(dtp);
+ tip->dtt_type = DT_FPTR_TYPE(dtp);
+ }
+
+ tip->dtt_object = dmp->dm_name;
+ return (0);
+}
+
+static dtrace_objinfo_t *
+dt_module_info(const dt_module_t *dmp, dtrace_objinfo_t *dto)
+{
+ dto->dto_name = dmp->dm_name;
+ dto->dto_file = dmp->dm_file;
+ dto->dto_id = dmp->dm_modid;
+ dto->dto_flags = 0;
+
+ if (dmp->dm_flags & DT_DM_KERNEL)
+ dto->dto_flags |= DTRACE_OBJ_F_KERNEL;
+ if (dmp->dm_flags & DT_DM_PRIMARY)
+ dto->dto_flags |= DTRACE_OBJ_F_PRIMARY;
+
+ dto->dto_text_va = dmp->dm_text_va;
+ dto->dto_text_size = dmp->dm_text_size;
+ dto->dto_data_va = dmp->dm_data_va;
+ dto->dto_data_size = dmp->dm_data_size;
+ dto->dto_bss_va = dmp->dm_bss_va;
+ dto->dto_bss_size = dmp->dm_bss_size;
+
+ return (dto);
+}
+
+int
+dtrace_object_iter(dtrace_hdl_t *dtp, dtrace_obj_f *func, void *data)
+{
+ const dt_module_t *dmp = dt_list_next(&dtp->dt_modlist);
+ dtrace_objinfo_t dto;
+ int rv;
+
+ for (; dmp != NULL; dmp = dt_list_next(dmp)) {
+ if ((rv = (*func)(dtp, dt_module_info(dmp, &dto), data)) != 0)
+ return (rv);
+ }
+
+ return (0);
+}
+
+int
+dtrace_object_info(dtrace_hdl_t *dtp, const char *object, dtrace_objinfo_t *dto)
+{
+ dt_module_t *dmp;
+
+ if (object == DTRACE_OBJ_EVERY || object == DTRACE_OBJ_KMODS ||
+ object == DTRACE_OBJ_UMODS || dto == NULL)
+ return (dt_set_errno(dtp, EINVAL));
+
+ if ((dmp = dt_module_from_object(dtp, object)) == NULL)
+ return (-1); /* dt_errno is set for us */
+
+ if (dt_module_load(dtp, dmp) == -1)
+ return (-1); /* dt_errno is set for us */
+
+ (void) dt_module_info(dmp, dto);
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h
new file mode 100644
index 000000000000..6db16cced373
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _DT_MODULE_H
+#define _DT_MODULE_H
+
+#include <dt_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern dt_module_t *dt_module_create(dtrace_hdl_t *, const char *);
+extern int dt_module_load(dtrace_hdl_t *, dt_module_t *);
+extern void dt_module_unload(dtrace_hdl_t *, dt_module_t *);
+extern void dt_module_destroy(dtrace_hdl_t *, dt_module_t *);
+
+extern dt_module_t *dt_module_lookup_by_name(dtrace_hdl_t *, const char *);
+extern dt_module_t *dt_module_lookup_by_ctf(dtrace_hdl_t *, ctf_file_t *);
+
+#ifdef __FreeBSD__
+extern dt_kmodule_t *dt_kmodule_lookup(dtrace_hdl_t *, const char *);
+#endif
+
+extern int dt_module_hasctf(dtrace_hdl_t *, dt_module_t *);
+extern ctf_file_t *dt_module_getctf(dtrace_hdl_t *, dt_module_t *);
+extern dt_ident_t *dt_module_extern(dtrace_hdl_t *, dt_module_t *,
+ const char *, const dtrace_typeinfo_t *);
+
+extern const char *dt_module_modelname(dt_module_t *);
+extern int dt_module_getlibid(dtrace_hdl_t *, dt_module_t *,
+ const ctf_file_t *);
+extern ctf_file_t *dt_module_getctflib(dtrace_hdl_t *, dt_module_t *,
+ const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_MODULE_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
new file mode 100644
index 000000000000..492fb937cba2
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
@@ -0,0 +1,1746 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ */
+
+#include <sys/types.h>
+#ifdef illumos
+#include <sys/modctl.h>
+#include <sys/systeminfo.h>
+#else
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/linker.h>
+#endif
+#include <sys/resource.h>
+
+#include <libelf.h>
+#include <strings.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <limits.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+#define _POSIX_PTHREAD_SEMANTICS
+#include <dirent.h>
+#undef _POSIX_PTHREAD_SEMANTICS
+
+#include <dt_impl.h>
+#include <dt_program.h>
+#include <dt_module.h>
+#include <dt_printf.h>
+#include <dt_string.h>
+#include <dt_provider.h>
+#ifndef illumos
+#include <sys/sysctl.h>
+#include <string.h>
+#endif
+#if defined(__i386__)
+#include <ieeefp.h>
+#endif
+
+/*
+ * Stability and versioning definitions. These #defines are used in the tables
+ * of identifiers below to fill in the attribute and version fields associated
+ * with each identifier. The DT_ATTR_* macros are a convenience to permit more
+ * concise declarations of common attributes such as Stable/Stable/Common. The
+ * DT_VERS_* macros declare the encoded integer values of all versions used so
+ * far. DT_VERS_LATEST must correspond to the latest version value among all
+ * versions exported by the D compiler. DT_VERS_STRING must be an ASCII string
+ * that contains DT_VERS_LATEST within it along with any suffixes (e.g. Beta).
+ * You must update DT_VERS_LATEST and DT_VERS_STRING when adding a new version,
+ * and then add the new version to the _dtrace_versions[] array declared below.
+ * Refer to the Solaris Dynamic Tracing Guide Stability and Versioning chapters
+ * respectively for an explanation of these DTrace features and their values.
+ *
+ * NOTE: Although the DTrace versioning scheme supports the labeling and
+ * introduction of incompatible changes (e.g. dropping an interface in a
+ * major release), the libdtrace code does not currently support this.
+ * All versions are assumed to strictly inherit from one another. If
+ * we ever need to provide divergent interfaces, this will need work.
+ */
+#define DT_ATTR_STABCMN { DTRACE_STABILITY_STABLE, \
+ DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }
+
+#define DT_ATTR_EVOLCMN { DTRACE_STABILITY_EVOLVING, \
+ DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON \
+}
+
+/*
+ * The version number should be increased for every customer visible release
+ * of DTrace. The major number should be incremented when a fundamental
+ * change has been made that would affect all consumers, and would reflect
+ * sweeping changes to DTrace or the D language. The minor number should be
+ * incremented when a change is introduced that could break scripts that had
+ * previously worked; for example, adding a new built-in variable could break
+ * a script which was already using that identifier. The micro number should
+ * be changed when introducing functionality changes or major bug fixes that
+ * do not affect backward compatibility -- this is merely to make capabilities
+ * easily determined from the version number. Minor bugs do not require any
+ * modification to the version number.
+ */
+#define DT_VERS_1_0 DT_VERSION_NUMBER(1, 0, 0)
+#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_1_2_2 DT_VERSION_NUMBER(1, 2, 2)
+#define DT_VERS_1_3 DT_VERSION_NUMBER(1, 3, 0)
+#define DT_VERS_1_4 DT_VERSION_NUMBER(1, 4, 0)
+#define DT_VERS_1_4_1 DT_VERSION_NUMBER(1, 4, 1)
+#define DT_VERS_1_5 DT_VERSION_NUMBER(1, 5, 0)
+#define DT_VERS_1_6 DT_VERSION_NUMBER(1, 6, 0)
+#define DT_VERS_1_6_1 DT_VERSION_NUMBER(1, 6, 1)
+#define DT_VERS_1_6_2 DT_VERSION_NUMBER(1, 6, 2)
+#define DT_VERS_1_6_3 DT_VERSION_NUMBER(1, 6, 3)
+#define DT_VERS_1_7 DT_VERSION_NUMBER(1, 7, 0)
+#define DT_VERS_1_7_1 DT_VERSION_NUMBER(1, 7, 1)
+#define DT_VERS_1_8 DT_VERSION_NUMBER(1, 8, 0)
+#define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1)
+#define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0)
+#define DT_VERS_1_9_1 DT_VERSION_NUMBER(1, 9, 1)
+#define DT_VERS_1_10 DT_VERSION_NUMBER(1, 10, 0)
+#define DT_VERS_1_11 DT_VERSION_NUMBER(1, 11, 0)
+#define DT_VERS_1_12 DT_VERSION_NUMBER(1, 12, 0)
+#define DT_VERS_1_12_1 DT_VERSION_NUMBER(1, 12, 1)
+#define DT_VERS_1_13 DT_VERSION_NUMBER(1, 13, 0)
+#define DT_VERS_LATEST DT_VERS_1_13
+#define DT_VERS_STRING "Sun D 1.13"
+
+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 */
+ DT_VERS_1_3, /* D API 1.3 Solaris Express 10/06 */
+ DT_VERS_1_4, /* D API 1.4 Solaris Express 2/07 */
+ DT_VERS_1_4_1, /* D API 1.4.1 Solaris Express 4/07 */
+ DT_VERS_1_5, /* D API 1.5 Solaris Express 7/07 */
+ DT_VERS_1_6, /* D API 1.6 */
+ DT_VERS_1_6_1, /* D API 1.6.1 */
+ DT_VERS_1_6_2, /* D API 1.6.2 */
+ DT_VERS_1_6_3, /* D API 1.6.3 */
+ DT_VERS_1_7, /* D API 1.7 */
+ DT_VERS_1_7_1, /* D API 1.7.1 */
+ DT_VERS_1_8, /* D API 1.8 */
+ DT_VERS_1_8_1, /* D API 1.8.1 */
+ DT_VERS_1_9, /* D API 1.9 */
+ DT_VERS_1_9_1, /* D API 1.9.1 */
+ DT_VERS_1_10, /* D API 1.10 */
+ DT_VERS_1_11, /* D API 1.11 */
+ DT_VERS_1_12, /* D API 1.12 */
+ DT_VERS_1_12_1, /* D API 1.12.1 */
+ DT_VERS_1_13, /* D API 1.13 */
+ 0
+};
+
+/*
+ * Global variables that are formatted on FreeBSD based on the kernel file name.
+ */
+#ifndef illumos
+static char curthread_str[MAXPATHLEN];
+static char intmtx_str[MAXPATHLEN];
+static char threadmtx_str[MAXPATHLEN];
+static char rwlock_str[MAXPATHLEN];
+static char sxlock_str[MAXPATHLEN];
+#endif
+
+/*
+ * Table of global identifiers. This is used to populate the global identifier
+ * hash when a new dtrace client open occurs. For more info see dt_ident.h.
+ * The global identifiers that represent functions use the dt_idops_func ops
+ * and specify the private data pointer as a prototype string which is parsed
+ * when the identifier is first encountered. These prototypes look like ANSI
+ * C function prototypes except that the special symbol "@" can be used as a
+ * wildcard to represent a single parameter of any type (i.e. any dt_node_t).
+ * The standard "..." notation can also be used to represent varargs. An empty
+ * parameter list is taken to mean void (that is, no arguments are permitted).
+ * A parameter enclosed in square brackets (e.g. "[int]") denotes an optional
+ * argument.
+ */
+static const dt_ident_t _dtrace_globals[] = {
+{ "alloca", DT_IDENT_FUNC, 0, DIF_SUBR_ALLOCA, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void *(size_t)" },
+{ "arg0", DT_IDENT_SCALAR, 0, DIF_VAR_ARG0, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "arg1", DT_IDENT_SCALAR, 0, DIF_VAR_ARG1, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "arg2", DT_IDENT_SCALAR, 0, DIF_VAR_ARG2, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "arg3", DT_IDENT_SCALAR, 0, DIF_VAR_ARG3, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "arg4", DT_IDENT_SCALAR, 0, DIF_VAR_ARG4, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "arg5", DT_IDENT_SCALAR, 0, DIF_VAR_ARG5, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "arg6", DT_IDENT_SCALAR, 0, DIF_VAR_ARG6, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "arg7", DT_IDENT_SCALAR, 0, DIF_VAR_ARG7, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "arg8", DT_IDENT_SCALAR, 0, DIF_VAR_ARG8, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "arg9", DT_IDENT_SCALAR, 0, DIF_VAR_ARG9, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "args", DT_IDENT_ARRAY, 0, DIF_VAR_ARGS, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_args, NULL },
+{ "avg", DT_IDENT_AGGFUNC, 0, DTRACEAGG_AVG, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@)" },
+{ "basename", DT_IDENT_FUNC, 0, DIF_SUBR_BASENAME, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "string(const char *)" },
+{ "bcopy", DT_IDENT_FUNC, 0, DIF_SUBR_BCOPY, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(void *, void *, size_t)" },
+{ "breakpoint", DT_IDENT_ACTFUNC, 0, DT_ACT_BREAKPOINT,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void()" },
+{ "caller", DT_IDENT_SCALAR, 0, DIF_VAR_CALLER, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "uintptr_t" },
+{ "chill", DT_IDENT_ACTFUNC, 0, DT_ACT_CHILL, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(int)" },
+{ "cleanpath", DT_IDENT_FUNC, 0, DIF_SUBR_CLEANPATH, DT_ATTR_STABCMN,
+ DT_VERS_1_0, &dt_idops_func, "string(const char *)" },
+{ "clear", DT_IDENT_ACTFUNC, 0, DT_ACT_CLEAR, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(...)" },
+{ "commit", DT_IDENT_ACTFUNC, 0, DT_ACT_COMMIT, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(int)" },
+{ "copyin", DT_IDENT_FUNC, 0, DIF_SUBR_COPYIN, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void *(uintptr_t, size_t)" },
+{ "copyinstr", DT_IDENT_FUNC, 0, DIF_SUBR_COPYINSTR,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "string(uintptr_t, [size_t])" },
+{ "copyinto", DT_IDENT_FUNC, 0, DIF_SUBR_COPYINTO, DT_ATTR_STABCMN,
+ DT_VERS_1_0, &dt_idops_func, "void(uintptr_t, size_t, void *)" },
+{ "copyout", DT_IDENT_FUNC, 0, DIF_SUBR_COPYOUT, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(void *, uintptr_t, size_t)" },
+{ "copyoutstr", DT_IDENT_FUNC, 0, DIF_SUBR_COPYOUTSTR,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(char *, uintptr_t, size_t)" },
+{ "count", DT_IDENT_AGGFUNC, 0, DTRACEAGG_COUNT, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void()" },
+{ "curthread", DT_IDENT_SCALAR, 0, DIF_VAR_CURTHREAD,
+ { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE,
+ DTRACE_CLASS_COMMON }, DT_VERS_1_0,
+#ifdef illumos
+ &dt_idops_type, "genunix`kthread_t *" },
+#else
+ &dt_idops_type, curthread_str },
+#endif
+{ "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "string(void *, int64_t)" },
+{ "denormalize", DT_IDENT_ACTFUNC, 0, DT_ACT_DENORMALIZE, DT_ATTR_STABCMN,
+ DT_VERS_1_0, &dt_idops_func, "void(...)" },
+{ "dirname", DT_IDENT_FUNC, 0, DIF_SUBR_DIRNAME, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "string(const char *)" },
+{ "discard", DT_IDENT_ACTFUNC, 0, DT_ACT_DISCARD, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(int)" },
+{ "epid", DT_IDENT_SCALAR, 0, DIF_VAR_EPID, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "uint_t" },
+{ "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int" },
+{ "execargs", DT_IDENT_SCALAR, 0, DIF_VAR_EXECARGS,
+ DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
+{ "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME,
+ DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
+{ "exit", DT_IDENT_ACTFUNC, 0, DT_ACT_EXIT, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(int)" },
+{ "freopen", DT_IDENT_ACTFUNC, 0, DT_ACT_FREOPEN, DT_ATTR_STABCMN,
+ DT_VERS_1_1, &dt_idops_func, "void(@, ...)" },
+{ "ftruncate", DT_IDENT_ACTFUNC, 0, DT_ACT_FTRUNCATE, DT_ATTR_STABCMN,
+ DT_VERS_1_0, &dt_idops_func, "void()" },
+{ "func", DT_IDENT_ACTFUNC, 0, DT_ACT_SYM, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" },
+{ "getmajor", DT_IDENT_FUNC, 0, DIF_SUBR_GETMAJOR,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "genunix`major_t(genunix`dev_t)" },
+{ "getminor", DT_IDENT_FUNC, 0, DIF_SUBR_GETMINOR,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "genunix`minor_t(genunix`dev_t)" },
+{ "htonl", DT_IDENT_FUNC, 0, DIF_SUBR_HTONL, DT_ATTR_EVOLCMN, DT_VERS_1_3,
+ &dt_idops_func, "uint32_t(uint32_t)" },
+{ "htonll", DT_IDENT_FUNC, 0, DIF_SUBR_HTONLL, DT_ATTR_EVOLCMN, DT_VERS_1_3,
+ &dt_idops_func, "uint64_t(uint64_t)" },
+{ "htons", DT_IDENT_FUNC, 0, DIF_SUBR_HTONS, DT_ATTR_EVOLCMN, DT_VERS_1_3,
+ &dt_idops_func, "uint16_t(uint16_t)" },
+{ "getf", DT_IDENT_FUNC, 0, DIF_SUBR_GETF, DT_ATTR_STABCMN, DT_VERS_1_10,
+ &dt_idops_func, "file_t *(int)" },
+{ "gid", DT_IDENT_SCALAR, 0, DIF_VAR_GID, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "gid_t" },
+{ "id", DT_IDENT_SCALAR, 0, DIF_VAR_ID, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "uint_t" },
+{ "index", DT_IDENT_FUNC, 0, DIF_SUBR_INDEX, DT_ATTR_STABCMN, DT_VERS_1_1,
+ &dt_idops_func, "int(const char *, const char *, [int])" },
+{ "inet_ntoa", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA, DT_ATTR_STABCMN,
+#ifdef illumos
+ DT_VERS_1_5, &dt_idops_func, "string(ipaddr_t *)" },
+#else
+ DT_VERS_1_5, &dt_idops_func, "string(in_addr_t *)" },
+#endif
+{ "inet_ntoa6", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA6, DT_ATTR_STABCMN,
+#ifdef illumos
+ DT_VERS_1_5, &dt_idops_func, "string(in6_addr_t *)" },
+#else
+ DT_VERS_1_5, &dt_idops_func, "string(struct in6_addr *)" },
+#endif
+{ "inet_ntop", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOP, DT_ATTR_STABCMN,
+ DT_VERS_1_5, &dt_idops_func, "string(int, void *)" },
+{ "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "uint_t" },
+#ifdef __FreeBSD__
+{ "jailname", DT_IDENT_SCALAR, 0, DIF_VAR_JAILNAME,
+ DT_ATTR_STABCMN, DT_VERS_1_13, &dt_idops_type, "string" },
+{ "jid", DT_IDENT_SCALAR, 0, DIF_VAR_JID, DT_ATTR_STABCMN, DT_VERS_1_13,
+ &dt_idops_type, "int" },
+#endif
+{ "json", DT_IDENT_FUNC, 0, DIF_SUBR_JSON, DT_ATTR_STABCMN, DT_VERS_1_11,
+ &dt_idops_func, "string(const char *, const char *)" },
+{ "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "stack(...)" },
+{ "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "string(int64_t, [int])" },
+{ "llquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LLQUANTIZE, DT_ATTR_STABCMN,
+ DT_VERS_1_7, &dt_idops_func,
+ "void(@, int32_t, int32_t, int32_t, int32_t, ...)" },
+{ "lquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LQUANTIZE,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@, int32_t, int32_t, ...)" },
+{ "max", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MAX, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@)" },
+{ "memref", DT_IDENT_FUNC, 0, DIF_SUBR_MEMREF, DT_ATTR_STABCMN, DT_VERS_1_1,
+ &dt_idops_func, "uintptr_t *(void *, size_t)" },
+#ifndef illumos
+{ "memstr", DT_IDENT_FUNC, 0, DIF_SUBR_MEMSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "string(void *, char, size_t)" },
+#endif
+{ "min", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MIN, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@)" },
+{ "mod", DT_IDENT_ACTFUNC, 0, DT_ACT_MOD, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" },
+#ifdef illumos
+{ "msgdsize", DT_IDENT_FUNC, 0, DIF_SUBR_MSGDSIZE,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "size_t(mblk_t *)" },
+{ "msgsize", DT_IDENT_FUNC, 0, DIF_SUBR_MSGSIZE,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "size_t(mblk_t *)" },
+{ "mutex_owned", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNED,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "int(genunix`kmutex_t *)" },
+{ "mutex_owner", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNER,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "genunix`kthread_t *(genunix`kmutex_t *)" },
+{ "mutex_type_adaptive", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_ADAPTIVE,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "int(genunix`kmutex_t *)" },
+{ "mutex_type_spin", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_SPIN,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "int(genunix`kmutex_t *)" },
+#else
+{ "mutex_owned", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNED,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, intmtx_str },
+{ "mutex_owner", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNER,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, threadmtx_str },
+{ "mutex_type_adaptive", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_ADAPTIVE,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, intmtx_str },
+{ "mutex_type_spin", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_SPIN,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, intmtx_str },
+#endif
+{ "ntohl", DT_IDENT_FUNC, 0, DIF_SUBR_NTOHL, DT_ATTR_EVOLCMN, DT_VERS_1_3,
+ &dt_idops_func, "uint32_t(uint32_t)" },
+{ "ntohll", DT_IDENT_FUNC, 0, DIF_SUBR_NTOHLL, DT_ATTR_EVOLCMN, DT_VERS_1_3,
+ &dt_idops_func, "uint64_t(uint64_t)" },
+{ "ntohs", DT_IDENT_FUNC, 0, DIF_SUBR_NTOHS, DT_ATTR_EVOLCMN, DT_VERS_1_3,
+ &dt_idops_func, "uint16_t(uint16_t)" },
+{ "normalize", DT_IDENT_ACTFUNC, 0, DT_ACT_NORMALIZE, DT_ATTR_STABCMN,
+ DT_VERS_1_0, &dt_idops_func, "void(...)" },
+{ "panic", DT_IDENT_ACTFUNC, 0, DT_ACT_PANIC, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void()" },
+{ "pid", DT_IDENT_SCALAR, 0, DIF_VAR_PID, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "pid_t" },
+{ "ppid", DT_IDENT_SCALAR, 0, DIF_VAR_PPID, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "pid_t" },
+{ "print", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINT, DT_ATTR_STABCMN, DT_VERS_1_9,
+ &dt_idops_func, "void(@)" },
+{ "printa", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTA, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@, ...)" },
+{ "printf", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTF, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@, ...)" },
+{ "printm", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTM, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(size_t, uintptr_t *)" },
+{ "probefunc", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEFUNC,
+ DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
+{ "probemod", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEMOD,
+ DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
+{ "probename", DT_IDENT_SCALAR, 0, DIF_VAR_PROBENAME,
+ DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
+{ "probeprov", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEPROV,
+ DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
+{ "progenyof", DT_IDENT_FUNC, 0, DIF_SUBR_PROGENYOF,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "int(pid_t)" },
+{ "quantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_QUANTIZE,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@, ...)" },
+{ "raise", DT_IDENT_ACTFUNC, 0, DT_ACT_RAISE, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(int)" },
+{ "rand", DT_IDENT_FUNC, 0, DIF_SUBR_RAND, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "int()" },
+{ "rindex", DT_IDENT_FUNC, 0, DIF_SUBR_RINDEX, DT_ATTR_STABCMN, DT_VERS_1_1,
+ &dt_idops_func, "int(const char *, const char *, [int])" },
+#ifdef illumos
+{ "rw_iswriter", DT_IDENT_FUNC, 0, DIF_SUBR_RW_ISWRITER,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "int(genunix`krwlock_t *)" },
+{ "rw_read_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_READ_HELD,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "int(genunix`krwlock_t *)" },
+{ "rw_write_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_WRITE_HELD,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, "int(genunix`krwlock_t *)" },
+#else
+{ "rw_iswriter", DT_IDENT_FUNC, 0, DIF_SUBR_RW_ISWRITER,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, rwlock_str },
+{ "rw_read_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_READ_HELD,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, rwlock_str },
+{ "rw_write_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_WRITE_HELD,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, rwlock_str },
+#endif
+{ "self", DT_IDENT_PTR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "void" },
+{ "setopt", DT_IDENT_ACTFUNC, 0, DT_ACT_SETOPT, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "void(const char *, [const char *])" },
+{ "speculate", DT_IDENT_ACTFUNC, 0, DT_ACT_SPECULATE,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(int)" },
+{ "speculation", DT_IDENT_FUNC, 0, DIF_SUBR_SPECULATION,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "int()" },
+{ "stack", DT_IDENT_ACTFUNC, 0, DT_ACT_STACK, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "stack(...)" },
+{ "stackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_STACKDEPTH,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "uint32_t" },
+{ "stddev", DT_IDENT_AGGFUNC, 0, DTRACEAGG_STDDEV, DT_ATTR_STABCMN,
+ DT_VERS_1_6, &dt_idops_func, "void(@)" },
+{ "stop", DT_IDENT_ACTFUNC, 0, DT_ACT_STOP, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void()" },
+{ "strchr", DT_IDENT_FUNC, 0, DIF_SUBR_STRCHR, DT_ATTR_STABCMN, DT_VERS_1_1,
+ &dt_idops_func, "string(const char *, char)" },
+{ "strlen", DT_IDENT_FUNC, 0, DIF_SUBR_STRLEN, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "size_t(const char *)" },
+{ "strjoin", DT_IDENT_FUNC, 0, DIF_SUBR_STRJOIN, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "string(const char *, const char *)" },
+{ "strrchr", DT_IDENT_FUNC, 0, DIF_SUBR_STRRCHR, DT_ATTR_STABCMN, DT_VERS_1_1,
+ &dt_idops_func, "string(const char *, char)" },
+{ "strstr", DT_IDENT_FUNC, 0, DIF_SUBR_STRSTR, DT_ATTR_STABCMN, DT_VERS_1_1,
+ &dt_idops_func, "string(const char *, const char *)" },
+{ "strtok", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOK, DT_ATTR_STABCMN, DT_VERS_1_1,
+ &dt_idops_func, "string(const char *, const char *)" },
+{ "strtoll", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOLL, DT_ATTR_STABCMN, DT_VERS_1_11,
+ &dt_idops_func, "int64_t(const char *, [int])" },
+{ "substr", DT_IDENT_FUNC, 0, DIF_SUBR_SUBSTR, DT_ATTR_STABCMN, DT_VERS_1_1,
+ &dt_idops_func, "string(const char *, int, [int])" },
+{ "sum", DT_IDENT_AGGFUNC, 0, DTRACEAGG_SUM, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@)" },
+#ifndef illumos
+{ "sx_isexclusive", DT_IDENT_FUNC, 0, DIF_SUBR_SX_ISEXCLUSIVE,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, sxlock_str },
+{ "sx_shared_held", DT_IDENT_FUNC, 0, DIF_SUBR_SX_SHARED_HELD,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, sxlock_str },
+{ "sx_exclusive_held", DT_IDENT_FUNC, 0, DIF_SUBR_SX_EXCLUSIVE_HELD,
+ DT_ATTR_EVOLCMN, DT_VERS_1_0,
+ &dt_idops_func, sxlock_str },
+#endif
+{ "sym", DT_IDENT_ACTFUNC, 0, DT_ACT_SYM, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" },
+{ "system", DT_IDENT_ACTFUNC, 0, DT_ACT_SYSTEM, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@, ...)" },
+{ "this", DT_IDENT_PTR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "void" },
+{ "tid", DT_IDENT_SCALAR, 0, DIF_VAR_TID, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "id_t" },
+{ "timestamp", DT_IDENT_SCALAR, 0, DIF_VAR_TIMESTAMP,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "uint64_t" },
+{ "tolower", DT_IDENT_FUNC, 0, DIF_SUBR_TOLOWER, DT_ATTR_STABCMN, DT_VERS_1_8,
+ &dt_idops_func, "string(const char *)" },
+{ "toupper", DT_IDENT_FUNC, 0, DIF_SUBR_TOUPPER, DT_ATTR_STABCMN, DT_VERS_1_8,
+ &dt_idops_func, "string(const char *)" },
+{ "trace", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACE, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@)" },
+{ "tracemem", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACEMEM,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "void(@, size_t, ...)" },
+{ "trunc", DT_IDENT_ACTFUNC, 0, DT_ACT_TRUNC, DT_ATTR_STABCMN,
+ DT_VERS_1_0, &dt_idops_func, "void(...)" },
+{ "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
+{ "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_type, "uint64_t" },
+{ "ufunc", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
+{ "uid", DT_IDENT_SCALAR, 0, DIF_VAR_UID, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "uid_t" },
+{ "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
+{ "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_regs, NULL },
+{ "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "stack(...)" },
+{ "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH,
+ DT_ATTR_STABCMN, DT_VERS_1_2,
+ &dt_idops_type, "uint32_t" },
+{ "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
+{ "vtimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_VTIMESTAMP,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "uint64_t" },
+{ "walltimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_WALLTIMESTAMP,
+ DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_type, "int64_t" },
+{ "zonename", DT_IDENT_SCALAR, 0, DIF_VAR_ZONENAME,
+ DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
+
+#ifndef illumos
+{ "cpu", DT_IDENT_SCALAR, 0, DIF_VAR_CPU,
+ DT_ATTR_STABCMN, DT_VERS_1_6_3, &dt_idops_type, "int" },
+#endif
+
+{ NULL, 0, 0, 0, { 0, 0, 0 }, 0, NULL, NULL }
+};
+
+/*
+ * Tables of ILP32 intrinsic integer and floating-point type templates to use
+ * to populate the dynamic "C" CTF type container.
+ */
+static const dt_intrinsic_t _dtrace_intrinsics_32[] = {
+{ "void", { CTF_INT_SIGNED, 0, 0 }, CTF_K_INTEGER },
+{ "signed", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER },
+{ "int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "long", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "signed char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "signed short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER },
+{ "signed int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "signed long", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "signed long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "unsigned char", { CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "unsigned short", { 0, 0, 16 }, CTF_K_INTEGER },
+{ "unsigned int", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned long", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned long long", { 0, 0, 64 }, CTF_K_INTEGER },
+{ "_Bool", { CTF_INT_BOOL, 0, 8 }, CTF_K_INTEGER },
+{ "float", { CTF_FP_SINGLE, 0, 32 }, CTF_K_FLOAT },
+{ "double", { CTF_FP_DOUBLE, 0, 64 }, CTF_K_FLOAT },
+{ "long double", { CTF_FP_LDOUBLE, 0, 128 }, CTF_K_FLOAT },
+{ "float imaginary", { CTF_FP_IMAGRY, 0, 32 }, CTF_K_FLOAT },
+{ "double imaginary", { CTF_FP_DIMAGRY, 0, 64 }, CTF_K_FLOAT },
+{ "long double imaginary", { CTF_FP_LDIMAGRY, 0, 128 }, CTF_K_FLOAT },
+{ "float complex", { CTF_FP_CPLX, 0, 64 }, CTF_K_FLOAT },
+{ "double complex", { CTF_FP_DCPLX, 0, 128 }, CTF_K_FLOAT },
+{ "long double complex", { CTF_FP_LDCPLX, 0, 256 }, CTF_K_FLOAT },
+{ NULL, { 0, 0, 0 }, 0 }
+};
+
+/*
+ * Tables of LP64 intrinsic integer and floating-point type templates to use
+ * to populate the dynamic "C" CTF type container.
+ */
+static const dt_intrinsic_t _dtrace_intrinsics_64[] = {
+{ "void", { CTF_INT_SIGNED, 0, 0 }, CTF_K_INTEGER },
+{ "signed", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER },
+{ "int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "signed char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "signed short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER },
+{ "signed int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "signed long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "signed long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "unsigned char", { CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "unsigned short", { 0, 0, 16 }, CTF_K_INTEGER },
+{ "unsigned int", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned long", { 0, 0, 64 }, CTF_K_INTEGER },
+{ "unsigned long long", { 0, 0, 64 }, CTF_K_INTEGER },
+{ "_Bool", { CTF_INT_BOOL, 0, 8 }, CTF_K_INTEGER },
+{ "float", { CTF_FP_SINGLE, 0, 32 }, CTF_K_FLOAT },
+{ "double", { CTF_FP_DOUBLE, 0, 64 }, CTF_K_FLOAT },
+{ "long double", { CTF_FP_LDOUBLE, 0, 128 }, CTF_K_FLOAT },
+{ "float imaginary", { CTF_FP_IMAGRY, 0, 32 }, CTF_K_FLOAT },
+{ "double imaginary", { CTF_FP_DIMAGRY, 0, 64 }, CTF_K_FLOAT },
+{ "long double imaginary", { CTF_FP_LDIMAGRY, 0, 128 }, CTF_K_FLOAT },
+{ "float complex", { CTF_FP_CPLX, 0, 64 }, CTF_K_FLOAT },
+{ "double complex", { CTF_FP_DCPLX, 0, 128 }, CTF_K_FLOAT },
+{ "long double complex", { CTF_FP_LDCPLX, 0, 256 }, CTF_K_FLOAT },
+{ NULL, { 0, 0, 0 }, 0 }
+};
+
+/*
+ * Tables of ILP32 typedefs to use to populate the dynamic "D" CTF container.
+ * These aliases ensure that D definitions can use typical <sys/types.h> names.
+ */
+static const dt_typedef_t _dtrace_typedefs_32[] = {
+{ "char", "int8_t" },
+{ "short", "int16_t" },
+{ "int", "int32_t" },
+{ "long long", "int64_t" },
+{ "int", "intptr_t" },
+{ "int", "ssize_t" },
+{ "unsigned char", "uint8_t" },
+{ "unsigned short", "uint16_t" },
+{ "unsigned", "uint32_t" },
+{ "unsigned long long", "uint64_t" },
+{ "unsigned char", "uchar_t" },
+{ "unsigned short", "ushort_t" },
+{ "unsigned", "uint_t" },
+{ "unsigned long", "ulong_t" },
+{ "unsigned long long", "u_longlong_t" },
+{ "int", "ptrdiff_t" },
+{ "unsigned", "uintptr_t" },
+{ "unsigned", "size_t" },
+{ "long", "id_t" },
+{ "long", "pid_t" },
+{ NULL, NULL }
+};
+
+/*
+ * Tables of LP64 typedefs to use to populate the dynamic "D" CTF container.
+ * These aliases ensure that D definitions can use typical <sys/types.h> names.
+ */
+static const dt_typedef_t _dtrace_typedefs_64[] = {
+{ "char", "int8_t" },
+{ "short", "int16_t" },
+{ "int", "int32_t" },
+{ "long", "int64_t" },
+{ "long", "intptr_t" },
+{ "long", "ssize_t" },
+{ "unsigned char", "uint8_t" },
+{ "unsigned short", "uint16_t" },
+{ "unsigned", "uint32_t" },
+{ "unsigned long", "uint64_t" },
+{ "unsigned char", "uchar_t" },
+{ "unsigned short", "ushort_t" },
+{ "unsigned", "uint_t" },
+{ "unsigned long", "ulong_t" },
+{ "unsigned long long", "u_longlong_t" },
+{ "long", "ptrdiff_t" },
+{ "unsigned long", "uintptr_t" },
+{ "unsigned long", "size_t" },
+{ "int", "id_t" },
+{ "int", "pid_t" },
+{ NULL, NULL }
+};
+
+/*
+ * Tables of ILP32 integer type templates used to populate the dtp->dt_ints[]
+ * cache when a new dtrace client open occurs. Values are set by dtrace_open().
+ */
+static const dt_intdesc_t _dtrace_ints_32[] = {
+{ "int", NULL, CTF_ERR, 0x7fffffffULL },
+{ "unsigned int", NULL, CTF_ERR, 0xffffffffULL },
+{ "long", NULL, CTF_ERR, 0x7fffffffULL },
+{ "unsigned long", NULL, CTF_ERR, 0xffffffffULL },
+{ "long long", NULL, CTF_ERR, 0x7fffffffffffffffULL },
+{ "unsigned long long", NULL, CTF_ERR, 0xffffffffffffffffULL }
+};
+
+/*
+ * Tables of LP64 integer type templates used to populate the dtp->dt_ints[]
+ * cache when a new dtrace client open occurs. Values are set by dtrace_open().
+ */
+static const dt_intdesc_t _dtrace_ints_64[] = {
+{ "int", NULL, CTF_ERR, 0x7fffffffULL },
+{ "unsigned int", NULL, CTF_ERR, 0xffffffffULL },
+{ "long", NULL, CTF_ERR, 0x7fffffffffffffffULL },
+{ "unsigned long", NULL, CTF_ERR, 0xffffffffffffffffULL },
+{ "long long", NULL, CTF_ERR, 0x7fffffffffffffffULL },
+{ "unsigned long long", NULL, CTF_ERR, 0xffffffffffffffffULL }
+};
+
+/*
+ * Table of macro variable templates used to populate the macro identifier hash
+ * when a new dtrace client open occurs. Values are set by dtrace_update().
+ */
+static const dt_ident_t _dtrace_macros[] = {
+{ "egid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "euid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "gid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "pid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "pgid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "ppid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "projid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "sid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "taskid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "target", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ "uid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 },
+{ NULL, 0, 0, 0, { 0, 0, 0 }, 0 }
+};
+
+/*
+ * Hard-wired definition string to be compiled and cached every time a new
+ * DTrace library handle is initialized. This string should only be used to
+ * contain definitions that should be present regardless of DTRACE_O_NOLIBS.
+ */
+static const char _dtrace_hardwire[] = "\
+inline long NULL = 0; \n\
+#pragma D binding \"1.0\" NULL\n\
+";
+
+/*
+ * Default DTrace configuration to use when opening libdtrace DTRACE_O_NODEV.
+ * If DTRACE_O_NODEV is not set, we load the configuration from the kernel.
+ * The use of CTF_MODEL_NATIVE is more subtle than it might appear: we are
+ * relying on the fact that when running dtrace(1M), isaexec will invoke the
+ * binary with the same bitness as the kernel, which is what we want by default
+ * when generating our DIF. The user can override the choice using oflags.
+ */
+static const dtrace_conf_t _dtrace_conf = {
+ DIF_VERSION, /* dtc_difversion */
+ DIF_DIR_NREGS, /* dtc_difintregs */
+ DIF_DTR_NREGS, /* dtc_diftupregs */
+ CTF_MODEL_NATIVE /* dtc_ctfmodel */
+};
+
+const dtrace_attribute_t _dtrace_maxattr = {
+ DTRACE_STABILITY_MAX,
+ DTRACE_STABILITY_MAX,
+ DTRACE_CLASS_MAX
+};
+
+const dtrace_attribute_t _dtrace_defattr = {
+ DTRACE_STABILITY_STABLE,
+ DTRACE_STABILITY_STABLE,
+ DTRACE_CLASS_COMMON
+};
+
+const dtrace_attribute_t _dtrace_symattr = {
+ DTRACE_STABILITY_PRIVATE,
+ DTRACE_STABILITY_PRIVATE,
+ DTRACE_CLASS_UNKNOWN
+};
+
+const dtrace_attribute_t _dtrace_typattr = {
+ DTRACE_STABILITY_PRIVATE,
+ DTRACE_STABILITY_PRIVATE,
+ DTRACE_CLASS_UNKNOWN
+};
+
+const dtrace_attribute_t _dtrace_prvattr = {
+ DTRACE_STABILITY_PRIVATE,
+ DTRACE_STABILITY_PRIVATE,
+ DTRACE_CLASS_UNKNOWN
+};
+
+const dtrace_pattr_t _dtrace_prvdesc = {
+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },
+};
+
+#ifdef illumos
+const char *_dtrace_defcpp = "/usr/ccs/lib/cpp"; /* default cpp(1) to invoke */
+const char *_dtrace_defld = "/usr/ccs/bin/ld"; /* default ld(1) to invoke */
+#else
+const char *_dtrace_defcpp = "cpp"; /* default cpp(1) to invoke */
+const char *_dtrace_defld = "ld"; /* default ld(1) to invoke */
+const char *_dtrace_defobjcopy = "objcopy"; /* default objcopy(1) to invoke */
+#endif
+
+const char *_dtrace_libdir = "/usr/lib/dtrace"; /* default library directory */
+#ifdef illumos
+const char *_dtrace_provdir = "/dev/dtrace/provider"; /* provider directory */
+#else
+const char *_dtrace_libdir32 = "/usr/lib32/dtrace";
+const char *_dtrace_provdir = "/dev/dtrace"; /* provider directory */
+#endif
+
+int _dtrace_strbuckets = 211; /* default number of hash buckets (prime) */
+int _dtrace_intbuckets = 256; /* default number of integer buckets (Pof2) */
+uint_t _dtrace_strsize = 256; /* default size of string intrinsic type */
+uint_t _dtrace_stkindent = 14; /* default whitespace indent for stack/ustack */
+uint_t _dtrace_pidbuckets = 64; /* default number of pid hash buckets */
+uint_t _dtrace_pidlrulim = 8; /* default number of pid handles to cache */
+size_t _dtrace_bufsize = 512; /* default dt_buf_create() size */
+int _dtrace_argmax = 32; /* default maximum number of probe arguments */
+
+int _dtrace_debug = 0; /* debug messages enabled (off) */
+const char *const _dtrace_version = DT_VERS_STRING; /* API version string */
+int _dtrace_rdvers = RD_VERSION; /* rtld_db feature version */
+
+typedef struct dt_fdlist {
+ int *df_fds; /* array of provider driver file descriptors */
+ uint_t df_ents; /* number of valid elements in df_fds[] */
+ uint_t df_size; /* size of df_fds[] */
+} dt_fdlist_t;
+
+#ifdef illumos
+#pragma init(_dtrace_init)
+#else
+void _dtrace_init(void) __attribute__ ((constructor));
+#endif
+void
+_dtrace_init(void)
+{
+ _dtrace_debug = getenv("DTRACE_DEBUG") != NULL;
+
+ for (; _dtrace_rdvers > 0; _dtrace_rdvers--) {
+ if (rd_init(_dtrace_rdvers) == RD_OK)
+ break;
+ }
+#if defined(__i386__)
+ /* make long doubles 64 bits -sson */
+ (void) fpsetprec(FP_PE);
+#endif
+}
+
+static dtrace_hdl_t *
+set_open_errno(dtrace_hdl_t *dtp, int *errp, int err)
+{
+ if (dtp != NULL)
+ dtrace_close(dtp);
+ if (errp != NULL)
+ *errp = err;
+ return (NULL);
+}
+
+static void
+dt_provmod_open(dt_provmod_t **provmod, dt_fdlist_t *dfp)
+{
+ dt_provmod_t *prov;
+ char path[PATH_MAX];
+ int fd;
+#ifdef illumos
+ struct dirent *dp, *ep;
+ DIR *dirp;
+
+ if ((dirp = opendir(_dtrace_provdir)) == NULL)
+ return; /* failed to open directory; just skip it */
+
+ ep = alloca(sizeof (struct dirent) + PATH_MAX + 1);
+ bzero(ep, sizeof (struct dirent) + PATH_MAX + 1);
+
+ while (readdir_r(dirp, ep, &dp) == 0 && dp != NULL) {
+ if (dp->d_name[0] == '.')
+ continue; /* skip "." and ".." */
+
+ if (dfp->df_ents == dfp->df_size) {
+ uint_t size = dfp->df_size ? dfp->df_size * 2 : 16;
+ int *fds = realloc(dfp->df_fds, size * sizeof (int));
+
+ if (fds == NULL)
+ break; /* skip the rest of this directory */
+
+ dfp->df_fds = fds;
+ dfp->df_size = size;
+ }
+
+ (void) snprintf(path, sizeof (path), "%s/%s",
+ _dtrace_provdir, dp->d_name);
+
+ if ((fd = open(path, O_RDONLY)) == -1)
+ continue; /* failed to open driver; just skip it */
+
+ if (((prov = malloc(sizeof (dt_provmod_t))) == NULL) ||
+ (prov->dp_name = malloc(strlen(dp->d_name) + 1)) == NULL) {
+ free(prov);
+ (void) close(fd);
+ break;
+ }
+
+ (void) strcpy(prov->dp_name, dp->d_name);
+ prov->dp_next = *provmod;
+ *provmod = prov;
+
+ dt_dprintf("opened provider %s\n", dp->d_name);
+ dfp->df_fds[dfp->df_ents++] = fd;
+ }
+
+ (void) closedir(dirp);
+#else /* !illumos */
+ char *p;
+ char *p1;
+ char *p_providers = NULL;
+ int error;
+ size_t len = 0;
+
+ /*
+ * Loop to allocate/reallocate memory for the string of provider
+ * names and retry:
+ */
+ while(1) {
+ /*
+ * The first time around, get the string length. The next time,
+ * hopefully we've allocated enough memory.
+ */
+ error = sysctlbyname("debug.dtrace.providers",p_providers,&len,NULL,0);
+ if (len == 0)
+ /* No providers? That's strange. Where's dtrace? */
+ break;
+ else if (error == 0 && p_providers == NULL) {
+ /*
+ * Allocate the initial memory which should be enough
+ * unless another provider loads before we have
+ * time to go back and get the string.
+ */
+ if ((p_providers = malloc(len)) == NULL)
+ /* How do we report errors here? */
+ return;
+ } else if (error == -1 && errno == ENOMEM) {
+ /*
+ * The current buffer isn't large enough, so
+ * reallocate it. We normally won't need to do this
+ * because providers aren't being loaded all the time.
+ */
+ if ((p = realloc(p_providers,len)) == NULL) {
+ free(p_providers);
+ /* How do we report errors here? */
+ return;
+ }
+ p_providers = p;
+ } else
+ break;
+ }
+
+ /* Check if we got a string of provider names: */
+ if (error == 0 && len > 0 && p_providers != NULL) {
+ p = p_providers;
+
+ /*
+ * Parse the string containing the space separated
+ * provider names.
+ */
+ while ((p1 = strsep(&p," ")) != NULL) {
+ if (dfp->df_ents == dfp->df_size) {
+ uint_t size = dfp->df_size ? dfp->df_size * 2 : 16;
+ int *fds = realloc(dfp->df_fds, size * sizeof (int));
+
+ if (fds == NULL)
+ break;
+
+ dfp->df_fds = fds;
+ dfp->df_size = size;
+ }
+
+ (void) snprintf(path, sizeof (path), "/dev/dtrace/%s", p1);
+
+ if ((fd = open(path, O_RDONLY | O_CLOEXEC)) == -1)
+ continue; /* failed to open driver; just skip it */
+
+ if (((prov = malloc(sizeof (dt_provmod_t))) == NULL) ||
+ (prov->dp_name = malloc(strlen(p1) + 1)) == NULL) {
+ free(prov);
+ (void) close(fd);
+ break;
+ }
+
+ (void) strcpy(prov->dp_name, p1);
+ prov->dp_next = *provmod;
+ *provmod = prov;
+
+ dt_dprintf("opened provider %s\n", p1);
+ dfp->df_fds[dfp->df_ents++] = fd;
+ }
+ }
+ if (p_providers != NULL)
+ free(p_providers);
+#endif /* illumos */
+}
+
+static void
+dt_provmod_destroy(dt_provmod_t **provmod)
+{
+ dt_provmod_t *next, *current;
+
+ for (current = *provmod; current != NULL; current = next) {
+ next = current->dp_next;
+ free(current->dp_name);
+ free(current);
+ }
+
+ *provmod = NULL;
+}
+
+#ifdef illumos
+static const char *
+dt_get_sysinfo(int cmd, char *buf, size_t len)
+{
+ ssize_t rv = sysinfo(cmd, buf, len);
+ char *p = buf;
+
+ if (rv < 0 || rv > len)
+ (void) snprintf(buf, len, "%s", "Unknown");
+
+ while ((p = strchr(p, '.')) != NULL)
+ *p++ = '_';
+
+ return (buf);
+}
+#endif
+
+static dtrace_hdl_t *
+dt_vopen(int version, int flags, int *errp,
+ const dtrace_vector_t *vector, void *arg)
+{
+ dtrace_hdl_t *dtp = NULL;
+ int dtfd = -1, ftfd = -1, fterr = 0;
+ dtrace_prog_t *pgp;
+ dt_module_t *dmp;
+ dt_provmod_t *provmod = NULL;
+ int i, err;
+ struct rlimit rl;
+
+ const dt_intrinsic_t *dinp;
+ const dt_typedef_t *dtyp;
+ const dt_ident_t *idp;
+
+ dtrace_typeinfo_t dtt;
+ ctf_funcinfo_t ctc;
+ ctf_arinfo_t ctr;
+
+ dt_fdlist_t df = { NULL, 0, 0 };
+
+ char isadef[32], utsdef[32];
+ char s1[64], s2[64];
+
+ if (version <= 0)
+ return (set_open_errno(dtp, errp, EINVAL));
+
+ if (version > DTRACE_VERSION)
+ return (set_open_errno(dtp, errp, EDT_VERSION));
+
+ if (version < DTRACE_VERSION) {
+ /*
+ * Currently, increasing the library version number is used to
+ * denote a binary incompatible change. That is, a consumer
+ * of the library cannot run on a version of the library with
+ * a higher DTRACE_VERSION number than the consumer compiled
+ * against. Once the library API has been committed to,
+ * backwards binary compatibility will be required; at that
+ * time, this check should change to return EDT_OVERSION only
+ * if the specified version number is less than the version
+ * number at the time of interface commitment.
+ */
+ return (set_open_errno(dtp, errp, EDT_OVERSION));
+ }
+
+ if (flags & ~DTRACE_O_MASK)
+ return (set_open_errno(dtp, errp, EINVAL));
+
+ if ((flags & DTRACE_O_LP64) && (flags & DTRACE_O_ILP32))
+ return (set_open_errno(dtp, errp, EINVAL));
+
+ if (vector == NULL && arg != NULL)
+ return (set_open_errno(dtp, errp, EINVAL));
+
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ return (set_open_errno(dtp, errp, EDT_ELFVERSION));
+
+ if (vector != NULL || (flags & DTRACE_O_NODEV))
+ goto alloc; /* do not attempt to open dtrace device */
+
+ /*
+ * Before we get going, crank our limit on file descriptors up to the
+ * hard limit. This is to allow for the fact that libproc keeps file
+ * descriptors to objects open for the lifetime of the proc handle;
+ * without raising our hard limit, we would have an acceptably small
+ * bound on the number of processes that we could concurrently
+ * instrument with the pid provider.
+ */
+ if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
+ rl.rlim_cur = rl.rlim_max;
+ (void) setrlimit(RLIMIT_NOFILE, &rl);
+ }
+
+ /*
+ * Get the device path of each of the providers. We hold them open
+ * in the df.df_fds list until we open the DTrace driver itself,
+ * allowing us to see all of the probes provided on this system. Once
+ * we have the DTrace driver open, we can safely close all the providers
+ * now that they have registered with the framework.
+ */
+ dt_provmod_open(&provmod, &df);
+
+ dtfd = open("/dev/dtrace/dtrace", O_RDWR | O_CLOEXEC);
+ err = errno; /* save errno from opening dtfd */
+#if defined(__FreeBSD__)
+ /*
+ * Automatically load the 'dtraceall' module if we couldn't open the
+ * char device.
+ */
+ if (err == ENOENT && modfind("dtraceall") < 0) {
+ kldload("dtraceall"); /* ignore the error */
+ dtfd = open("/dev/dtrace/dtrace", O_RDWR | O_CLOEXEC);
+ err = errno;
+ }
+#endif
+#ifdef illumos
+ ftfd = open("/dev/dtrace/provider/fasttrap", O_RDWR);
+#else
+ ftfd = open("/dev/dtrace/fasttrap", O_RDWR | O_CLOEXEC);
+#endif
+ fterr = ftfd == -1 ? errno : 0; /* save errno from open ftfd */
+
+ while (df.df_ents-- != 0)
+ (void) close(df.df_fds[df.df_ents]);
+
+ free(df.df_fds);
+
+ /*
+ * If we failed to open the dtrace device, fail dtrace_open().
+ * We convert some kernel errnos to custom libdtrace errnos to
+ * improve the resulting message from the usual strerror().
+ */
+ if (dtfd == -1) {
+ dt_provmod_destroy(&provmod);
+ switch (err) {
+ case ENOENT:
+ err = EDT_NOENT;
+ break;
+ case EBUSY:
+ err = EDT_BUSY;
+ break;
+ case EACCES:
+ err = EDT_ACCESS;
+ break;
+ }
+ return (set_open_errno(dtp, errp, err));
+ }
+
+alloc:
+ if ((dtp = malloc(sizeof (dtrace_hdl_t))) == NULL) {
+ dt_provmod_destroy(&provmod);
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+ }
+
+ bzero(dtp, sizeof (dtrace_hdl_t));
+ dtp->dt_oflags = flags;
+#ifdef illumos
+ dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
+#else
+ dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
+#endif
+ dtp->dt_linkmode = DT_LINK_KERNEL;
+ dtp->dt_linktype = DT_LTYP_ELF;
+ dtp->dt_xlatemode = DT_XL_STATIC;
+ dtp->dt_stdcmode = DT_STDC_XA;
+ dtp->dt_encoding = DT_ENCODING_UNSET;
+ dtp->dt_version = version;
+ dtp->dt_fd = dtfd;
+ dtp->dt_ftfd = ftfd;
+ dtp->dt_fterr = fterr;
+ dtp->dt_cdefs_fd = -1;
+ dtp->dt_ddefs_fd = -1;
+#ifdef illumos
+ dtp->dt_stdout_fd = -1;
+#else
+ dtp->dt_freopen_fp = NULL;
+#endif
+ dtp->dt_modbuckets = _dtrace_strbuckets;
+ dtp->dt_mods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *));
+#ifdef __FreeBSD__
+ dtp->dt_kmods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *));
+#endif
+ dtp->dt_provbuckets = _dtrace_strbuckets;
+ dtp->dt_provs = calloc(dtp->dt_provbuckets, sizeof (dt_provider_t *));
+ dt_proc_init(dtp);
+ dtp->dt_vmax = DT_VERS_LATEST;
+ dtp->dt_cpp_path = strdup(_dtrace_defcpp);
+ dtp->dt_cpp_argv = malloc(sizeof (char *));
+ dtp->dt_cpp_argc = 1;
+ dtp->dt_cpp_args = 1;
+ dtp->dt_ld_path = strdup(_dtrace_defld);
+#ifdef __FreeBSD__
+ dtp->dt_objcopy_path = strdup(_dtrace_defobjcopy);
+#endif
+ dtp->dt_provmod = provmod;
+ dtp->dt_vector = vector;
+ dtp->dt_varg = arg;
+ dt_dof_init(dtp);
+ (void) uname(&dtp->dt_uts);
+
+ if (dtp->dt_mods == NULL || dtp->dt_provs == NULL ||
+ dtp->dt_procs == NULL || dtp->dt_proc_env == NULL ||
+ dtp->dt_ld_path == NULL || dtp->dt_cpp_path == NULL ||
+#ifdef __FreeBSD__
+ dtp->dt_kmods == NULL ||
+ dtp->dt_objcopy_path == NULL ||
+#endif
+ dtp->dt_cpp_argv == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+
+ for (i = 0; i < DTRACEOPT_MAX; i++)
+ dtp->dt_options[i] = DTRACEOPT_UNSET;
+
+ dtp->dt_cpp_argv[0] = (char *)strbasename(dtp->dt_cpp_path);
+
+#ifdef illumos
+ (void) snprintf(isadef, sizeof (isadef), "-D__SUNW_D_%u",
+ (uint_t)(sizeof (void *) * NBBY));
+
+ (void) snprintf(utsdef, sizeof (utsdef), "-D__%s_%s",
+ dt_get_sysinfo(SI_SYSNAME, s1, sizeof (s1)),
+ dt_get_sysinfo(SI_RELEASE, s2, sizeof (s2)));
+
+ if (dt_cpp_add_arg(dtp, "-D__sun") == NULL ||
+ dt_cpp_add_arg(dtp, "-D__unix") == NULL ||
+ dt_cpp_add_arg(dtp, "-D__SVR4") == NULL ||
+ dt_cpp_add_arg(dtp, "-D__SUNW_D=1") == NULL ||
+ dt_cpp_add_arg(dtp, isadef) == NULL ||
+ dt_cpp_add_arg(dtp, utsdef) == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+#endif
+
+ if (flags & DTRACE_O_NODEV)
+ bcopy(&_dtrace_conf, &dtp->dt_conf, sizeof (_dtrace_conf));
+ else if (dt_ioctl(dtp, DTRACEIOC_CONF, &dtp->dt_conf) != 0)
+ return (set_open_errno(dtp, errp, errno));
+
+ if (flags & DTRACE_O_LP64)
+ dtp->dt_conf.dtc_ctfmodel = CTF_MODEL_LP64;
+ else if (flags & DTRACE_O_ILP32)
+ dtp->dt_conf.dtc_ctfmodel = CTF_MODEL_ILP32;
+
+#ifdef __sparc
+ /*
+ * On SPARC systems, __sparc is always defined for <sys/isa_defs.h>
+ * and __sparcv9 is defined if we are doing a 64-bit compile.
+ */
+ if (dt_cpp_add_arg(dtp, "-D__sparc") == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+
+ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64 &&
+ dt_cpp_add_arg(dtp, "-D__sparcv9") == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+#endif
+
+#ifdef illumos
+#ifdef __x86
+ /*
+ * On x86 systems, __i386 is defined for <sys/isa_defs.h> for 32-bit
+ * compiles and __amd64 is defined for 64-bit compiles. Unlike SPARC,
+ * they are defined exclusive of one another (see PSARC 2004/619).
+ */
+ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) {
+ if (dt_cpp_add_arg(dtp, "-D__amd64") == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+ } else {
+ if (dt_cpp_add_arg(dtp, "-D__i386") == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+ }
+#endif
+#else
+#if defined(__amd64__) || defined(__i386__)
+ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) {
+ if (dt_cpp_add_arg(dtp, "-m64") == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+ } else {
+ if (dt_cpp_add_arg(dtp, "-m32") == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+ }
+#endif
+#endif
+
+ if (dtp->dt_conf.dtc_difversion < DIF_VERSION)
+ return (set_open_errno(dtp, errp, EDT_DIFVERS));
+
+ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_ILP32)
+ bcopy(_dtrace_ints_32, dtp->dt_ints, sizeof (_dtrace_ints_32));
+ else
+ bcopy(_dtrace_ints_64, dtp->dt_ints, sizeof (_dtrace_ints_64));
+
+ /*
+ * On FreeBSD the kernel module name can't be hard-coded. The
+ * 'kern.bootfile' sysctl value tells us exactly which file is being
+ * used as the kernel.
+ */
+#ifndef illumos
+ {
+ char bootfile[MAXPATHLEN];
+ char *p;
+ int i;
+ size_t len = sizeof(bootfile);
+
+ /* This call shouldn't fail, but use a default just in case. */
+ if (sysctlbyname("kern.bootfile", bootfile, &len, NULL, 0) != 0)
+ strlcpy(bootfile, "kernel", sizeof(bootfile));
+
+ if ((p = strrchr(bootfile, '/')) != NULL)
+ p++;
+ else
+ p = bootfile;
+
+ /*
+ * Format the global variables based on the kernel module name.
+ */
+ snprintf(curthread_str, sizeof(curthread_str), "%s`struct thread *",p);
+ snprintf(intmtx_str, sizeof(intmtx_str), "int(%s`struct mtx *)",p);
+ snprintf(threadmtx_str, sizeof(threadmtx_str), "struct thread *(%s`struct mtx *)",p);
+ snprintf(rwlock_str, sizeof(rwlock_str), "int(%s`struct rwlock *)",p);
+ snprintf(sxlock_str, sizeof(sxlock_str), "int(%s`struct sx *)",p);
+ }
+#endif
+
+ dtp->dt_macros = dt_idhash_create("macro", NULL, 0, UINT_MAX);
+ dtp->dt_aggs = dt_idhash_create("aggregation", NULL,
+ DTRACE_AGGVARIDNONE + 1, UINT_MAX);
+
+ dtp->dt_globals = dt_idhash_create("global", _dtrace_globals,
+ DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX);
+
+ dtp->dt_tls = dt_idhash_create("thread local", NULL,
+ DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX);
+
+ if (dtp->dt_macros == NULL || dtp->dt_aggs == NULL ||
+ dtp->dt_globals == NULL || dtp->dt_tls == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+
+ /*
+ * Populate the dt_macros identifier hash table by hand: we can't use
+ * the dt_idhash_populate() mechanism because we're not yet compiling
+ * and dtrace_update() needs to immediately reference these idents.
+ */
+ for (idp = _dtrace_macros; idp->di_name != NULL; idp++) {
+ if (dt_idhash_insert(dtp->dt_macros, idp->di_name,
+ idp->di_kind, idp->di_flags, idp->di_id, idp->di_attr,
+ idp->di_vers, idp->di_ops ? idp->di_ops : &dt_idops_thaw,
+ idp->di_iarg, 0) == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+ }
+
+ /*
+ * Update the module list using /system/object and load the values for
+ * the macro variable definitions according to the current process.
+ */
+ dtrace_update(dtp);
+
+ /*
+ * Select the intrinsics and typedefs we want based on the data model.
+ * The intrinsics are under "C". The typedefs are added under "D".
+ */
+ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_ILP32) {
+ dinp = _dtrace_intrinsics_32;
+ dtyp = _dtrace_typedefs_32;
+ } else {
+ dinp = _dtrace_intrinsics_64;
+ dtyp = _dtrace_typedefs_64;
+ }
+
+ /*
+ * Create a dynamic CTF container under the "C" scope for intrinsic
+ * types and types defined in ANSI-C header files that are included.
+ */
+ if ((dmp = dtp->dt_cdefs = dt_module_create(dtp, "C")) == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+
+ if ((dmp->dm_ctfp = ctf_create(&dtp->dt_ctferr)) == NULL)
+ return (set_open_errno(dtp, errp, EDT_CTF));
+
+ dt_dprintf("created CTF container for %s (%p)\n",
+ dmp->dm_name, (void *)dmp->dm_ctfp);
+
+ (void) ctf_setmodel(dmp->dm_ctfp, dtp->dt_conf.dtc_ctfmodel);
+ ctf_setspecific(dmp->dm_ctfp, dmp);
+
+ dmp->dm_flags = DT_DM_LOADED; /* fake up loaded bit */
+ dmp->dm_modid = -1; /* no module ID */
+
+ /*
+ * Fill the dynamic "C" CTF container with all of the intrinsic
+ * integer and floating-point types appropriate for this data model.
+ */
+ for (; dinp->din_name != NULL; dinp++) {
+ if (dinp->din_kind == CTF_K_INTEGER) {
+ err = ctf_add_integer(dmp->dm_ctfp, CTF_ADD_ROOT,
+ dinp->din_name, &dinp->din_data);
+ } else {
+ err = ctf_add_float(dmp->dm_ctfp, CTF_ADD_ROOT,
+ dinp->din_name, &dinp->din_data);
+ }
+
+ if (err == CTF_ERR) {
+ dt_dprintf("failed to add %s to C container: %s\n",
+ dinp->din_name, ctf_errmsg(
+ ctf_errno(dmp->dm_ctfp)));
+ return (set_open_errno(dtp, errp, EDT_CTF));
+ }
+ }
+
+ if (ctf_update(dmp->dm_ctfp) != 0) {
+ dt_dprintf("failed to update C container: %s\n",
+ ctf_errmsg(ctf_errno(dmp->dm_ctfp)));
+ return (set_open_errno(dtp, errp, EDT_CTF));
+ }
+
+ /*
+ * Add intrinsic pointer types that are needed to initialize printf
+ * format dictionary types (see table in dt_printf.c).
+ */
+ (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT,
+ ctf_lookup_by_name(dmp->dm_ctfp, "void"));
+
+ (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT,
+ ctf_lookup_by_name(dmp->dm_ctfp, "char"));
+
+ (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT,
+ ctf_lookup_by_name(dmp->dm_ctfp, "int"));
+
+ if (ctf_update(dmp->dm_ctfp) != 0) {
+ dt_dprintf("failed to update C container: %s\n",
+ ctf_errmsg(ctf_errno(dmp->dm_ctfp)));
+ return (set_open_errno(dtp, errp, EDT_CTF));
+ }
+
+ /*
+ * Create a dynamic CTF container under the "D" scope for types that
+ * are defined by the D program itself or on-the-fly by the D compiler.
+ * The "D" CTF container is a child of the "C" CTF container.
+ */
+ if ((dmp = dtp->dt_ddefs = dt_module_create(dtp, "D")) == NULL)
+ return (set_open_errno(dtp, errp, EDT_NOMEM));
+
+ if ((dmp->dm_ctfp = ctf_create(&dtp->dt_ctferr)) == NULL)
+ return (set_open_errno(dtp, errp, EDT_CTF));
+
+ dt_dprintf("created CTF container for %s (%p)\n",
+ dmp->dm_name, (void *)dmp->dm_ctfp);
+
+ (void) ctf_setmodel(dmp->dm_ctfp, dtp->dt_conf.dtc_ctfmodel);
+ ctf_setspecific(dmp->dm_ctfp, dmp);
+
+ dmp->dm_flags = DT_DM_LOADED; /* fake up loaded bit */
+ dmp->dm_modid = -1; /* no module ID */
+
+ if (ctf_import(dmp->dm_ctfp, dtp->dt_cdefs->dm_ctfp) == CTF_ERR) {
+ dt_dprintf("failed to import D parent container: %s\n",
+ ctf_errmsg(ctf_errno(dmp->dm_ctfp)));
+ return (set_open_errno(dtp, errp, EDT_CTF));
+ }
+
+ /*
+ * Fill the dynamic "D" CTF container with all of the built-in typedefs
+ * that we need to use for our D variable and function definitions.
+ * This ensures that basic inttypes.h names are always available to us.
+ */
+ for (; dtyp->dty_src != NULL; dtyp++) {
+ if (ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
+ dtyp->dty_dst, ctf_lookup_by_name(dmp->dm_ctfp,
+ dtyp->dty_src)) == CTF_ERR) {
+ dt_dprintf("failed to add typedef %s %s to D "
+ "container: %s", dtyp->dty_src, dtyp->dty_dst,
+ ctf_errmsg(ctf_errno(dmp->dm_ctfp)));
+ return (set_open_errno(dtp, errp, EDT_CTF));
+ }
+ }
+
+ /*
+ * Insert a CTF ID corresponding to a pointer to a type of kind
+ * CTF_K_FUNCTION we can use in the compiler for function pointers.
+ * CTF treats all function pointers as "int (*)()" so we only need one.
+ */
+ ctc.ctc_return = ctf_lookup_by_name(dmp->dm_ctfp, "int");
+ ctc.ctc_argc = 0;
+ ctc.ctc_flags = 0;
+
+ dtp->dt_type_func = ctf_add_function(dmp->dm_ctfp,
+ CTF_ADD_ROOT, &ctc, NULL);
+
+ dtp->dt_type_fptr = ctf_add_pointer(dmp->dm_ctfp,
+ CTF_ADD_ROOT, dtp->dt_type_func);
+
+ /*
+ * We also insert CTF definitions for the special D intrinsic types
+ * string and <DYN> into the D container. The string type is added
+ * as a typedef of char[n]. The <DYN> type is an alias for void.
+ * We compare types to these special CTF ids throughout the compiler.
+ */
+ ctr.ctr_contents = ctf_lookup_by_name(dmp->dm_ctfp, "char");
+ ctr.ctr_index = ctf_lookup_by_name(dmp->dm_ctfp, "long");
+ ctr.ctr_nelems = _dtrace_strsize;
+
+ dtp->dt_type_str = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
+ "string", ctf_add_array(dmp->dm_ctfp, CTF_ADD_ROOT, &ctr));
+
+ dtp->dt_type_dyn = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
+ "<DYN>", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
+
+ dtp->dt_type_stack = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
+ "stack", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
+
+ dtp->dt_type_symaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
+ "_symaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
+
+ dtp->dt_type_usymaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
+ "_usymaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
+
+ if (dtp->dt_type_func == CTF_ERR || dtp->dt_type_fptr == CTF_ERR ||
+ dtp->dt_type_str == CTF_ERR || dtp->dt_type_dyn == CTF_ERR ||
+ dtp->dt_type_stack == CTF_ERR || dtp->dt_type_symaddr == CTF_ERR ||
+ dtp->dt_type_usymaddr == CTF_ERR) {
+ dt_dprintf("failed to add intrinsic to D container: %s\n",
+ ctf_errmsg(ctf_errno(dmp->dm_ctfp)));
+ return (set_open_errno(dtp, errp, EDT_CTF));
+ }
+
+ if (ctf_update(dmp->dm_ctfp) != 0) {
+ dt_dprintf("failed update D container: %s\n",
+ ctf_errmsg(ctf_errno(dmp->dm_ctfp)));
+ return (set_open_errno(dtp, errp, EDT_CTF));
+ }
+
+ /*
+ * Initialize the integer description table used to convert integer
+ * constants to the appropriate types. Refer to the comments above
+ * dt_node_int() for a complete description of how this table is used.
+ */
+ for (i = 0; i < sizeof (dtp->dt_ints) / sizeof (dtp->dt_ints[0]); i++) {
+ if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY,
+ dtp->dt_ints[i].did_name, &dtt) != 0) {
+ dt_dprintf("failed to lookup integer type %s: %s\n",
+ dtp->dt_ints[i].did_name,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ return (set_open_errno(dtp, errp, dtp->dt_errno));
+ }
+ dtp->dt_ints[i].did_ctfp = dtt.dtt_ctfp;
+ dtp->dt_ints[i].did_type = dtt.dtt_type;
+ }
+
+ /*
+ * Now that we've created the "C" and "D" containers, move them to the
+ * start of the module list so that these types and symbols are found
+ * first (for stability) when iterating through the module list.
+ */
+ dt_list_delete(&dtp->dt_modlist, dtp->dt_ddefs);
+ dt_list_prepend(&dtp->dt_modlist, dtp->dt_ddefs);
+
+ dt_list_delete(&dtp->dt_modlist, dtp->dt_cdefs);
+ dt_list_prepend(&dtp->dt_modlist, dtp->dt_cdefs);
+
+ if (dt_pfdict_create(dtp) == -1)
+ return (set_open_errno(dtp, errp, dtp->dt_errno));
+
+ /*
+ * If we are opening libdtrace DTRACE_O_NODEV enable C_ZDEFS by default
+ * because without /dev/dtrace open, we will not be able to load the
+ * names and attributes of any providers or probes from the kernel.
+ */
+ if (flags & DTRACE_O_NODEV)
+ dtp->dt_cflags |= DTRACE_C_ZDEFS;
+
+ /*
+ * Load hard-wired inlines into the definition cache by calling the
+ * compiler on the raw definition string defined above.
+ */
+ if ((pgp = dtrace_program_strcompile(dtp, _dtrace_hardwire,
+ DTRACE_PROBESPEC_NONE, DTRACE_C_EMPTY, 0, NULL)) == NULL) {
+ dt_dprintf("failed to load hard-wired definitions: %s\n",
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ return (set_open_errno(dtp, errp, EDT_HARDWIRE));
+ }
+
+ dt_program_destroy(dtp, pgp);
+
+ /*
+ * Set up the default DTrace library path. Once set, the next call to
+ * dt_compile() will compile all the libraries. We intentionally defer
+ * library processing to improve overhead for clients that don't ever
+ * compile, and to provide better error reporting (because the full
+ * reporting of compiler errors requires dtrace_open() to succeed).
+ */
+#ifdef __FreeBSD__
+#ifdef __LP64__
+ if ((dtp->dt_oflags & DTRACE_O_ILP32) != 0) {
+ if (dtrace_setopt(dtp, "libdir", _dtrace_libdir32) != 0)
+ return (set_open_errno(dtp, errp, dtp->dt_errno));
+ }
+#endif
+ if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0)
+ return (set_open_errno(dtp, errp, dtp->dt_errno));
+#else
+ if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0)
+ return (set_open_errno(dtp, errp, dtp->dt_errno));
+#endif
+
+ return (dtp);
+}
+
+dtrace_hdl_t *
+dtrace_open(int version, int flags, int *errp)
+{
+ return (dt_vopen(version, flags, errp, NULL, NULL));
+}
+
+dtrace_hdl_t *
+dtrace_vopen(int version, int flags, int *errp,
+ const dtrace_vector_t *vector, void *arg)
+{
+ return (dt_vopen(version, flags, errp, vector, arg));
+}
+
+void
+dtrace_close(dtrace_hdl_t *dtp)
+{
+ dt_ident_t *idp, *ndp;
+ dt_module_t *dmp;
+ dt_provider_t *pvp;
+ dtrace_prog_t *pgp;
+ dt_xlator_t *dxp;
+ dt_dirpath_t *dirp;
+#ifdef __FreeBSD__
+ dt_kmodule_t *dkm;
+ uint_t h;
+#endif
+ int i;
+
+ if (dtp->dt_procs != NULL)
+ dt_proc_fini(dtp);
+
+ while ((pgp = dt_list_next(&dtp->dt_programs)) != NULL)
+ dt_program_destroy(dtp, pgp);
+
+ while ((dxp = dt_list_next(&dtp->dt_xlators)) != NULL)
+ dt_xlator_destroy(dtp, dxp);
+
+ dt_free(dtp, dtp->dt_xlatormap);
+
+ for (idp = dtp->dt_externs; idp != NULL; idp = ndp) {
+ ndp = idp->di_next;
+ dt_ident_destroy(idp);
+ }
+
+ if (dtp->dt_macros != NULL)
+ dt_idhash_destroy(dtp->dt_macros);
+ if (dtp->dt_aggs != NULL)
+ dt_idhash_destroy(dtp->dt_aggs);
+ if (dtp->dt_globals != NULL)
+ dt_idhash_destroy(dtp->dt_globals);
+ if (dtp->dt_tls != NULL)
+ dt_idhash_destroy(dtp->dt_tls);
+
+#ifdef __FreeBSD__
+ for (h = 0; h < dtp->dt_modbuckets; h++)
+ while ((dkm = dtp->dt_kmods[h]) != NULL) {
+ dtp->dt_kmods[h] = dkm->dkm_next;
+ free(dkm->dkm_name);
+ free(dkm);
+ }
+#endif
+
+ while ((dmp = dt_list_next(&dtp->dt_modlist)) != NULL)
+ dt_module_destroy(dtp, dmp);
+
+ while ((pvp = dt_list_next(&dtp->dt_provlist)) != NULL)
+ dt_provider_destroy(dtp, pvp);
+
+ if (dtp->dt_fd != -1)
+ (void) close(dtp->dt_fd);
+ if (dtp->dt_ftfd != -1)
+ (void) close(dtp->dt_ftfd);
+ if (dtp->dt_cdefs_fd != -1)
+ (void) close(dtp->dt_cdefs_fd);
+ if (dtp->dt_ddefs_fd != -1)
+ (void) close(dtp->dt_ddefs_fd);
+#ifdef illumos
+ if (dtp->dt_stdout_fd != -1)
+ (void) close(dtp->dt_stdout_fd);
+#else
+ if (dtp->dt_freopen_fp != NULL)
+ (void) fclose(dtp->dt_freopen_fp);
+#endif
+
+ dt_epid_destroy(dtp);
+ dt_aggid_destroy(dtp);
+ dt_format_destroy(dtp);
+ dt_strdata_destroy(dtp);
+ dt_buffered_destroy(dtp);
+ dt_aggregate_destroy(dtp);
+ dt_pfdict_destroy(dtp);
+ dt_provmod_destroy(&dtp->dt_provmod);
+ dt_dof_fini(dtp);
+
+ for (i = 1; i < dtp->dt_cpp_argc; i++)
+ free(dtp->dt_cpp_argv[i]);
+
+ while ((dirp = dt_list_next(&dtp->dt_lib_path)) != NULL) {
+ dt_list_delete(&dtp->dt_lib_path, dirp);
+ free(dirp->dir_path);
+ free(dirp);
+ }
+
+ free(dtp->dt_cpp_argv);
+ free(dtp->dt_cpp_path);
+ free(dtp->dt_ld_path);
+#ifdef __FreeBSD__
+ free(dtp->dt_objcopy_path);
+#endif
+
+ free(dtp->dt_mods);
+#ifdef __FreeBSD__
+ free(dtp->dt_kmods);
+#endif
+ free(dtp->dt_provs);
+ free(dtp);
+}
+
+int
+dtrace_provider_modules(dtrace_hdl_t *dtp, const char **mods, int nmods)
+{
+ dt_provmod_t *prov;
+ int i = 0;
+
+ for (prov = dtp->dt_provmod; prov != NULL; prov = prov->dp_next, i++) {
+ if (i < nmods)
+ mods[i] = prov->dp_name;
+ }
+
+ return (i);
+}
+
+int
+dtrace_ctlfd(dtrace_hdl_t *dtp)
+{
+ return (dtp->dt_fd);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
new file mode 100644
index 000000000000..c99e6007f9da
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
@@ -0,0 +1,1113 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <strings.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+
+#include <dt_impl.h>
+#include <dt_string.h>
+
+static int
+dt_opt_agg(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dt_aggregate_t *agp = &dtp->dt_aggregate;
+
+ if (arg != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ agp->dtat_flags |= option;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_amin(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ char str[DTRACE_ATTR2STR_MAX];
+ dtrace_attribute_t attr;
+
+ if (arg == NULL || dtrace_str2attr(arg, &attr) == -1)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ dt_dprintf("set compiler attribute minimum to %s\n",
+ dtrace_attr2str(attr, str, sizeof (str)));
+
+ if (dtp->dt_pcb != NULL) {
+ dtp->dt_pcb->pcb_cflags |= DTRACE_C_EATTR;
+ dtp->dt_pcb->pcb_amin = attr;
+ } else {
+ dtp->dt_cflags |= DTRACE_C_EATTR;
+ dtp->dt_amin = attr;
+ }
+
+ return (0);
+}
+
+static void
+dt_coredump(void)
+{
+ const char msg[] = "libdtrace DEBUG: [ forcing coredump ]\n";
+
+ struct sigaction act;
+ struct rlimit lim;
+
+ (void) write(STDERR_FILENO, msg, sizeof (msg) - 1);
+
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+
+ (void) sigemptyset(&act.sa_mask);
+ (void) sigaction(SIGABRT, &act, NULL);
+
+ lim.rlim_cur = RLIM_INFINITY;
+ lim.rlim_max = RLIM_INFINITY;
+
+ (void) setrlimit(RLIMIT_CORE, &lim);
+ abort();
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_core(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ static int enabled = 0;
+
+ if (arg != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (enabled++ || atexit(dt_coredump) == 0)
+ return (0);
+
+ return (dt_set_errno(dtp, errno));
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_cpp_hdrs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (dtp->dt_pcb != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTCTX));
+
+ if (dt_cpp_add_arg(dtp, "-H") == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_cpp_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ char *cpp;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (dtp->dt_pcb != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTCTX));
+
+ if ((cpp = strdup(arg)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ dtp->dt_cpp_argv[0] = (char *)strbasename(cpp);
+ free(dtp->dt_cpp_path);
+ dtp->dt_cpp_path = cpp;
+
+ return (0);
+}
+
+static int
+dt_opt_cpp_opts(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ char *buf;
+ size_t len;
+ const char *opt = (const char *)option;
+
+ if (opt == NULL || arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (dtp->dt_pcb != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTCTX));
+
+ len = strlen(opt) + strlen(arg) + 1;
+ buf = alloca(len);
+
+ (void) strcpy(buf, opt);
+ (void) strcat(buf, arg);
+
+ if (dt_cpp_add_arg(dtp, buf) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_ctypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ int fd;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ (void) close(dtp->dt_cdefs_fd);
+ dtp->dt_cdefs_fd = fd;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_droptags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dtp->dt_droptags = 1;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_dtypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ int fd;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ (void) close(dtp->dt_ddefs_fd);
+ dtp->dt_ddefs_fd = fd;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_debug(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ _dtrace_debug = 1;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_iregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ int n;
+
+ if (arg == NULL || (n = atoi(arg)) <= 0)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ dtp->dt_conf.dtc_difintregs = n;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_lazyload(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dtp->dt_lazyload = 1;
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_ld_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ char *ld;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (dtp->dt_pcb != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTCTX));
+
+ if ((ld = strdup(arg)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ free(dtp->dt_ld_path);
+ dtp->dt_ld_path = ld;
+
+ return (0);
+}
+
+#ifdef __FreeBSD__
+static int
+dt_opt_objcopy_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ char *objcopy;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (dtp->dt_pcb != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTCTX));
+
+ if ((objcopy = strdup(arg)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ free(dtp->dt_objcopy_path);
+ dtp->dt_objcopy_path = objcopy;
+
+ return (0);
+}
+#endif
+
+/*ARGSUSED*/
+static int
+dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dt_dirpath_t *dp;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if ((dp = malloc(sizeof (dt_dirpath_t))) == NULL ||
+ (dp->dir_path = strdup(arg)) == NULL) {
+ free(dp);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ dt_list_append(&dtp->dt_lib_path, dp);
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_linkmode(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (strcmp(arg, "kernel") == 0)
+ dtp->dt_linkmode = DT_LINK_KERNEL;
+ else if (strcmp(arg, "primary") == 0)
+ dtp->dt_linkmode = DT_LINK_PRIMARY;
+ else if (strcmp(arg, "dynamic") == 0)
+ dtp->dt_linkmode = DT_LINK_DYNAMIC;
+ else if (strcmp(arg, "static") == 0)
+ dtp->dt_linkmode = DT_LINK_STATIC;
+ else
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (strcasecmp(arg, "elf") == 0)
+ dtp->dt_linktype = DT_LTYP_ELF;
+ else if (strcasecmp(arg, "dof") == 0)
+ dtp->dt_linktype = DT_LTYP_DOF;
+ else
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (strcmp(arg, "ascii") == 0)
+ dtp->dt_encoding = DT_ENCODING_ASCII;
+ else if (strcmp(arg, "utf8") == 0)
+ dtp->dt_encoding = DT_ENCODING_UTF8;
+ else
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (strcmp(arg, "exec") == 0)
+ dtp->dt_prcmode = DT_PROC_STOP_CREATE;
+ else if (strcmp(arg, "preinit") == 0)
+ dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
+ else if (strcmp(arg, "postinit") == 0)
+ dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
+ else if (strcmp(arg, "main") == 0)
+ dtp->dt_prcmode = DT_PROC_STOP_MAIN;
+ else
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ int n;
+
+ if (arg == NULL || (n = atoi(arg)) < 0)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ dtp->dt_procs->dph_lrulim = n;
+ return (0);
+}
+
+static int
+dt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ char **p;
+ char *var;
+ int nvars;
+
+ /*
+ * We can't effectively set environment variables from #pragma lines
+ * since the processes have already been spawned.
+ */
+ if (dtp->dt_pcb != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTCTX));
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (!option && strchr(arg, '=') != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ for (nvars = 0, p = dtp->dt_proc_env; *p != NULL; nvars++, p++)
+ continue;
+
+ for (p = dtp->dt_proc_env; *p != NULL; p++) {
+ var = strchr(*p, '=');
+ if (var == NULL)
+ var = *p + strlen(*p);
+ if (strncmp(*p, arg, var - *p) == 0) {
+ dt_free(dtp, *p);
+ *p = dtp->dt_proc_env[nvars - 1];
+ dtp->dt_proc_env[nvars - 1] = NULL;
+ nvars--;
+ }
+ }
+
+ if (option) {
+ if ((var = strdup(arg)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ nvars++;
+ if ((p = dt_alloc(dtp, sizeof(char *) * (nvars + 1))) == NULL) {
+ dt_free(dtp, var);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ bcopy(dtp->dt_proc_env, p, sizeof(char *) * nvars);
+ dt_free(dtp, dtp->dt_proc_env);
+ dtp->dt_proc_env = p;
+
+ dtp->dt_proc_env[nvars - 1] = var;
+ dtp->dt_proc_env[nvars] = NULL;
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (dtp->dt_pcb != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTCTX));
+
+ if (strcmp(arg, "a") == 0)
+ dtp->dt_stdcmode = DT_STDC_XA;
+ else if (strcmp(arg, "c") == 0)
+ dtp->dt_stdcmode = DT_STDC_XC;
+ else if (strcmp(arg, "s") == 0)
+ dtp->dt_stdcmode = DT_STDC_XS;
+ else if (strcmp(arg, "t") == 0)
+ dtp->dt_stdcmode = DT_STDC_XT;
+ else
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
+ char *path;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if ((path = strdup(arg)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ free(dp->dir_path);
+ dp->dir_path = path;
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ int m;
+
+ if (arg == NULL || (m = atoi(arg)) <= 0)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ dtp->dt_treedump = m;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ int n;
+
+ if (arg == NULL || (n = atoi(arg)) <= 0)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ dtp->dt_conf.dtc_diftupregs = n;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (strcmp(arg, "dynamic") == 0)
+ dtp->dt_xlatemode = DT_XL_DYNAMIC;
+ else if (strcmp(arg, "static") == 0)
+ dtp->dt_xlatemode = DT_XL_STATIC;
+ else
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_cflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (dtp->dt_pcb != NULL)
+ dtp->dt_pcb->pcb_cflags |= option;
+ else
+ dtp->dt_cflags |= option;
+
+ return (0);
+}
+
+static int
+dt_opt_dflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ dtp->dt_dflags |= option;
+ return (0);
+}
+
+static int
+dt_opt_invcflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ if (arg != NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (dtp->dt_pcb != NULL)
+ dtp->dt_pcb->pcb_cflags &= ~option;
+ else
+ dtp->dt_cflags &= ~option;
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_opt_version(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dt_version_t v;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (dt_version_str2num(arg, &v) == -1)
+ return (dt_set_errno(dtp, EDT_VERSINVAL));
+
+ if (!dt_version_defined(v))
+ return (dt_set_errno(dtp, EDT_VERSUNDEF));
+
+ return (dt_reduce(dtp, v));
+}
+
+static int
+dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ char *end;
+ dtrace_optval_t val = 0;
+ int i;
+
+ const struct {
+ char *positive;
+ char *negative;
+ } couples[] = {
+ { "yes", "no" },
+ { "enable", "disable" },
+ { "enabled", "disabled" },
+ { "true", "false" },
+ { "on", "off" },
+ { "set", "unset" },
+ { NULL }
+ };
+
+ if (arg != NULL) {
+ if (arg[0] == '\0') {
+ val = DTRACEOPT_UNSET;
+ goto out;
+ }
+
+ for (i = 0; couples[i].positive != NULL; i++) {
+ if (strcasecmp(couples[i].positive, arg) == 0) {
+ val = 1;
+ goto out;
+ }
+
+ if (strcasecmp(couples[i].negative, arg) == 0) {
+ val = DTRACEOPT_UNSET;
+ goto out;
+ }
+ }
+
+ errno = 0;
+ val = strtoull(arg, &end, 0);
+
+ if (*end != '\0' || errno != 0 || val < 0)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+ }
+
+out:
+ dtp->dt_options[option] = val;
+ return (0);
+}
+
+static int
+dt_optval_parse(const char *arg, dtrace_optval_t *rval)
+{
+ dtrace_optval_t mul = 1;
+ size_t len;
+ char *end;
+
+ len = strlen(arg);
+ errno = 0;
+
+ switch (arg[len - 1]) {
+ case 't':
+ case 'T':
+ mul *= 1024;
+ /*FALLTHRU*/
+ case 'g':
+ case 'G':
+ mul *= 1024;
+ /*FALLTHRU*/
+ case 'm':
+ case 'M':
+ mul *= 1024;
+ /*FALLTHRU*/
+ case 'k':
+ case 'K':
+ mul *= 1024;
+ /*FALLTHRU*/
+ default:
+ break;
+ }
+
+ errno = 0;
+ *rval = strtoull(arg, &end, 0) * mul;
+
+ if ((mul > 1 && end != &arg[len - 1]) || (mul == 1 && *end != '\0') ||
+ *rval < 0 || errno != 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+dt_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dtrace_optval_t val = 0;
+
+ if (arg != NULL && dt_optval_parse(arg, &val) != 0)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ dtp->dt_options[option] = val;
+ return (0);
+}
+
+static int
+dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ char *end;
+ int i;
+ dtrace_optval_t mul = 1, val = 0;
+
+ const struct {
+ char *name;
+ hrtime_t mul;
+ } suffix[] = {
+ { "ns", NANOSEC / NANOSEC },
+ { "nsec", NANOSEC / NANOSEC },
+ { "us", NANOSEC / MICROSEC },
+ { "usec", NANOSEC / MICROSEC },
+ { "ms", NANOSEC / MILLISEC },
+ { "msec", NANOSEC / MILLISEC },
+ { "s", NANOSEC / SEC },
+ { "sec", NANOSEC / SEC },
+ { "m", NANOSEC * (hrtime_t)60 },
+ { "min", NANOSEC * (hrtime_t)60 },
+ { "h", NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
+ { "hour", NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
+ { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) },
+ { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) },
+ { "hz", 0 },
+ { NULL }
+ };
+
+ if (arg != NULL) {
+ errno = 0;
+ val = strtoull(arg, &end, 0);
+
+ for (i = 0; suffix[i].name != NULL; i++) {
+ if (strcasecmp(suffix[i].name, end) == 0) {
+ mul = suffix[i].mul;
+ break;
+ }
+ }
+
+ if (suffix[i].name == NULL && *end != '\0' || val < 0)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (mul == 0) {
+ /*
+ * The rate has been specified in frequency-per-second.
+ */
+ if (val != 0)
+ val = NANOSEC / val;
+ } else {
+ val *= mul;
+ }
+ }
+
+ dtp->dt_options[option] = val;
+ return (0);
+}
+
+/*
+ * When setting the strsize option, set the option in the dt_options array
+ * using dt_opt_size() as usual, and then update the definition of the CTF
+ * type for the D intrinsic "string" to be an array of the corresponding size.
+ * If any errors occur, reset dt_options[option] to its previous value.
+ */
+static int
+dt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dtrace_optval_t val = dtp->dt_options[option];
+ ctf_file_t *fp = DT_STR_CTFP(dtp);
+ ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp));
+ ctf_arinfo_t r;
+
+ if (dt_opt_size(dtp, arg, option) != 0)
+ return (-1); /* dt_errno is set for us */
+
+ if (dtp->dt_options[option] > UINT_MAX) {
+ dtp->dt_options[option] = val;
+ return (dt_set_errno(dtp, EOVERFLOW));
+ }
+
+ if (ctf_array_info(fp, type, &r) == CTF_ERR) {
+ dtp->dt_options[option] = val;
+ dtp->dt_ctferr = ctf_errno(fp);
+ return (dt_set_errno(dtp, EDT_CTF));
+ }
+
+ r.ctr_nelems = (uint_t)dtp->dt_options[option];
+
+ if (ctf_set_array(fp, type, &r) == CTF_ERR ||
+ ctf_update(fp) == CTF_ERR) {
+ dtp->dt_options[option] = val;
+ dtp->dt_ctferr = ctf_errno(fp);
+ return (dt_set_errno(dtp, EDT_CTF));
+ }
+
+ return (0);
+}
+
+static const struct {
+ const char *dtbp_name;
+ int dtbp_policy;
+} _dtrace_bufpolicies[] = {
+ { "ring", DTRACEOPT_BUFPOLICY_RING },
+ { "fill", DTRACEOPT_BUFPOLICY_FILL },
+ { "switch", DTRACEOPT_BUFPOLICY_SWITCH },
+ { NULL, 0 }
+};
+
+/*ARGSUSED*/
+static int
+dt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dtrace_optval_t policy = DTRACEOPT_UNSET;
+ int i;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) {
+ if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) {
+ policy = _dtrace_bufpolicies[i].dtbp_policy;
+ break;
+ }
+ }
+
+ if (policy == DTRACEOPT_UNSET)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy;
+
+ return (0);
+}
+
+static const struct {
+ const char *dtbr_name;
+ int dtbr_policy;
+} _dtrace_bufresize[] = {
+ { "auto", DTRACEOPT_BUFRESIZE_AUTO },
+ { "manual", DTRACEOPT_BUFRESIZE_MANUAL },
+ { NULL, 0 }
+};
+
+/*ARGSUSED*/
+static int
+dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dtrace_optval_t policy = DTRACEOPT_UNSET;
+ int i;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) {
+ if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) {
+ policy = _dtrace_bufresize[i].dtbr_policy;
+ break;
+ }
+ }
+
+ if (policy == DTRACEOPT_UNSET)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy;
+
+ return (0);
+}
+
+int
+dt_options_load(dtrace_hdl_t *dtp)
+{
+ dof_hdr_t hdr, *dof;
+ dof_sec_t *sec;
+ size_t offs;
+ int i;
+
+ /*
+ * To load the option values, we need to ask the kernel to provide its
+ * DOF, which we'll sift through to look for OPTDESC sections.
+ */
+ bzero(&hdr, sizeof (dof_hdr_t));
+ hdr.dofh_loadsz = sizeof (dof_hdr_t);
+
+#ifdef illumos
+ if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
+#else
+ dof = &hdr;
+ if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
+#endif
+ return (dt_set_errno(dtp, errno));
+
+ if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
+ return (dt_set_errno(dtp, EINVAL));
+
+ dof = alloca(hdr.dofh_loadsz);
+ bzero(dof, sizeof (dof_hdr_t));
+ dof->dofh_loadsz = hdr.dofh_loadsz;
+
+ for (i = 0; i < DTRACEOPT_MAX; i++)
+ dtp->dt_options[i] = DTRACEOPT_UNSET;
+
+#ifdef illumos
+ if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
+#else
+ if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
+#endif
+ return (dt_set_errno(dtp, errno));
+
+ for (i = 0; i < dof->dofh_secnum; i++) {
+ sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
+ dof->dofh_secoff + i * dof->dofh_secsize);
+
+ if (sec->dofs_type != DOF_SECT_OPTDESC)
+ continue;
+
+ break;
+ }
+
+ for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
+ dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
+ ((uintptr_t)dof + sec->dofs_offset + offs);
+
+ if (opt->dofo_strtab != DOF_SECIDX_NONE)
+ continue;
+
+ if (opt->dofo_option >= DTRACEOPT_MAX)
+ continue;
+
+ dtp->dt_options[opt->dofo_option] = opt->dofo_value;
+ }
+
+ return (0);
+}
+
+typedef struct dt_option {
+ const char *o_name;
+ int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
+ uintptr_t o_option;
+} dt_option_t;
+
+/*
+ * Compile-time options.
+ */
+static const dt_option_t _dtrace_ctoptions[] = {
+ { "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU },
+ { "amin", dt_opt_amin },
+ { "argref", dt_opt_cflags, DTRACE_C_ARGREF },
+ { "core", dt_opt_core },
+ { "cpp", dt_opt_cflags, DTRACE_C_CPP },
+ { "cpphdrs", dt_opt_cpp_hdrs },
+ { "cpppath", dt_opt_cpp_path },
+ { "ctypes", dt_opt_ctypes },
+ { "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG },
+ { "dtypes", dt_opt_dtypes },
+ { "debug", dt_opt_debug },
+ { "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
+ { "droptags", dt_opt_droptags },
+ { "empty", dt_opt_cflags, DTRACE_C_EMPTY },
+ { "encoding", dt_opt_encoding },
+ { "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
+ { "evaltime", dt_opt_evaltime },
+ { "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
+ { "iregs", dt_opt_iregs },
+ { "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF },
+ { "knodefs", dt_opt_cflags, DTRACE_C_KNODEF },
+ { "late", dt_opt_xlate },
+ { "lazyload", dt_opt_lazyload },
+ { "ldpath", dt_opt_ld_path },
+ { "libdir", dt_opt_libdir },
+ { "linkmode", dt_opt_linkmode },
+ { "linktype", dt_opt_linktype },
+ { "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
+#ifdef __FreeBSD__
+ { "objcopypath", dt_opt_objcopy_path },
+#endif
+ { "pgmax", dt_opt_pgmax },
+ { "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
+ { "setenv", dt_opt_setenv, 1 },
+ { "stdc", dt_opt_stdc },
+ { "strip", dt_opt_dflags, DTRACE_D_STRIP },
+ { "syslibdir", dt_opt_syslibdir },
+ { "tree", dt_opt_tree },
+ { "tregs", dt_opt_tregs },
+ { "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
+ { "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
+ { "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
+ { "unsetenv", dt_opt_setenv, 0 },
+ { "verbose", dt_opt_cflags, DTRACE_C_DIFV },
+ { "version", dt_opt_version },
+ { "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
+ { NULL, NULL, 0 }
+};
+
+/*
+ * Run-time options.
+ */
+static const dt_option_t _dtrace_rtoptions[] = {
+ { "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
+ { "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
+ { "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
+ { "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE },
+ { "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE },
+ { "cpu", dt_opt_runtime, DTRACEOPT_CPU },
+ { "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
+ { "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
+ { "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
+ { "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
+ { "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
+ { "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
+ { "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
+ { "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
+ { "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
+ { "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
+ { "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
+ { "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
+ { NULL, NULL, 0 }
+};
+
+/*
+ * Dynamic run-time options.
+ */
+static const dt_option_t _dtrace_drtoptions[] = {
+ { "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST },
+ { "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK },
+ { "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
+ { "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
+ { "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
+ { "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
+ { "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
+ { "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM },
+ { "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
+ { "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
+ { "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
+ { "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
+ { "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
+ { NULL, NULL, 0 }
+};
+
+int
+dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
+{
+ const dt_option_t *op;
+
+ if (opt == NULL)
+ return (dt_set_errno(dtp, EINVAL));
+
+ /*
+ * We only need to search the run-time options -- it's not legal
+ * to get the values of compile-time options.
+ */
+ for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
+ if (strcmp(op->o_name, opt) == 0) {
+ *val = dtp->dt_options[op->o_option];
+ return (0);
+ }
+ }
+
+ for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
+ if (strcmp(op->o_name, opt) == 0) {
+ *val = dtp->dt_options[op->o_option];
+ return (0);
+ }
+ }
+
+ return (dt_set_errno(dtp, EDT_BADOPTNAME));
+}
+
+int
+dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
+{
+ const dt_option_t *op;
+
+ if (opt == NULL)
+ return (dt_set_errno(dtp, EINVAL));
+
+ for (op = _dtrace_ctoptions; op->o_name != NULL; op++) {
+ if (strcmp(op->o_name, opt) == 0)
+ return (op->o_func(dtp, val, op->o_option));
+ }
+
+ for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
+ if (strcmp(op->o_name, opt) == 0)
+ return (op->o_func(dtp, val, op->o_option));
+ }
+
+ for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
+ if (strcmp(op->o_name, opt) == 0) {
+ /*
+ * Only dynamic run-time options may be set while
+ * tracing is active.
+ */
+ if (dtp->dt_active)
+ return (dt_set_errno(dtp, EDT_ACTIVE));
+
+ return (op->o_func(dtp, val, op->o_option));
+ }
+ }
+
+ return (dt_set_errno(dtp, EDT_BADOPTNAME));
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
new file mode 100644
index 000000000000..f028f99ccf64
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
@@ -0,0 +1,5192 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent Inc. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * DTrace D Language Parser
+ *
+ * The D Parser is a lex/yacc parser consisting of the lexer dt_lex.l, the
+ * parsing grammar dt_grammar.y, and this file, dt_parser.c, which handles
+ * the construction of the parse tree nodes and their syntactic validation.
+ * The parse tree is constructed of dt_node_t structures (see <dt_parser.h>)
+ * that are built in two passes: (1) the "create" pass, where the parse tree
+ * nodes are allocated by calls from the grammar to dt_node_*() subroutines,
+ * and (2) the "cook" pass, where nodes are coalesced, assigned D types, and
+ * validated according to the syntactic rules of the language.
+ *
+ * All node allocations are performed using dt_node_alloc(). All node frees
+ * during the parsing phase are performed by dt_node_free(), which frees node-
+ * internal state but does not actually free the nodes. All final node frees
+ * are done as part of the end of dt_compile() or as part of destroying
+ * persistent identifiers or translators which have embedded nodes.
+ *
+ * The dt_node_* routines that implement pass (1) may allocate new nodes. The
+ * dt_cook_* routines that implement pass (2) may *not* allocate new nodes.
+ * They may free existing nodes using dt_node_free(), but they may not actually
+ * deallocate any dt_node_t's. Currently dt_cook_op2() is an exception to this
+ * rule: see the comments therein for how this issue is resolved.
+ *
+ * The dt_cook_* routines are responsible for (at minimum) setting the final
+ * node type (dn_ctfp/dn_type) and attributes (dn_attr). If dn_ctfp/dn_type
+ * are set manually (i.e. not by one of the type assignment functions), then
+ * the DT_NF_COOKED flag must be set manually on the node.
+ *
+ * The cooking pass can be applied to the same parse tree more than once (used
+ * in the case of a comma-separated list of probe descriptions). As such, the
+ * cook routines must not perform any parse tree transformations which would
+ * be invalid if the tree were subsequently cooked using a different context.
+ *
+ * The dn_ctfp and dn_type fields form the type of the node. This tuple can
+ * take on the following set of values, which form our type invariants:
+ *
+ * 1. dn_ctfp = NULL, dn_type = CTF_ERR
+ *
+ * In this state, the node has unknown type and is not yet cooked. The
+ * DT_NF_COOKED flag is not yet set on the node.
+ *
+ * 2. dn_ctfp = DT_DYN_CTFP(dtp), dn_type = DT_DYN_TYPE(dtp)
+ *
+ * In this state, the node is a dynamic D type. This means that generic
+ * operations are not valid on this node and only code that knows how to
+ * examine the inner details of the node can operate on it. A <DYN> node
+ * must have dn_ident set to point to an identifier describing the object
+ * and its type. The DT_NF_REF flag is set for all nodes of type <DYN>.
+ * At present, the D compiler uses the <DYN> type for:
+ *
+ * - associative arrays that do not yet have a value type defined
+ * - translated data (i.e. the result of the xlate operator)
+ * - aggregations
+ *
+ * 3. dn_ctfp = DT_STR_CTFP(dtp), dn_type = DT_STR_TYPE(dtp)
+ *
+ * In this state, the node is of type D string. The string type is really
+ * a char[0] typedef, but requires special handling throughout the compiler.
+ *
+ * 4. dn_ctfp != NULL, dn_type = any other type ID
+ *
+ * In this state, the node is of some known D/CTF type. The normal libctf
+ * APIs can be used to learn more about the type name or structure. When
+ * the type is assigned, the DT_NF_SIGNED, DT_NF_REF, and DT_NF_BITFIELD
+ * flags cache the corresponding attributes of the underlying CTF type.
+ */
+
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <strings.h>
+#include <assert.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <dt_impl.h>
+#include <dt_grammar.h>
+#include <dt_module.h>
+#include <dt_provider.h>
+#include <dt_string.h>
+#include <dt_as.h>
+
+dt_pcb_t *yypcb; /* current control block for parser */
+dt_node_t *yypragma; /* lex token list for control lines */
+char yyintprefix; /* int token macro prefix (+/-) */
+char yyintsuffix[4]; /* int token suffix string [uU][lL] */
+int yyintdecimal; /* int token format flag (1=decimal, 0=octal/hex) */
+
+static const char *
+opstr(int op)
+{
+ switch (op) {
+ case DT_TOK_COMMA: return (",");
+ case DT_TOK_ELLIPSIS: return ("...");
+ case DT_TOK_ASGN: return ("=");
+ case DT_TOK_ADD_EQ: return ("+=");
+ case DT_TOK_SUB_EQ: return ("-=");
+ case DT_TOK_MUL_EQ: return ("*=");
+ case DT_TOK_DIV_EQ: return ("/=");
+ case DT_TOK_MOD_EQ: return ("%=");
+ case DT_TOK_AND_EQ: return ("&=");
+ case DT_TOK_XOR_EQ: return ("^=");
+ case DT_TOK_OR_EQ: return ("|=");
+ case DT_TOK_LSH_EQ: return ("<<=");
+ case DT_TOK_RSH_EQ: return (">>=");
+ case DT_TOK_QUESTION: return ("?");
+ case DT_TOK_COLON: return (":");
+ case DT_TOK_LOR: return ("||");
+ case DT_TOK_LXOR: return ("^^");
+ case DT_TOK_LAND: return ("&&");
+ case DT_TOK_BOR: return ("|");
+ case DT_TOK_XOR: return ("^");
+ case DT_TOK_BAND: return ("&");
+ case DT_TOK_EQU: return ("==");
+ case DT_TOK_NEQ: return ("!=");
+ case DT_TOK_LT: return ("<");
+ case DT_TOK_LE: return ("<=");
+ case DT_TOK_GT: return (">");
+ case DT_TOK_GE: return (">=");
+ case DT_TOK_LSH: return ("<<");
+ case DT_TOK_RSH: return (">>");
+ case DT_TOK_ADD: return ("+");
+ case DT_TOK_SUB: return ("-");
+ case DT_TOK_MUL: return ("*");
+ case DT_TOK_DIV: return ("/");
+ case DT_TOK_MOD: return ("%");
+ case DT_TOK_LNEG: return ("!");
+ case DT_TOK_BNEG: return ("~");
+ case DT_TOK_ADDADD: return ("++");
+ case DT_TOK_PREINC: return ("++");
+ case DT_TOK_POSTINC: return ("++");
+ case DT_TOK_SUBSUB: return ("--");
+ case DT_TOK_PREDEC: return ("--");
+ case DT_TOK_POSTDEC: return ("--");
+ case DT_TOK_IPOS: return ("+");
+ case DT_TOK_INEG: return ("-");
+ case DT_TOK_DEREF: return ("*");
+ case DT_TOK_ADDROF: return ("&");
+ case DT_TOK_OFFSETOF: return ("offsetof");
+ case DT_TOK_SIZEOF: return ("sizeof");
+ case DT_TOK_STRINGOF: return ("stringof");
+ case DT_TOK_XLATE: return ("xlate");
+ case DT_TOK_LPAR: return ("(");
+ case DT_TOK_RPAR: return (")");
+ case DT_TOK_LBRAC: return ("[");
+ case DT_TOK_RBRAC: return ("]");
+ case DT_TOK_PTR: return ("->");
+ case DT_TOK_DOT: return (".");
+ case DT_TOK_STRING: return ("<string>");
+ case DT_TOK_IDENT: return ("<ident>");
+ case DT_TOK_TNAME: return ("<type>");
+ case DT_TOK_INT: return ("<int>");
+ default: return ("<?>");
+ }
+}
+
+int
+dt_type_lookup(const char *s, dtrace_typeinfo_t *tip)
+{
+ static const char delimiters[] = " \t\n\r\v\f*`";
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ const char *p, *q, *r, *end, *obj;
+
+ for (p = s, end = s + strlen(s); *p != '\0'; p = q) {
+ while (isspace(*p))
+ p++; /* skip leading whitespace prior to token */
+
+ if (p == end || (q = strpbrk(p + 1, delimiters)) == NULL)
+ break; /* empty string or single token remaining */
+
+ if (*q == '`') {
+ char *object = alloca((size_t)(q - p) + 1);
+ char *type = alloca((size_t)(end - s) + 1);
+
+ /*
+ * Copy from the start of the token (p) to the location
+ * backquote (q) to extract the nul-terminated object.
+ */
+ bcopy(p, object, (size_t)(q - p));
+ object[(size_t)(q - p)] = '\0';
+
+ /*
+ * Copy the original string up to the start of this
+ * token (p) into type, and then concatenate everything
+ * after q. This is the type name without the object.
+ */
+ bcopy(s, type, (size_t)(p - s));
+ bcopy(q + 1, type + (size_t)(p - s), strlen(q + 1) + 1);
+
+ /*
+ * There may be at most three delimeters. The second
+ * delimeter is usually used to distinguish the type
+ * within a given module, however, there could be a link
+ * map id on the scene in which case that delimeter
+ * would be the third. We determine presence of the lmid
+ * if it rouglhly meets the from LM[0-9]
+ */
+ if ((r = strchr(q + 1, '`')) != NULL &&
+ ((r = strchr(r + 1, '`')) != NULL)) {
+ if (strchr(r + 1, '`') != NULL)
+ return (dt_set_errno(dtp,
+ EDT_BADSCOPE));
+ if (q[1] != 'L' || q[2] != 'M')
+ return (dt_set_errno(dtp,
+ EDT_BADSCOPE));
+ }
+
+ return (dtrace_lookup_by_type(dtp, object, type, tip));
+ }
+ }
+
+ if (yypcb->pcb_idepth != 0)
+ obj = DTRACE_OBJ_CDEFS;
+ else
+ obj = DTRACE_OBJ_EVERY;
+
+ return (dtrace_lookup_by_type(dtp, obj, s, tip));
+}
+
+/*
+ * When we parse type expressions or parse an expression with unary "&", we
+ * need to find a type that is a pointer to a previously known type.
+ * Unfortunately CTF is limited to a per-container view, so ctf_type_pointer()
+ * alone does not suffice for our needs. We provide a more intelligent wrapper
+ * for the compiler that attempts to compute a pointer to either the given type
+ * or its base (that is, we try both "foo_t *" and "struct foo *"), and also
+ * to potentially construct the required type on-the-fly.
+ */
+int
+dt_type_pointer(dtrace_typeinfo_t *tip)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ ctf_file_t *ctfp = tip->dtt_ctfp;
+ ctf_id_t type = tip->dtt_type;
+ ctf_id_t base = ctf_type_resolve(ctfp, type);
+ uint_t bflags = tip->dtt_flags;
+
+ dt_module_t *dmp;
+ ctf_id_t ptr;
+
+ if ((ptr = ctf_type_pointer(ctfp, type)) != CTF_ERR ||
+ (ptr = ctf_type_pointer(ctfp, base)) != CTF_ERR) {
+ tip->dtt_type = ptr;
+ return (0);
+ }
+
+ if (yypcb->pcb_idepth != 0)
+ dmp = dtp->dt_cdefs;
+ else
+ dmp = dtp->dt_ddefs;
+
+ if (ctfp != dmp->dm_ctfp && ctfp != ctf_parent_file(dmp->dm_ctfp) &&
+ (type = ctf_add_type(dmp->dm_ctfp, ctfp, type)) == CTF_ERR) {
+ dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp);
+ return (dt_set_errno(dtp, EDT_CTF));
+ }
+
+ ptr = ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, type);
+
+ if (ptr == CTF_ERR || ctf_update(dmp->dm_ctfp) == CTF_ERR) {
+ dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp);
+ return (dt_set_errno(dtp, EDT_CTF));
+ }
+
+ tip->dtt_object = dmp->dm_name;
+ tip->dtt_ctfp = dmp->dm_ctfp;
+ tip->dtt_type = ptr;
+ tip->dtt_flags = bflags;
+
+ return (0);
+}
+
+const char *
+dt_type_name(ctf_file_t *ctfp, ctf_id_t type, char *buf, size_t len)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+
+ if (ctfp == DT_FPTR_CTFP(dtp) && type == DT_FPTR_TYPE(dtp))
+ (void) snprintf(buf, len, "function pointer");
+ else if (ctfp == DT_FUNC_CTFP(dtp) && type == DT_FUNC_TYPE(dtp))
+ (void) snprintf(buf, len, "function");
+ else if (ctfp == DT_DYN_CTFP(dtp) && type == DT_DYN_TYPE(dtp))
+ (void) snprintf(buf, len, "dynamic variable");
+ else if (ctfp == NULL)
+ (void) snprintf(buf, len, "<none>");
+ else if (ctf_type_name(ctfp, type, buf, len) == NULL)
+ (void) snprintf(buf, len, "unknown");
+
+ return (buf);
+}
+
+/*
+ * Perform the "usual arithmetic conversions" to determine which of the two
+ * input operand types should be promoted and used as a result type. The
+ * rules for this are described in ISOC[6.3.1.8] and K&R[A6.5].
+ */
+static void
+dt_type_promote(dt_node_t *lp, dt_node_t *rp, ctf_file_t **ofp, ctf_id_t *otype)
+{
+ ctf_file_t *lfp = lp->dn_ctfp;
+ ctf_id_t ltype = lp->dn_type;
+
+ ctf_file_t *rfp = rp->dn_ctfp;
+ ctf_id_t rtype = rp->dn_type;
+
+ ctf_id_t lbase = ctf_type_resolve(lfp, ltype);
+ uint_t lkind = ctf_type_kind(lfp, lbase);
+
+ ctf_id_t rbase = ctf_type_resolve(rfp, rtype);
+ uint_t rkind = ctf_type_kind(rfp, rbase);
+
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ ctf_encoding_t le, re;
+ uint_t lrank, rrank;
+
+ assert(lkind == CTF_K_INTEGER || lkind == CTF_K_ENUM);
+ assert(rkind == CTF_K_INTEGER || rkind == CTF_K_ENUM);
+
+ if (lkind == CTF_K_ENUM) {
+ lfp = DT_INT_CTFP(dtp);
+ ltype = lbase = DT_INT_TYPE(dtp);
+ }
+
+ if (rkind == CTF_K_ENUM) {
+ rfp = DT_INT_CTFP(dtp);
+ rtype = rbase = DT_INT_TYPE(dtp);
+ }
+
+ if (ctf_type_encoding(lfp, lbase, &le) == CTF_ERR) {
+ yypcb->pcb_hdl->dt_ctferr = ctf_errno(lfp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
+ }
+
+ if (ctf_type_encoding(rfp, rbase, &re) == CTF_ERR) {
+ yypcb->pcb_hdl->dt_ctferr = ctf_errno(rfp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
+ }
+
+ /*
+ * Compute an integer rank based on the size and unsigned status.
+ * If rank is identical, pick the "larger" of the equivalent types
+ * which we define as having a larger base ctf_id_t. If rank is
+ * different, pick the type with the greater rank.
+ */
+ lrank = le.cte_bits + ((le.cte_format & CTF_INT_SIGNED) == 0);
+ rrank = re.cte_bits + ((re.cte_format & CTF_INT_SIGNED) == 0);
+
+ if (lrank == rrank) {
+ if (lbase - rbase < 0)
+ goto return_rtype;
+ else
+ goto return_ltype;
+ } else if (lrank > rrank) {
+ goto return_ltype;
+ } else
+ goto return_rtype;
+
+return_ltype:
+ *ofp = lfp;
+ *otype = ltype;
+ return;
+
+return_rtype:
+ *ofp = rfp;
+ *otype = rtype;
+}
+
+void
+dt_node_promote(dt_node_t *lp, dt_node_t *rp, dt_node_t *dnp)
+{
+ dt_type_promote(lp, rp, &dnp->dn_ctfp, &dnp->dn_type);
+ dt_node_type_assign(dnp, dnp->dn_ctfp, dnp->dn_type, B_FALSE);
+ dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+}
+
+const char *
+dt_node_name(const dt_node_t *dnp, char *buf, size_t len)
+{
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ const char *prefix = "", *suffix = "";
+ const dtrace_syminfo_t *dts;
+ char *s;
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_INT:
+ (void) snprintf(buf, len, "integer constant 0x%llx",
+ (u_longlong_t)dnp->dn_value);
+ break;
+ case DT_NODE_STRING:
+ s = strchr2esc(dnp->dn_string, strlen(dnp->dn_string));
+ (void) snprintf(buf, len, "string constant \"%s\"",
+ s != NULL ? s : dnp->dn_string);
+ free(s);
+ break;
+ case DT_NODE_IDENT:
+ (void) snprintf(buf, len, "identifier %s", dnp->dn_string);
+ break;
+ case DT_NODE_VAR:
+ case DT_NODE_FUNC:
+ case DT_NODE_AGG:
+ case DT_NODE_INLINE:
+ switch (dnp->dn_ident->di_kind) {
+ case DT_IDENT_FUNC:
+ case DT_IDENT_AGGFUNC:
+ case DT_IDENT_ACTFUNC:
+ suffix = "( )";
+ break;
+ case DT_IDENT_AGG:
+ prefix = "@";
+ break;
+ }
+ (void) snprintf(buf, len, "%s %s%s%s",
+ dt_idkind_name(dnp->dn_ident->di_kind),
+ prefix, dnp->dn_ident->di_name, suffix);
+ break;
+ case DT_NODE_SYM:
+ dts = dnp->dn_ident->di_data;
+ (void) snprintf(buf, len, "symbol %s`%s",
+ dts->dts_object, dts->dts_name);
+ break;
+ case DT_NODE_TYPE:
+ (void) snprintf(buf, len, "type %s",
+ dt_node_type_name(dnp, n1, sizeof (n1)));
+ break;
+ case DT_NODE_OP1:
+ case DT_NODE_OP2:
+ case DT_NODE_OP3:
+ (void) snprintf(buf, len, "operator %s", opstr(dnp->dn_op));
+ break;
+ case DT_NODE_DEXPR:
+ case DT_NODE_DFUNC:
+ if (dnp->dn_expr)
+ return (dt_node_name(dnp->dn_expr, buf, len));
+ (void) snprintf(buf, len, "%s", "statement");
+ break;
+ case DT_NODE_PDESC:
+ if (dnp->dn_desc->dtpd_id == 0) {
+ (void) snprintf(buf, len,
+ "probe description %s:%s:%s:%s",
+ dnp->dn_desc->dtpd_provider, dnp->dn_desc->dtpd_mod,
+ dnp->dn_desc->dtpd_func, dnp->dn_desc->dtpd_name);
+ } else {
+ (void) snprintf(buf, len, "probe description %u",
+ dnp->dn_desc->dtpd_id);
+ }
+ break;
+ case DT_NODE_CLAUSE:
+ (void) snprintf(buf, len, "%s", "clause");
+ break;
+ case DT_NODE_MEMBER:
+ (void) snprintf(buf, len, "member %s", dnp->dn_membname);
+ break;
+ case DT_NODE_XLATOR:
+ (void) snprintf(buf, len, "translator <%s> (%s)",
+ dt_type_name(dnp->dn_xlator->dx_dst_ctfp,
+ dnp->dn_xlator->dx_dst_type, n1, sizeof (n1)),
+ dt_type_name(dnp->dn_xlator->dx_src_ctfp,
+ dnp->dn_xlator->dx_src_type, n2, sizeof (n2)));
+ break;
+ case DT_NODE_PROG:
+ (void) snprintf(buf, len, "%s", "program");
+ break;
+ default:
+ (void) snprintf(buf, len, "node <%u>", dnp->dn_kind);
+ break;
+ }
+
+ return (buf);
+}
+
+/*
+ * dt_node_xalloc() can be used to create new parse nodes from any libdtrace
+ * caller. The caller is responsible for assigning dn_link appropriately.
+ */
+dt_node_t *
+dt_node_xalloc(dtrace_hdl_t *dtp, int kind)
+{
+ dt_node_t *dnp = dt_alloc(dtp, sizeof (dt_node_t));
+
+ if (dnp == NULL)
+ return (NULL);
+
+ dnp->dn_ctfp = NULL;
+ dnp->dn_type = CTF_ERR;
+ dnp->dn_kind = (uchar_t)kind;
+ dnp->dn_flags = 0;
+ dnp->dn_op = 0;
+ dnp->dn_line = -1;
+ dnp->dn_reg = -1;
+ dnp->dn_attr = _dtrace_defattr;
+ dnp->dn_list = NULL;
+ dnp->dn_link = NULL;
+ bzero(&dnp->dn_u, sizeof (dnp->dn_u));
+
+ return (dnp);
+}
+
+/*
+ * dt_node_alloc() is used to create new parse nodes from the parser. It
+ * assigns the node location based on the current lexer line number and places
+ * the new node on the default allocation list. If allocation fails, we
+ * automatically longjmp the caller back to the enclosing compilation call.
+ */
+static dt_node_t *
+dt_node_alloc(int kind)
+{
+ dt_node_t *dnp = dt_node_xalloc(yypcb->pcb_hdl, kind);
+
+ if (dnp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dnp->dn_line = yylineno;
+ dnp->dn_link = yypcb->pcb_list;
+ yypcb->pcb_list = dnp;
+
+ return (dnp);
+}
+
+void
+dt_node_free(dt_node_t *dnp)
+{
+ uchar_t kind = dnp->dn_kind;
+
+ dnp->dn_kind = DT_NODE_FREE;
+
+ switch (kind) {
+ case DT_NODE_STRING:
+ case DT_NODE_IDENT:
+ case DT_NODE_TYPE:
+ free(dnp->dn_string);
+ dnp->dn_string = NULL;
+ break;
+
+ case DT_NODE_VAR:
+ case DT_NODE_FUNC:
+ case DT_NODE_PROBE:
+ if (dnp->dn_ident != NULL) {
+ if (dnp->dn_ident->di_flags & DT_IDFLG_ORPHAN)
+ dt_ident_destroy(dnp->dn_ident);
+ dnp->dn_ident = NULL;
+ }
+ dt_node_list_free(&dnp->dn_args);
+ break;
+
+ case DT_NODE_OP1:
+ if (dnp->dn_child != NULL) {
+ dt_node_free(dnp->dn_child);
+ dnp->dn_child = NULL;
+ }
+ break;
+
+ case DT_NODE_OP3:
+ if (dnp->dn_expr != NULL) {
+ dt_node_free(dnp->dn_expr);
+ dnp->dn_expr = NULL;
+ }
+ /*FALLTHRU*/
+ case DT_NODE_OP2:
+ if (dnp->dn_left != NULL) {
+ dt_node_free(dnp->dn_left);
+ dnp->dn_left = NULL;
+ }
+ if (dnp->dn_right != NULL) {
+ dt_node_free(dnp->dn_right);
+ dnp->dn_right = NULL;
+ }
+ break;
+
+ case DT_NODE_DEXPR:
+ case DT_NODE_DFUNC:
+ if (dnp->dn_expr != NULL) {
+ dt_node_free(dnp->dn_expr);
+ dnp->dn_expr = NULL;
+ }
+ break;
+
+ case DT_NODE_AGG:
+ if (dnp->dn_aggfun != NULL) {
+ dt_node_free(dnp->dn_aggfun);
+ dnp->dn_aggfun = NULL;
+ }
+ dt_node_list_free(&dnp->dn_aggtup);
+ break;
+
+ case DT_NODE_PDESC:
+ free(dnp->dn_spec);
+ dnp->dn_spec = NULL;
+ free(dnp->dn_desc);
+ dnp->dn_desc = NULL;
+ break;
+
+ case DT_NODE_CLAUSE:
+ if (dnp->dn_pred != NULL)
+ dt_node_free(dnp->dn_pred);
+ if (dnp->dn_locals != NULL)
+ dt_idhash_destroy(dnp->dn_locals);
+ dt_node_list_free(&dnp->dn_pdescs);
+ dt_node_list_free(&dnp->dn_acts);
+ break;
+
+ case DT_NODE_MEMBER:
+ free(dnp->dn_membname);
+ dnp->dn_membname = NULL;
+ if (dnp->dn_membexpr != NULL) {
+ dt_node_free(dnp->dn_membexpr);
+ dnp->dn_membexpr = NULL;
+ }
+ break;
+
+ case DT_NODE_PROVIDER:
+ dt_node_list_free(&dnp->dn_probes);
+ free(dnp->dn_provname);
+ dnp->dn_provname = NULL;
+ break;
+
+ case DT_NODE_PROG:
+ dt_node_list_free(&dnp->dn_list);
+ break;
+ }
+}
+
+void
+dt_node_attr_assign(dt_node_t *dnp, dtrace_attribute_t attr)
+{
+ if ((yypcb->pcb_cflags & DTRACE_C_EATTR) &&
+ (dt_attr_cmp(attr, yypcb->pcb_amin) < 0)) {
+ char a[DTRACE_ATTR2STR_MAX];
+ char s[BUFSIZ];
+
+ dnerror(dnp, D_ATTR_MIN, "attributes for %s (%s) are less than "
+ "predefined minimum\n", dt_node_name(dnp, s, sizeof (s)),
+ dtrace_attr2str(attr, a, sizeof (a)));
+ }
+
+ dnp->dn_attr = attr;
+}
+
+void
+dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type,
+ boolean_t user)
+{
+ ctf_id_t base = ctf_type_resolve(fp, type);
+ uint_t kind = ctf_type_kind(fp, base);
+ ctf_encoding_t e;
+
+ dnp->dn_flags &=
+ ~(DT_NF_SIGNED | DT_NF_REF | DT_NF_BITFIELD | DT_NF_USERLAND);
+
+ if (kind == CTF_K_INTEGER && ctf_type_encoding(fp, base, &e) == 0) {
+ size_t size = e.cte_bits / NBBY;
+
+ if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)))
+ dnp->dn_flags |= DT_NF_BITFIELD;
+
+ if (e.cte_format & CTF_INT_SIGNED)
+ dnp->dn_flags |= DT_NF_SIGNED;
+ }
+
+ if (kind == CTF_K_FLOAT && ctf_type_encoding(fp, base, &e) == 0) {
+ if (e.cte_bits / NBBY > sizeof (uint64_t))
+ dnp->dn_flags |= DT_NF_REF;
+ }
+
+ if (kind == CTF_K_STRUCT || kind == CTF_K_UNION ||
+ kind == CTF_K_FORWARD ||
+ kind == CTF_K_ARRAY || kind == CTF_K_FUNCTION)
+ dnp->dn_flags |= DT_NF_REF;
+ else if (yypcb != NULL && fp == DT_DYN_CTFP(yypcb->pcb_hdl) &&
+ type == DT_DYN_TYPE(yypcb->pcb_hdl))
+ dnp->dn_flags |= DT_NF_REF;
+
+ if (user)
+ dnp->dn_flags |= DT_NF_USERLAND;
+
+ dnp->dn_flags |= DT_NF_COOKED;
+ dnp->dn_ctfp = fp;
+ dnp->dn_type = type;
+}
+
+void
+dt_node_type_propagate(const dt_node_t *src, dt_node_t *dst)
+{
+ assert(src->dn_flags & DT_NF_COOKED);
+ dst->dn_flags = src->dn_flags & ~DT_NF_LVALUE;
+ dst->dn_ctfp = src->dn_ctfp;
+ dst->dn_type = src->dn_type;
+}
+
+const char *
+dt_node_type_name(const dt_node_t *dnp, char *buf, size_t len)
+{
+ if (dt_node_is_dynamic(dnp) && dnp->dn_ident != NULL) {
+ (void) snprintf(buf, len, "%s",
+ dt_idkind_name(dt_ident_resolve(dnp->dn_ident)->di_kind));
+ return (buf);
+ }
+
+ if (dnp->dn_flags & DT_NF_USERLAND) {
+ size_t n = snprintf(buf, len, "userland ");
+ len = len > n ? len - n : 0;
+ (void) dt_type_name(dnp->dn_ctfp, dnp->dn_type, buf + n, len);
+ return (buf);
+ }
+
+ return (dt_type_name(dnp->dn_ctfp, dnp->dn_type, buf, len));
+}
+
+size_t
+dt_node_type_size(const dt_node_t *dnp)
+{
+ ctf_id_t base;
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+
+ if (dnp->dn_kind == DT_NODE_STRING)
+ return (strlen(dnp->dn_string) + 1);
+
+ if (dt_node_is_dynamic(dnp) && dnp->dn_ident != NULL)
+ return (dt_ident_size(dnp->dn_ident));
+
+ base = ctf_type_resolve(dnp->dn_ctfp, dnp->dn_type);
+
+ if (ctf_type_kind(dnp->dn_ctfp, base) == CTF_K_FORWARD)
+ return (0);
+
+ /*
+ * Here we have a 32-bit user pointer that is being used with a 64-bit
+ * kernel. When we're using it and its tagged as a userland reference --
+ * then we need to keep it as a 32-bit pointer. However, if we are
+ * referring to it as a kernel address, eg. being used after a copyin()
+ * then we need to make sure that we actually return the kernel's size
+ * of a pointer, 8 bytes.
+ */
+ if (ctf_type_kind(dnp->dn_ctfp, base) == CTF_K_POINTER &&
+ ctf_getmodel(dnp->dn_ctfp) == CTF_MODEL_ILP32 &&
+ !(dnp->dn_flags & DT_NF_USERLAND) &&
+ dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
+ return (8);
+
+ return (ctf_type_size(dnp->dn_ctfp, dnp->dn_type));
+}
+
+/*
+ * Determine if the specified parse tree node references an identifier of the
+ * specified kind, and if so return a pointer to it; otherwise return NULL.
+ * This function resolves the identifier itself, following through any inlines.
+ */
+dt_ident_t *
+dt_node_resolve(const dt_node_t *dnp, uint_t idkind)
+{
+ dt_ident_t *idp;
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_VAR:
+ case DT_NODE_SYM:
+ case DT_NODE_FUNC:
+ case DT_NODE_AGG:
+ case DT_NODE_INLINE:
+ case DT_NODE_PROBE:
+ idp = dt_ident_resolve(dnp->dn_ident);
+ return (idp->di_kind == idkind ? idp : NULL);
+ }
+
+ if (dt_node_is_dynamic(dnp)) {
+ idp = dt_ident_resolve(dnp->dn_ident);
+ return (idp->di_kind == idkind ? idp : NULL);
+ }
+
+ return (NULL);
+}
+
+size_t
+dt_node_sizeof(const dt_node_t *dnp)
+{
+ dtrace_syminfo_t *sip;
+ GElf_Sym sym;
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+
+ /*
+ * The size of the node as used for the sizeof() operator depends on
+ * the kind of the node. If the node is a SYM, the size is obtained
+ * from the symbol table; if it is not a SYM, the size is determined
+ * from the node's type. This is slightly different from C's sizeof()
+ * operator in that (for example) when applied to a function, sizeof()
+ * will evaluate to the length of the function rather than the size of
+ * the function type.
+ */
+ if (dnp->dn_kind != DT_NODE_SYM)
+ return (dt_node_type_size(dnp));
+
+ sip = dnp->dn_ident->di_data;
+
+ if (dtrace_lookup_by_name(dtp, sip->dts_object,
+ sip->dts_name, &sym, NULL) == -1)
+ return (0);
+
+ return (sym.st_size);
+}
+
+int
+dt_node_is_integer(const dt_node_t *dnp)
+{
+ ctf_file_t *fp = dnp->dn_ctfp;
+ ctf_encoding_t e;
+ ctf_id_t type;
+ uint_t kind;
+
+ assert(dnp->dn_flags & DT_NF_COOKED);
+
+ type = ctf_type_resolve(fp, dnp->dn_type);
+ kind = ctf_type_kind(fp, type);
+
+ if (kind == CTF_K_INTEGER &&
+ ctf_type_encoding(fp, type, &e) == 0 && IS_VOID(e))
+ return (0); /* void integer */
+
+ return (kind == CTF_K_INTEGER || kind == CTF_K_ENUM);
+}
+
+int
+dt_node_is_float(const dt_node_t *dnp)
+{
+ ctf_file_t *fp = dnp->dn_ctfp;
+ ctf_encoding_t e;
+ ctf_id_t type;
+ uint_t kind;
+
+ assert(dnp->dn_flags & DT_NF_COOKED);
+
+ type = ctf_type_resolve(fp, dnp->dn_type);
+ kind = ctf_type_kind(fp, type);
+
+ return (kind == CTF_K_FLOAT &&
+ ctf_type_encoding(dnp->dn_ctfp, type, &e) == 0 && (
+ e.cte_format == CTF_FP_SINGLE || e.cte_format == CTF_FP_DOUBLE ||
+ e.cte_format == CTF_FP_LDOUBLE));
+}
+
+int
+dt_node_is_scalar(const dt_node_t *dnp)
+{
+ ctf_file_t *fp = dnp->dn_ctfp;
+ ctf_encoding_t e;
+ ctf_id_t type;
+ uint_t kind;
+
+ assert(dnp->dn_flags & DT_NF_COOKED);
+
+ type = ctf_type_resolve(fp, dnp->dn_type);
+ kind = ctf_type_kind(fp, type);
+
+ if (kind == CTF_K_INTEGER &&
+ ctf_type_encoding(fp, type, &e) == 0 && IS_VOID(e))
+ return (0); /* void cannot be used as a scalar */
+
+ return (kind == CTF_K_INTEGER || kind == CTF_K_ENUM ||
+ kind == CTF_K_POINTER);
+}
+
+int
+dt_node_is_arith(const dt_node_t *dnp)
+{
+ ctf_file_t *fp = dnp->dn_ctfp;
+ ctf_encoding_t e;
+ ctf_id_t type;
+ uint_t kind;
+
+ assert(dnp->dn_flags & DT_NF_COOKED);
+
+ type = ctf_type_resolve(fp, dnp->dn_type);
+ kind = ctf_type_kind(fp, type);
+
+ if (kind == CTF_K_INTEGER)
+ return (ctf_type_encoding(fp, type, &e) == 0 && !IS_VOID(e));
+ else
+ return (kind == CTF_K_ENUM);
+}
+
+int
+dt_node_is_vfptr(const dt_node_t *dnp)
+{
+ ctf_file_t *fp = dnp->dn_ctfp;
+ ctf_encoding_t e;
+ ctf_id_t type;
+ uint_t kind;
+
+ assert(dnp->dn_flags & DT_NF_COOKED);
+
+ type = ctf_type_resolve(fp, dnp->dn_type);
+ if (ctf_type_kind(fp, type) != CTF_K_POINTER)
+ return (0); /* type is not a pointer */
+
+ type = ctf_type_resolve(fp, ctf_type_reference(fp, type));
+ kind = ctf_type_kind(fp, type);
+
+ return (kind == CTF_K_FUNCTION || (kind == CTF_K_INTEGER &&
+ ctf_type_encoding(fp, type, &e) == 0 && IS_VOID(e)));
+}
+
+int
+dt_node_is_dynamic(const dt_node_t *dnp)
+{
+ if (dnp->dn_kind == DT_NODE_VAR &&
+ (dnp->dn_ident->di_flags & DT_IDFLG_INLINE)) {
+ const dt_idnode_t *inp = dnp->dn_ident->di_iarg;
+ return (inp->din_root ? dt_node_is_dynamic(inp->din_root) : 0);
+ }
+
+ return (dnp->dn_ctfp == DT_DYN_CTFP(yypcb->pcb_hdl) &&
+ dnp->dn_type == DT_DYN_TYPE(yypcb->pcb_hdl));
+}
+
+int
+dt_node_is_string(const dt_node_t *dnp)
+{
+ return (dnp->dn_ctfp == DT_STR_CTFP(yypcb->pcb_hdl) &&
+ dnp->dn_type == DT_STR_TYPE(yypcb->pcb_hdl));
+}
+
+int
+dt_node_is_stack(const dt_node_t *dnp)
+{
+ return (dnp->dn_ctfp == DT_STACK_CTFP(yypcb->pcb_hdl) &&
+ dnp->dn_type == DT_STACK_TYPE(yypcb->pcb_hdl));
+}
+
+int
+dt_node_is_symaddr(const dt_node_t *dnp)
+{
+ return (dnp->dn_ctfp == DT_SYMADDR_CTFP(yypcb->pcb_hdl) &&
+ dnp->dn_type == DT_SYMADDR_TYPE(yypcb->pcb_hdl));
+}
+
+int
+dt_node_is_usymaddr(const dt_node_t *dnp)
+{
+ return (dnp->dn_ctfp == DT_USYMADDR_CTFP(yypcb->pcb_hdl) &&
+ dnp->dn_type == DT_USYMADDR_TYPE(yypcb->pcb_hdl));
+}
+
+int
+dt_node_is_strcompat(const dt_node_t *dnp)
+{
+ ctf_file_t *fp = dnp->dn_ctfp;
+ ctf_encoding_t e;
+ ctf_arinfo_t r;
+ ctf_id_t base;
+ uint_t kind;
+
+ assert(dnp->dn_flags & DT_NF_COOKED);
+
+ base = ctf_type_resolve(fp, dnp->dn_type);
+ kind = ctf_type_kind(fp, base);
+
+ if (kind == CTF_K_POINTER &&
+ (base = ctf_type_reference(fp, base)) != CTF_ERR &&
+ (base = ctf_type_resolve(fp, base)) != CTF_ERR &&
+ ctf_type_encoding(fp, base, &e) == 0 && IS_CHAR(e))
+ return (1); /* promote char pointer to string */
+
+ if (kind == CTF_K_ARRAY && ctf_array_info(fp, base, &r) == 0 &&
+ (base = ctf_type_resolve(fp, r.ctr_contents)) != CTF_ERR &&
+ ctf_type_encoding(fp, base, &e) == 0 && IS_CHAR(e))
+ return (1); /* promote char array to string */
+
+ return (0);
+}
+
+int
+dt_node_is_pointer(const dt_node_t *dnp)
+{
+ ctf_file_t *fp = dnp->dn_ctfp;
+ uint_t kind;
+
+ assert(dnp->dn_flags & DT_NF_COOKED);
+
+ if (dt_node_is_string(dnp))
+ return (0); /* string are pass-by-ref but act like structs */
+
+ kind = ctf_type_kind(fp, ctf_type_resolve(fp, dnp->dn_type));
+ return (kind == CTF_K_POINTER || kind == CTF_K_ARRAY);
+}
+
+int
+dt_node_is_void(const dt_node_t *dnp)
+{
+ ctf_file_t *fp = dnp->dn_ctfp;
+ ctf_encoding_t e;
+ ctf_id_t type;
+
+ if (dt_node_is_dynamic(dnp))
+ return (0); /* <DYN> is an alias for void but not the same */
+
+ if (dt_node_is_stack(dnp))
+ return (0);
+
+ if (dt_node_is_symaddr(dnp) || dt_node_is_usymaddr(dnp))
+ return (0);
+
+ type = ctf_type_resolve(fp, dnp->dn_type);
+
+ return (ctf_type_kind(fp, type) == CTF_K_INTEGER &&
+ ctf_type_encoding(fp, type, &e) == 0 && IS_VOID(e));
+}
+
+int
+dt_node_is_ptrcompat(const dt_node_t *lp, const dt_node_t *rp,
+ ctf_file_t **fpp, ctf_id_t *tp)
+{
+ ctf_file_t *lfp = lp->dn_ctfp;
+ ctf_file_t *rfp = rp->dn_ctfp;
+
+ ctf_id_t lbase = CTF_ERR, rbase = CTF_ERR;
+ ctf_id_t lref = CTF_ERR, rref = CTF_ERR;
+
+ int lp_is_void, rp_is_void, lp_is_int, rp_is_int, compat;
+ uint_t lkind, rkind;
+ ctf_encoding_t e;
+ ctf_arinfo_t r;
+
+ assert(lp->dn_flags & DT_NF_COOKED);
+ assert(rp->dn_flags & DT_NF_COOKED);
+
+ if (dt_node_is_dynamic(lp) || dt_node_is_dynamic(rp))
+ return (0); /* fail if either node is a dynamic variable */
+
+ lp_is_int = dt_node_is_integer(lp);
+ rp_is_int = dt_node_is_integer(rp);
+
+ if (lp_is_int && rp_is_int)
+ return (0); /* fail if both nodes are integers */
+
+ if (lp_is_int && (lp->dn_kind != DT_NODE_INT || lp->dn_value != 0))
+ return (0); /* fail if lp is an integer that isn't 0 constant */
+
+ if (rp_is_int && (rp->dn_kind != DT_NODE_INT || rp->dn_value != 0))
+ return (0); /* fail if rp is an integer that isn't 0 constant */
+
+ if ((lp_is_int == 0 && rp_is_int == 0) && (
+ (lp->dn_flags & DT_NF_USERLAND) ^ (rp->dn_flags & DT_NF_USERLAND)))
+ return (0); /* fail if only one pointer is a userland address */
+
+ /*
+ * Resolve the left-hand and right-hand types to their base type, and
+ * then resolve the referenced type as well (assuming the base type
+ * is CTF_K_POINTER or CTF_K_ARRAY). Otherwise [lr]ref = CTF_ERR.
+ */
+ if (!lp_is_int) {
+ lbase = ctf_type_resolve(lfp, lp->dn_type);
+ lkind = ctf_type_kind(lfp, lbase);
+
+ if (lkind == CTF_K_POINTER) {
+ lref = ctf_type_resolve(lfp,
+ ctf_type_reference(lfp, lbase));
+ } else if (lkind == CTF_K_ARRAY &&
+ ctf_array_info(lfp, lbase, &r) == 0) {
+ lref = ctf_type_resolve(lfp, r.ctr_contents);
+ }
+ }
+
+ if (!rp_is_int) {
+ rbase = ctf_type_resolve(rfp, rp->dn_type);
+ rkind = ctf_type_kind(rfp, rbase);
+
+ if (rkind == CTF_K_POINTER) {
+ rref = ctf_type_resolve(rfp,
+ ctf_type_reference(rfp, rbase));
+ } else if (rkind == CTF_K_ARRAY &&
+ ctf_array_info(rfp, rbase, &r) == 0) {
+ rref = ctf_type_resolve(rfp, r.ctr_contents);
+ }
+ }
+
+ /*
+ * We know that one or the other type may still be a zero-valued
+ * integer constant. To simplify the code below, set the integer
+ * type variables equal to the non-integer types and proceed.
+ */
+ if (lp_is_int) {
+ lbase = rbase;
+ lkind = rkind;
+ lref = rref;
+ lfp = rfp;
+ } else if (rp_is_int) {
+ rbase = lbase;
+ rkind = lkind;
+ rref = lref;
+ rfp = lfp;
+ }
+
+ lp_is_void = ctf_type_encoding(lfp, lref, &e) == 0 && IS_VOID(e);
+ rp_is_void = ctf_type_encoding(rfp, rref, &e) == 0 && IS_VOID(e);
+
+ /*
+ * The types are compatible if both are pointers to the same type, or
+ * if either pointer is a void pointer. If they are compatible, set
+ * tp to point to the more specific pointer type and return it.
+ */
+ compat = (lkind == CTF_K_POINTER || lkind == CTF_K_ARRAY) &&
+ (rkind == CTF_K_POINTER || rkind == CTF_K_ARRAY) &&
+ (lp_is_void || rp_is_void || ctf_type_compat(lfp, lref, rfp, rref));
+
+ if (compat) {
+ if (fpp != NULL)
+ *fpp = rp_is_void ? lfp : rfp;
+ if (tp != NULL)
+ *tp = rp_is_void ? lbase : rbase;
+ }
+
+ return (compat);
+}
+
+/*
+ * The rules for checking argument types against parameter types are described
+ * in the ANSI-C spec (see K&R[A7.3.2] and K&R[A7.17]). We use the same rule
+ * set to determine whether associative array arguments match the prototype.
+ */
+int
+dt_node_is_argcompat(const dt_node_t *lp, const dt_node_t *rp)
+{
+ ctf_file_t *lfp = lp->dn_ctfp;
+ ctf_file_t *rfp = rp->dn_ctfp;
+
+ assert(lp->dn_flags & DT_NF_COOKED);
+ assert(rp->dn_flags & DT_NF_COOKED);
+
+ if (dt_node_is_integer(lp) && dt_node_is_integer(rp))
+ return (1); /* integer types are compatible */
+
+ if (dt_node_is_strcompat(lp) && dt_node_is_strcompat(rp))
+ return (1); /* string types are compatible */
+
+ if (dt_node_is_stack(lp) && dt_node_is_stack(rp))
+ return (1); /* stack types are compatible */
+
+ if (dt_node_is_symaddr(lp) && dt_node_is_symaddr(rp))
+ return (1); /* symaddr types are compatible */
+
+ if (dt_node_is_usymaddr(lp) && dt_node_is_usymaddr(rp))
+ return (1); /* usymaddr types are compatible */
+
+ switch (ctf_type_kind(lfp, ctf_type_resolve(lfp, lp->dn_type))) {
+ case CTF_K_FUNCTION:
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ return (ctf_type_compat(lfp, lp->dn_type, rfp, rp->dn_type));
+ default:
+ return (dt_node_is_ptrcompat(lp, rp, NULL, NULL));
+ }
+}
+
+/*
+ * We provide dt_node_is_posconst() as a convenience routine for callers who
+ * wish to verify that an argument is a positive non-zero integer constant.
+ */
+int
+dt_node_is_posconst(const dt_node_t *dnp)
+{
+ return (dnp->dn_kind == DT_NODE_INT && dnp->dn_value != 0 && (
+ (dnp->dn_flags & DT_NF_SIGNED) == 0 || (int64_t)dnp->dn_value > 0));
+}
+
+int
+dt_node_is_actfunc(const dt_node_t *dnp)
+{
+ return (dnp->dn_kind == DT_NODE_FUNC &&
+ dnp->dn_ident->di_kind == DT_IDENT_ACTFUNC);
+}
+
+/*
+ * The original rules for integer constant typing are described in K&R[A2.5.1].
+ * However, since we support long long, we instead use the rules from ISO C99
+ * clause 6.4.4.1 since that is where long longs are formally described. The
+ * rules require us to know whether the constant was specified in decimal or
+ * in octal or hex, which we do by looking at our lexer's 'yyintdecimal' flag.
+ * The type of an integer constant is the first of the corresponding list in
+ * which its value can be represented:
+ *
+ * unsuffixed decimal: int, long, long long
+ * unsuffixed oct/hex: int, unsigned int, long, unsigned long,
+ * long long, unsigned long long
+ * suffix [uU]: unsigned int, unsigned long, unsigned long long
+ * suffix [lL] decimal: long, long long
+ * suffix [lL] oct/hex: long, unsigned long, long long, unsigned long long
+ * suffix [uU][Ll]: unsigned long, unsigned long long
+ * suffix ll/LL decimal: long long
+ * suffix ll/LL oct/hex: long long, unsigned long long
+ * suffix [uU][ll/LL]: unsigned long long
+ *
+ * Given that our lexer has already validated the suffixes by regexp matching,
+ * there is an obvious way to concisely encode these rules: construct an array
+ * of the types in the order int, unsigned int, long, unsigned long, long long,
+ * unsigned long long. Compute an integer array starting index based on the
+ * suffix (e.g. none = 0, u = 1, ull = 5), and compute an increment based on
+ * the specifier (dec/oct/hex) and suffix (u). Then iterate from the starting
+ * index to the end, advancing using the increment, and searching until we
+ * find a limit that matches or we run out of choices (overflow). To make it
+ * even faster, we precompute the table of type information in dtrace_open().
+ */
+dt_node_t *
+dt_node_int(uintmax_t value)
+{
+ dt_node_t *dnp = dt_node_alloc(DT_NODE_INT);
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+
+ int n = (yyintdecimal | (yyintsuffix[0] == 'u')) + 1;
+ int i = 0;
+
+ const char *p;
+ char c;
+
+ dnp->dn_op = DT_TOK_INT;
+ dnp->dn_value = value;
+
+ for (p = yyintsuffix; (c = *p) != '\0'; p++) {
+ if (c == 'U' || c == 'u')
+ i += 1;
+ else if (c == 'L' || c == 'l')
+ i += 2;
+ }
+
+ for (; i < sizeof (dtp->dt_ints) / sizeof (dtp->dt_ints[0]); i += n) {
+ if (value <= dtp->dt_ints[i].did_limit) {
+ dt_node_type_assign(dnp,
+ dtp->dt_ints[i].did_ctfp,
+ dtp->dt_ints[i].did_type, B_FALSE);
+
+ /*
+ * If a prefix character is present in macro text, add
+ * in the corresponding operator node (see dt_lex.l).
+ */
+ switch (yyintprefix) {
+ case '+':
+ return (dt_node_op1(DT_TOK_IPOS, dnp));
+ case '-':
+ return (dt_node_op1(DT_TOK_INEG, dnp));
+ default:
+ return (dnp);
+ }
+ }
+ }
+
+ xyerror(D_INT_OFLOW, "integer constant 0x%llx cannot be represented "
+ "in any built-in integral type\n", (u_longlong_t)value);
+ /*NOTREACHED*/
+ return (NULL); /* keep gcc happy */
+}
+
+dt_node_t *
+dt_node_string(char *string)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_node_t *dnp;
+
+ if (string == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dnp = dt_node_alloc(DT_NODE_STRING);
+ dnp->dn_op = DT_TOK_STRING;
+ dnp->dn_string = string;
+ dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp), B_FALSE);
+
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_ident(char *name)
+{
+ dt_ident_t *idp;
+ dt_node_t *dnp;
+
+ if (name == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ /*
+ * If the identifier is an inlined integer constant, then create an INT
+ * node that is a clone of the inline parse tree node and return that
+ * immediately, allowing this inline to be used in parsing contexts
+ * that require constant expressions (e.g. scalar array sizes).
+ */
+ if ((idp = dt_idstack_lookup(&yypcb->pcb_globals, name)) != NULL &&
+ (idp->di_flags & DT_IDFLG_INLINE)) {
+ dt_idnode_t *inp = idp->di_iarg;
+
+ if (inp->din_root != NULL &&
+ inp->din_root->dn_kind == DT_NODE_INT) {
+ free(name);
+
+ dnp = dt_node_alloc(DT_NODE_INT);
+ dnp->dn_op = DT_TOK_INT;
+ dnp->dn_value = inp->din_root->dn_value;
+ dt_node_type_propagate(inp->din_root, dnp);
+
+ return (dnp);
+ }
+ }
+
+ dnp = dt_node_alloc(DT_NODE_IDENT);
+ dnp->dn_op = name[0] == '@' ? DT_TOK_AGG : DT_TOK_IDENT;
+ dnp->dn_string = name;
+
+ return (dnp);
+}
+
+/*
+ * Create an empty node of type corresponding to the given declaration.
+ * Explicit references to user types (C or D) are assigned the default
+ * stability; references to other types are _dtrace_typattr (Private).
+ */
+dt_node_t *
+dt_node_type(dt_decl_t *ddp)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dtrace_typeinfo_t dtt;
+ dt_node_t *dnp;
+ char *name = NULL;
+ int err;
+
+ /*
+ * If 'ddp' is NULL, we get a decl by popping the decl stack. This
+ * form of dt_node_type() is used by parameter rules in dt_grammar.y.
+ */
+ if (ddp == NULL)
+ ddp = dt_decl_pop_param(&name);
+
+ err = dt_decl_type(ddp, &dtt);
+ dt_decl_free(ddp);
+
+ if (err != 0) {
+ free(name);
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+ }
+
+ dnp = dt_node_alloc(DT_NODE_TYPE);
+ dnp->dn_op = DT_TOK_IDENT;
+ dnp->dn_string = name;
+
+ dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, dtt.dtt_flags);
+
+ if (dtt.dtt_ctfp == dtp->dt_cdefs->dm_ctfp ||
+ dtt.dtt_ctfp == dtp->dt_ddefs->dm_ctfp)
+ dt_node_attr_assign(dnp, _dtrace_defattr);
+ else
+ dt_node_attr_assign(dnp, _dtrace_typattr);
+
+ return (dnp);
+}
+
+/*
+ * Create a type node corresponding to a varargs (...) parameter by just
+ * assigning it type CTF_ERR. The decl processing code will handle this.
+ */
+dt_node_t *
+dt_node_vatype(void)
+{
+ dt_node_t *dnp = dt_node_alloc(DT_NODE_TYPE);
+
+ dnp->dn_op = DT_TOK_IDENT;
+ dnp->dn_ctfp = yypcb->pcb_hdl->dt_cdefs->dm_ctfp;
+ dnp->dn_type = CTF_ERR;
+ dnp->dn_attr = _dtrace_defattr;
+
+ return (dnp);
+}
+
+/*
+ * Instantiate a decl using the contents of the current declaration stack. As
+ * we do not currently permit decls to be initialized, this function currently
+ * returns NULL and no parse node is created. When this function is called,
+ * the topmost scope's ds_ident pointer will be set to NULL (indicating no
+ * init_declarator rule was matched) or will point to the identifier to use.
+ */
+dt_node_t *
+dt_node_decl(void)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_scope_t *dsp = &yypcb->pcb_dstack;
+ dt_dclass_t class = dsp->ds_class;
+ dt_decl_t *ddp = dt_decl_top();
+
+ dt_module_t *dmp;
+ dtrace_typeinfo_t dtt;
+ ctf_id_t type;
+
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ if (dt_decl_type(ddp, &dtt) != 0)
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+
+ /*
+ * If we have no declaration identifier, then this is either a spurious
+ * declaration of an intrinsic type (e.g. "extern int;") or declaration
+ * or redeclaration of a struct, union, or enum type or tag.
+ */
+ if (dsp->ds_ident == NULL) {
+ if (ddp->dd_kind != CTF_K_STRUCT &&
+ ddp->dd_kind != CTF_K_UNION && ddp->dd_kind != CTF_K_ENUM)
+ xyerror(D_DECL_USELESS, "useless declaration\n");
+
+ dt_dprintf("type %s added as id %ld\n", dt_type_name(
+ ddp->dd_ctfp, ddp->dd_type, n1, sizeof (n1)), ddp->dd_type);
+
+ return (NULL);
+ }
+
+ if (strchr(dsp->ds_ident, '`') != NULL) {
+ xyerror(D_DECL_SCOPE, "D scoping operator may not be used in "
+ "a declaration name (%s)\n", dsp->ds_ident);
+ }
+
+ /*
+ * If we are nested inside of a C include file, add the declaration to
+ * the C definition module; otherwise use the D definition module.
+ */
+ if (yypcb->pcb_idepth != 0)
+ dmp = dtp->dt_cdefs;
+ else
+ dmp = dtp->dt_ddefs;
+
+ /*
+ * If we see a global or static declaration of a function prototype,
+ * treat this as equivalent to a D extern declaration.
+ */
+ if (ctf_type_kind(dtt.dtt_ctfp, dtt.dtt_type) == CTF_K_FUNCTION &&
+ (class == DT_DC_DEFAULT || class == DT_DC_STATIC))
+ class = DT_DC_EXTERN;
+
+ switch (class) {
+ case DT_DC_AUTO:
+ case DT_DC_REGISTER:
+ case DT_DC_STATIC:
+ xyerror(D_DECL_BADCLASS, "specified storage class not "
+ "appropriate in D\n");
+ /*NOTREACHED*/
+
+ case DT_DC_EXTERN: {
+ dtrace_typeinfo_t ott;
+ dtrace_syminfo_t dts;
+ GElf_Sym sym;
+
+ int exists = dtrace_lookup_by_name(dtp,
+ dmp->dm_name, dsp->ds_ident, &sym, &dts) == 0;
+
+ if (exists && (dtrace_symbol_type(dtp, &sym, &dts, &ott) != 0 ||
+ ctf_type_cmp(dtt.dtt_ctfp, dtt.dtt_type,
+ ott.dtt_ctfp, ott.dtt_type) != 0)) {
+ xyerror(D_DECL_IDRED, "identifier redeclared: %s`%s\n"
+ "\t current: %s\n\tprevious: %s\n",
+ dmp->dm_name, dsp->ds_ident,
+ dt_type_name(dtt.dtt_ctfp, dtt.dtt_type,
+ n1, sizeof (n1)),
+ dt_type_name(ott.dtt_ctfp, ott.dtt_type,
+ n2, sizeof (n2)));
+ } else if (!exists && dt_module_extern(dtp, dmp,
+ dsp->ds_ident, &dtt) == NULL) {
+ xyerror(D_UNKNOWN,
+ "failed to extern %s: %s\n", dsp->ds_ident,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ } else {
+ dt_dprintf("extern %s`%s type=<%s>\n",
+ dmp->dm_name, dsp->ds_ident,
+ dt_type_name(dtt.dtt_ctfp, dtt.dtt_type,
+ n1, sizeof (n1)));
+ }
+ break;
+ }
+
+ case DT_DC_TYPEDEF:
+ if (dt_idstack_lookup(&yypcb->pcb_globals, dsp->ds_ident)) {
+ xyerror(D_DECL_IDRED, "global variable identifier "
+ "redeclared: %s\n", dsp->ds_ident);
+ }
+
+ if (ctf_lookup_by_name(dmp->dm_ctfp,
+ dsp->ds_ident) != CTF_ERR) {
+ xyerror(D_DECL_IDRED,
+ "typedef redeclared: %s\n", dsp->ds_ident);
+ }
+
+ /*
+ * If the source type for the typedef is not defined in the
+ * target container or its parent, copy the type to the target
+ * container and reset dtt_ctfp and dtt_type to the copy.
+ */
+ if (dtt.dtt_ctfp != dmp->dm_ctfp &&
+ dtt.dtt_ctfp != ctf_parent_file(dmp->dm_ctfp)) {
+
+ dtt.dtt_type = ctf_add_type(dmp->dm_ctfp,
+ dtt.dtt_ctfp, dtt.dtt_type);
+ dtt.dtt_ctfp = dmp->dm_ctfp;
+
+ if (dtt.dtt_type == CTF_ERR ||
+ ctf_update(dtt.dtt_ctfp) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to copy typedef %s "
+ "source type: %s\n", dsp->ds_ident,
+ ctf_errmsg(ctf_errno(dtt.dtt_ctfp)));
+ }
+ }
+
+ type = ctf_add_typedef(dmp->dm_ctfp,
+ CTF_ADD_ROOT, dsp->ds_ident, dtt.dtt_type);
+
+ if (type == CTF_ERR || ctf_update(dmp->dm_ctfp) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to typedef %s: %s\n",
+ dsp->ds_ident, ctf_errmsg(ctf_errno(dmp->dm_ctfp)));
+ }
+
+ dt_dprintf("typedef %s added as id %ld\n", dsp->ds_ident, type);
+ break;
+
+ default: {
+ ctf_encoding_t cte;
+ dt_idhash_t *dhp;
+ dt_ident_t *idp;
+ dt_node_t idn;
+ int assc, idkind;
+ uint_t id, kind;
+ ushort_t idflags;
+
+ switch (class) {
+ case DT_DC_THIS:
+ dhp = yypcb->pcb_locals;
+ idflags = DT_IDFLG_LOCAL;
+ idp = dt_idhash_lookup(dhp, dsp->ds_ident);
+ break;
+ case DT_DC_SELF:
+ dhp = dtp->dt_tls;
+ idflags = DT_IDFLG_TLS;
+ idp = dt_idhash_lookup(dhp, dsp->ds_ident);
+ break;
+ default:
+ dhp = dtp->dt_globals;
+ idflags = 0;
+ idp = dt_idstack_lookup(
+ &yypcb->pcb_globals, dsp->ds_ident);
+ break;
+ }
+
+ if (ddp->dd_kind == CTF_K_ARRAY && ddp->dd_node == NULL) {
+ xyerror(D_DECL_ARRNULL,
+ "array declaration requires array dimension or "
+ "tuple signature: %s\n", dsp->ds_ident);
+ }
+
+ if (idp != NULL && idp->di_gen == 0) {
+ xyerror(D_DECL_IDRED, "built-in identifier "
+ "redeclared: %s\n", idp->di_name);
+ }
+
+ if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_CDEFS,
+ dsp->ds_ident, NULL) == 0 ||
+ dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS,
+ dsp->ds_ident, NULL) == 0) {
+ xyerror(D_DECL_IDRED, "typedef identifier "
+ "redeclared: %s\n", dsp->ds_ident);
+ }
+
+ /*
+ * Cache some attributes of the decl to make the rest of this
+ * code simpler: if the decl is an array which is subscripted
+ * by a type rather than an integer, then it's an associative
+ * array (assc). We then expect to match either DT_IDENT_ARRAY
+ * for associative arrays or DT_IDENT_SCALAR for anything else.
+ */
+ assc = ddp->dd_kind == CTF_K_ARRAY &&
+ ddp->dd_node->dn_kind == DT_NODE_TYPE;
+
+ idkind = assc ? DT_IDENT_ARRAY : DT_IDENT_SCALAR;
+
+ /*
+ * Create a fake dt_node_t on the stack so we can determine the
+ * type of any matching identifier by assigning to this node.
+ * If the pre-existing ident has its di_type set, propagate
+ * the type by hand so as not to trigger a prototype check for
+ * arrays (yet); otherwise we use dt_ident_cook() on the ident
+ * to ensure it is fully initialized before looking at it.
+ */
+ bzero(&idn, sizeof (dt_node_t));
+
+ if (idp != NULL && idp->di_type != CTF_ERR)
+ dt_node_type_assign(&idn, idp->di_ctfp, idp->di_type,
+ B_FALSE);
+ else if (idp != NULL)
+ (void) dt_ident_cook(&idn, idp, NULL);
+
+ if (assc) {
+ if (class == DT_DC_THIS) {
+ xyerror(D_DECL_LOCASSC, "associative arrays "
+ "may not be declared as local variables:"
+ " %s\n", dsp->ds_ident);
+ }
+
+ if (dt_decl_type(ddp->dd_next, &dtt) != 0)
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+ }
+
+ if (idp != NULL && (idp->di_kind != idkind ||
+ ctf_type_cmp(dtt.dtt_ctfp, dtt.dtt_type,
+ idn.dn_ctfp, idn.dn_type) != 0)) {
+ xyerror(D_DECL_IDRED, "identifier redeclared: %s\n"
+ "\t current: %s %s\n\tprevious: %s %s\n",
+ dsp->ds_ident, dt_idkind_name(idkind),
+ dt_type_name(dtt.dtt_ctfp,
+ dtt.dtt_type, n1, sizeof (n1)),
+ dt_idkind_name(idp->di_kind),
+ dt_node_type_name(&idn, n2, sizeof (n2)));
+
+ } else if (idp != NULL && assc) {
+ const dt_idsig_t *isp = idp->di_data;
+ dt_node_t *dnp = ddp->dd_node;
+ int argc = 0;
+
+ for (; dnp != NULL; dnp = dnp->dn_list, argc++) {
+ const dt_node_t *pnp = &isp->dis_args[argc];
+
+ if (argc >= isp->dis_argc)
+ continue; /* tuple length mismatch */
+
+ if (ctf_type_cmp(dnp->dn_ctfp, dnp->dn_type,
+ pnp->dn_ctfp, pnp->dn_type) == 0)
+ continue;
+
+ xyerror(D_DECL_IDRED,
+ "identifier redeclared: %s\n"
+ "\t current: %s, key #%d of type %s\n"
+ "\tprevious: %s, key #%d of type %s\n",
+ dsp->ds_ident,
+ dt_idkind_name(idkind), argc + 1,
+ dt_node_type_name(dnp, n1, sizeof (n1)),
+ dt_idkind_name(idp->di_kind), argc + 1,
+ dt_node_type_name(pnp, n2, sizeof (n2)));
+ }
+
+ if (isp->dis_argc != argc) {
+ xyerror(D_DECL_IDRED,
+ "identifier redeclared: %s\n"
+ "\t current: %s of %s, tuple length %d\n"
+ "\tprevious: %s of %s, tuple length %d\n",
+ dsp->ds_ident, dt_idkind_name(idkind),
+ dt_type_name(dtt.dtt_ctfp, dtt.dtt_type,
+ n1, sizeof (n1)), argc,
+ dt_idkind_name(idp->di_kind),
+ dt_node_type_name(&idn, n2, sizeof (n2)),
+ isp->dis_argc);
+ }
+
+ } else if (idp == NULL) {
+ type = ctf_type_resolve(dtt.dtt_ctfp, dtt.dtt_type);
+ kind = ctf_type_kind(dtt.dtt_ctfp, type);
+
+ switch (kind) {
+ case CTF_K_INTEGER:
+ if (ctf_type_encoding(dtt.dtt_ctfp, type,
+ &cte) == 0 && IS_VOID(cte)) {
+ xyerror(D_DECL_VOIDOBJ, "cannot have "
+ "void object: %s\n", dsp->ds_ident);
+ }
+ break;
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ if (ctf_type_size(dtt.dtt_ctfp, type) != 0)
+ break; /* proceed to declaring */
+ /*FALLTHRU*/
+ case CTF_K_FORWARD:
+ xyerror(D_DECL_INCOMPLETE,
+ "incomplete struct/union/enum %s: %s\n",
+ dt_type_name(dtt.dtt_ctfp, dtt.dtt_type,
+ n1, sizeof (n1)), dsp->ds_ident);
+ /*NOTREACHED*/
+ }
+
+ if (dt_idhash_nextid(dhp, &id) == -1) {
+ xyerror(D_ID_OFLOW, "cannot create %s: limit "
+ "on number of %s variables exceeded\n",
+ dsp->ds_ident, dt_idhash_name(dhp));
+ }
+
+ dt_dprintf("declare %s %s variable %s, id=%u\n",
+ dt_idhash_name(dhp), dt_idkind_name(idkind),
+ dsp->ds_ident, id);
+
+ idp = dt_idhash_insert(dhp, dsp->ds_ident, idkind,
+ idflags | DT_IDFLG_WRITE | DT_IDFLG_DECL, id,
+ _dtrace_defattr, 0, assc ? &dt_idops_assc :
+ &dt_idops_thaw, NULL, dtp->dt_gen);
+
+ if (idp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dt_ident_type_assign(idp, dtt.dtt_ctfp, dtt.dtt_type);
+
+ /*
+ * If we are declaring an associative array, use our
+ * fake parse node to cook the new assoc identifier.
+ * This will force the ident code to instantiate the
+ * array type signature corresponding to the list of
+ * types pointed to by ddp->dd_node. We also reset
+ * the identifier's attributes based upon the result.
+ */
+ if (assc) {
+ idp->di_attr =
+ dt_ident_cook(&idn, idp, &ddp->dd_node);
+ }
+ }
+ }
+
+ } /* end of switch */
+
+ free(dsp->ds_ident);
+ dsp->ds_ident = NULL;
+
+ return (NULL);
+}
+
+dt_node_t *
+dt_node_func(dt_node_t *dnp, dt_node_t *args)
+{
+ dt_ident_t *idp;
+
+ if (dnp->dn_kind != DT_NODE_IDENT) {
+ xyerror(D_FUNC_IDENT,
+ "function designator is not of function type\n");
+ }
+
+ idp = dt_idstack_lookup(&yypcb->pcb_globals, dnp->dn_string);
+
+ if (idp == NULL) {
+ xyerror(D_FUNC_UNDEF,
+ "undefined function name: %s\n", dnp->dn_string);
+ }
+
+ if (idp->di_kind != DT_IDENT_FUNC &&
+ idp->di_kind != DT_IDENT_AGGFUNC &&
+ idp->di_kind != DT_IDENT_ACTFUNC) {
+ xyerror(D_FUNC_IDKIND, "%s '%s' may not be referenced as a "
+ "function\n", dt_idkind_name(idp->di_kind), idp->di_name);
+ }
+
+ free(dnp->dn_string);
+ dnp->dn_string = NULL;
+
+ dnp->dn_kind = DT_NODE_FUNC;
+ dnp->dn_flags &= ~DT_NF_COOKED;
+ dnp->dn_ident = idp;
+ dnp->dn_args = args;
+ dnp->dn_list = NULL;
+
+ return (dnp);
+}
+
+/*
+ * The offsetof() function is special because it takes a type name as an
+ * argument. It does not actually construct its own node; after looking up the
+ * structure or union offset, we just return an integer node with the offset.
+ */
+dt_node_t *
+dt_node_offsetof(dt_decl_t *ddp, char *s)
+{
+ dtrace_typeinfo_t dtt;
+ dt_node_t dn;
+ char *name;
+ int err;
+
+ ctf_membinfo_t ctm;
+ ctf_id_t type;
+ uint_t kind;
+
+ name = alloca(strlen(s) + 1);
+ (void) strcpy(name, s);
+ free(s);
+
+ err = dt_decl_type(ddp, &dtt);
+ dt_decl_free(ddp);
+
+ if (err != 0)
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+
+ type = ctf_type_resolve(dtt.dtt_ctfp, dtt.dtt_type);
+ kind = ctf_type_kind(dtt.dtt_ctfp, type);
+
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) {
+ xyerror(D_OFFSETOF_TYPE,
+ "offsetof operand must be a struct or union type\n");
+ }
+
+ if (ctf_member_info(dtt.dtt_ctfp, type, name, &ctm) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "failed to determine offset of %s: %s\n",
+ name, ctf_errmsg(ctf_errno(dtt.dtt_ctfp)));
+ }
+
+ bzero(&dn, sizeof (dn));
+ dt_node_type_assign(&dn, dtt.dtt_ctfp, ctm.ctm_type, B_FALSE);
+
+ if (dn.dn_flags & DT_NF_BITFIELD) {
+ xyerror(D_OFFSETOF_BITFIELD,
+ "cannot take offset of a bit-field: %s\n", name);
+ }
+
+ return (dt_node_int(ctm.ctm_offset / NBBY));
+}
+
+dt_node_t *
+dt_node_op1(int op, dt_node_t *cp)
+{
+ dt_node_t *dnp;
+
+ if (cp->dn_kind == DT_NODE_INT) {
+ switch (op) {
+ case DT_TOK_INEG:
+ /*
+ * If we're negating an unsigned integer, zero out any
+ * extra top bits to truncate the value to the size of
+ * the effective type determined by dt_node_int().
+ */
+ cp->dn_value = -cp->dn_value;
+ if (!(cp->dn_flags & DT_NF_SIGNED)) {
+ cp->dn_value &= ~0ULL >>
+ (64 - dt_node_type_size(cp) * NBBY);
+ }
+ /*FALLTHRU*/
+ case DT_TOK_IPOS:
+ return (cp);
+ case DT_TOK_BNEG:
+ cp->dn_value = ~cp->dn_value;
+ return (cp);
+ case DT_TOK_LNEG:
+ cp->dn_value = !cp->dn_value;
+ return (cp);
+ }
+ }
+
+ /*
+ * If sizeof is applied to a type_name or string constant, we can
+ * transform 'cp' into an integer constant in the node construction
+ * pass so that it can then be used for arithmetic in this pass.
+ */
+ if (op == DT_TOK_SIZEOF &&
+ (cp->dn_kind == DT_NODE_STRING || cp->dn_kind == DT_NODE_TYPE)) {
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ size_t size = dt_node_type_size(cp);
+
+ if (size == 0) {
+ xyerror(D_SIZEOF_TYPE, "cannot apply sizeof to an "
+ "operand of unknown size\n");
+ }
+
+ dt_node_type_assign(cp, dtp->dt_ddefs->dm_ctfp,
+ ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"),
+ B_FALSE);
+
+ cp->dn_kind = DT_NODE_INT;
+ cp->dn_op = DT_TOK_INT;
+ cp->dn_value = size;
+
+ return (cp);
+ }
+
+ dnp = dt_node_alloc(DT_NODE_OP1);
+ assert(op <= USHRT_MAX);
+ dnp->dn_op = (ushort_t)op;
+ dnp->dn_child = cp;
+
+ return (dnp);
+}
+
+/*
+ * If an integer constant is being cast to another integer type, we can
+ * perform the cast as part of integer constant folding in this pass. We must
+ * take action when the integer is being cast to a smaller type or if it is
+ * changing signed-ness. If so, we first shift rp's bits bits high (losing
+ * excess bits if narrowing) and then shift them down with either a logical
+ * shift (unsigned) or arithmetic shift (signed).
+ */
+static void
+dt_cast(dt_node_t *lp, dt_node_t *rp)
+{
+ size_t srcsize = dt_node_type_size(rp);
+ size_t dstsize = dt_node_type_size(lp);
+
+ if (dstsize < srcsize) {
+ int n = (sizeof (uint64_t) - dstsize) * NBBY;
+ rp->dn_value <<= n;
+ rp->dn_value >>= n;
+ } else if (dstsize > srcsize) {
+ int n = (sizeof (uint64_t) - srcsize) * NBBY;
+ int s = (dstsize - srcsize) * NBBY;
+
+ rp->dn_value <<= n;
+ if (rp->dn_flags & DT_NF_SIGNED) {
+ rp->dn_value = (intmax_t)rp->dn_value >> s;
+ rp->dn_value >>= n - s;
+ } else {
+ rp->dn_value >>= n;
+ }
+ }
+}
+
+dt_node_t *
+dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_node_t *dnp;
+
+ /*
+ * First we check for operations that are illegal -- namely those that
+ * might result in integer division by zero, and abort if one is found.
+ */
+ if (rp->dn_kind == DT_NODE_INT && rp->dn_value == 0 &&
+ (op == DT_TOK_MOD || op == DT_TOK_DIV ||
+ op == DT_TOK_MOD_EQ || op == DT_TOK_DIV_EQ))
+ xyerror(D_DIV_ZERO, "expression contains division by zero\n");
+
+ /*
+ * If both children are immediate values, we can just perform inline
+ * calculation and return a new immediate node with the result.
+ */
+ if (lp->dn_kind == DT_NODE_INT && rp->dn_kind == DT_NODE_INT) {
+ uintmax_t l = lp->dn_value;
+ uintmax_t r = rp->dn_value;
+
+ dnp = dt_node_int(0); /* allocate new integer node for result */
+
+ switch (op) {
+ case DT_TOK_LOR:
+ dnp->dn_value = l || r;
+ dt_node_type_assign(dnp,
+ DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
+ break;
+ case DT_TOK_LXOR:
+ dnp->dn_value = (l != 0) ^ (r != 0);
+ dt_node_type_assign(dnp,
+ DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
+ break;
+ case DT_TOK_LAND:
+ dnp->dn_value = l && r;
+ dt_node_type_assign(dnp,
+ DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
+ break;
+ case DT_TOK_BOR:
+ dnp->dn_value = l | r;
+ dt_node_promote(lp, rp, dnp);
+ break;
+ case DT_TOK_XOR:
+ dnp->dn_value = l ^ r;
+ dt_node_promote(lp, rp, dnp);
+ break;
+ case DT_TOK_BAND:
+ dnp->dn_value = l & r;
+ dt_node_promote(lp, rp, dnp);
+ break;
+ case DT_TOK_EQU:
+ dnp->dn_value = l == r;
+ dt_node_type_assign(dnp,
+ DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
+ break;
+ case DT_TOK_NEQ:
+ dnp->dn_value = l != r;
+ dt_node_type_assign(dnp,
+ DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
+ break;
+ case DT_TOK_LT:
+ dt_node_promote(lp, rp, dnp);
+ if (dnp->dn_flags & DT_NF_SIGNED)
+ dnp->dn_value = (intmax_t)l < (intmax_t)r;
+ else
+ dnp->dn_value = l < r;
+ dt_node_type_assign(dnp,
+ DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
+ break;
+ case DT_TOK_LE:
+ dt_node_promote(lp, rp, dnp);
+ if (dnp->dn_flags & DT_NF_SIGNED)
+ dnp->dn_value = (intmax_t)l <= (intmax_t)r;
+ else
+ dnp->dn_value = l <= r;
+ dt_node_type_assign(dnp,
+ DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
+ break;
+ case DT_TOK_GT:
+ dt_node_promote(lp, rp, dnp);
+ if (dnp->dn_flags & DT_NF_SIGNED)
+ dnp->dn_value = (intmax_t)l > (intmax_t)r;
+ else
+ dnp->dn_value = l > r;
+ dt_node_type_assign(dnp,
+ DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
+ break;
+ case DT_TOK_GE:
+ dt_node_promote(lp, rp, dnp);
+ if (dnp->dn_flags & DT_NF_SIGNED)
+ dnp->dn_value = (intmax_t)l >= (intmax_t)r;
+ else
+ dnp->dn_value = l >= r;
+ dt_node_type_assign(dnp,
+ DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
+ break;
+ case DT_TOK_LSH:
+ dnp->dn_value = l << r;
+ dt_node_type_propagate(lp, dnp);
+ dt_node_attr_assign(rp,
+ dt_attr_min(lp->dn_attr, rp->dn_attr));
+ break;
+ case DT_TOK_RSH:
+ dnp->dn_value = l >> r;
+ dt_node_type_propagate(lp, dnp);
+ dt_node_attr_assign(rp,
+ dt_attr_min(lp->dn_attr, rp->dn_attr));
+ break;
+ case DT_TOK_ADD:
+ dnp->dn_value = l + r;
+ dt_node_promote(lp, rp, dnp);
+ break;
+ case DT_TOK_SUB:
+ dnp->dn_value = l - r;
+ dt_node_promote(lp, rp, dnp);
+ break;
+ case DT_TOK_MUL:
+ dnp->dn_value = l * r;
+ dt_node_promote(lp, rp, dnp);
+ break;
+ case DT_TOK_DIV:
+ dt_node_promote(lp, rp, dnp);
+ if (dnp->dn_flags & DT_NF_SIGNED)
+ dnp->dn_value = (intmax_t)l / (intmax_t)r;
+ else
+ dnp->dn_value = l / r;
+ break;
+ case DT_TOK_MOD:
+ dt_node_promote(lp, rp, dnp);
+ if (dnp->dn_flags & DT_NF_SIGNED)
+ dnp->dn_value = (intmax_t)l % (intmax_t)r;
+ else
+ dnp->dn_value = l % r;
+ break;
+ default:
+ dt_node_free(dnp);
+ dnp = NULL;
+ }
+
+ if (dnp != NULL) {
+ dt_node_free(lp);
+ dt_node_free(rp);
+ return (dnp);
+ }
+ }
+
+ if (op == DT_TOK_LPAR && rp->dn_kind == DT_NODE_INT &&
+ dt_node_is_integer(lp)) {
+ dt_cast(lp, rp);
+ dt_node_type_propagate(lp, rp);
+ dt_node_attr_assign(rp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+ dt_node_free(lp);
+
+ return (rp);
+ }
+
+ /*
+ * If no immediate optimizations are available, create an new OP2 node
+ * and glue the left and right children into place and return.
+ */
+ dnp = dt_node_alloc(DT_NODE_OP2);
+ assert(op <= USHRT_MAX);
+ dnp->dn_op = (ushort_t)op;
+ dnp->dn_left = lp;
+ dnp->dn_right = rp;
+
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_op3(dt_node_t *expr, dt_node_t *lp, dt_node_t *rp)
+{
+ dt_node_t *dnp;
+
+ if (expr->dn_kind == DT_NODE_INT)
+ return (expr->dn_value != 0 ? lp : rp);
+
+ dnp = dt_node_alloc(DT_NODE_OP3);
+ dnp->dn_op = DT_TOK_QUESTION;
+ dnp->dn_expr = expr;
+ dnp->dn_left = lp;
+ dnp->dn_right = rp;
+
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_statement(dt_node_t *expr)
+{
+ dt_node_t *dnp;
+
+ if (expr->dn_kind == DT_NODE_AGG)
+ return (expr);
+
+ if (expr->dn_kind == DT_NODE_FUNC &&
+ expr->dn_ident->di_kind == DT_IDENT_ACTFUNC)
+ dnp = dt_node_alloc(DT_NODE_DFUNC);
+ else
+ dnp = dt_node_alloc(DT_NODE_DEXPR);
+
+ dnp->dn_expr = expr;
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_if(dt_node_t *pred, dt_node_t *acts, dt_node_t *else_acts)
+{
+ dt_node_t *dnp = dt_node_alloc(DT_NODE_IF);
+ dnp->dn_conditional = pred;
+ dnp->dn_body = acts;
+ dnp->dn_alternate_body = else_acts;
+
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_pdesc_by_name(char *spec)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_node_t *dnp;
+
+ if (spec == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dnp = dt_node_alloc(DT_NODE_PDESC);
+ dnp->dn_spec = spec;
+ dnp->dn_desc = malloc(sizeof (dtrace_probedesc_t));
+
+ if (dnp->dn_desc == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ if (dtrace_xstr2desc(dtp, yypcb->pcb_pspec, dnp->dn_spec,
+ yypcb->pcb_sargc, yypcb->pcb_sargv, dnp->dn_desc) != 0) {
+ xyerror(D_PDESC_INVAL, "invalid probe description \"%s\": %s\n",
+ dnp->dn_spec, dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ free(dnp->dn_spec);
+ dnp->dn_spec = NULL;
+
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_pdesc_by_id(uintmax_t id)
+{
+ static const char *const names[] = {
+ "providers", "modules", "functions"
+ };
+
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_node_t *dnp = dt_node_alloc(DT_NODE_PDESC);
+
+ if ((dnp->dn_desc = malloc(sizeof (dtrace_probedesc_t))) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ if (id > UINT_MAX) {
+ xyerror(D_PDESC_INVAL, "identifier %llu exceeds maximum "
+ "probe id\n", (u_longlong_t)id);
+ }
+
+ if (yypcb->pcb_pspec != DTRACE_PROBESPEC_NAME) {
+ xyerror(D_PDESC_INVAL, "probe identifier %llu not permitted "
+ "when specifying %s\n", (u_longlong_t)id,
+ names[yypcb->pcb_pspec]);
+ }
+
+ if (dtrace_id2desc(dtp, (dtrace_id_t)id, dnp->dn_desc) != 0) {
+ xyerror(D_PDESC_INVAL, "invalid probe identifier %llu: %s\n",
+ (u_longlong_t)id, dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_clause(dt_node_t *pdescs, dt_node_t *pred, dt_node_t *acts)
+{
+ dt_node_t *dnp = dt_node_alloc(DT_NODE_CLAUSE);
+
+ dnp->dn_pdescs = pdescs;
+ dnp->dn_pred = pred;
+ dnp->dn_acts = acts;
+
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_inline(dt_node_t *expr)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_scope_t *dsp = &yypcb->pcb_dstack;
+ dt_decl_t *ddp = dt_decl_top();
+
+ char n[DT_TYPE_NAMELEN];
+ dtrace_typeinfo_t dtt;
+
+ dt_ident_t *idp, *rdp;
+ dt_idnode_t *inp;
+ dt_node_t *dnp;
+
+ if (dt_decl_type(ddp, &dtt) != 0)
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+
+ if (dsp->ds_class != DT_DC_DEFAULT) {
+ xyerror(D_DECL_BADCLASS, "specified storage class not "
+ "appropriate for inline declaration\n");
+ }
+
+ if (dsp->ds_ident == NULL)
+ xyerror(D_DECL_USELESS, "inline declaration requires a name\n");
+
+ if ((idp = dt_idstack_lookup(
+ &yypcb->pcb_globals, dsp->ds_ident)) != NULL) {
+ xyerror(D_DECL_IDRED, "identifier redefined: %s\n\t current: "
+ "inline definition\n\tprevious: %s %s\n",
+ idp->di_name, dt_idkind_name(idp->di_kind),
+ (idp->di_flags & DT_IDFLG_INLINE) ? "inline" : "");
+ }
+
+ /*
+ * If we are declaring an inlined array, verify that we have a tuple
+ * signature, and then recompute 'dtt' as the array's value type.
+ */
+ if (ddp->dd_kind == CTF_K_ARRAY) {
+ if (ddp->dd_node == NULL) {
+ xyerror(D_DECL_ARRNULL, "inline declaration requires "
+ "array tuple signature: %s\n", dsp->ds_ident);
+ }
+
+ if (ddp->dd_node->dn_kind != DT_NODE_TYPE) {
+ xyerror(D_DECL_ARRNULL, "inline declaration cannot be "
+ "of scalar array type: %s\n", dsp->ds_ident);
+ }
+
+ if (dt_decl_type(ddp->dd_next, &dtt) != 0)
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+ }
+
+ /*
+ * If the inline identifier is not defined, then create it with the
+ * orphan flag set. We do not insert the identifier into dt_globals
+ * until we have successfully cooked the right-hand expression, below.
+ */
+ dnp = dt_node_alloc(DT_NODE_INLINE);
+ dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
+ dt_node_attr_assign(dnp, _dtrace_defattr);
+
+ if (dt_node_is_void(dnp)) {
+ xyerror(D_DECL_VOIDOBJ,
+ "cannot declare void inline: %s\n", dsp->ds_ident);
+ }
+
+ if (ctf_type_kind(dnp->dn_ctfp, ctf_type_resolve(
+ dnp->dn_ctfp, dnp->dn_type)) == CTF_K_FORWARD) {
+ xyerror(D_DECL_INCOMPLETE,
+ "incomplete struct/union/enum %s: %s\n",
+ dt_node_type_name(dnp, n, sizeof (n)), dsp->ds_ident);
+ }
+
+ if ((inp = malloc(sizeof (dt_idnode_t))) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ bzero(inp, sizeof (dt_idnode_t));
+
+ idp = dnp->dn_ident = dt_ident_create(dsp->ds_ident,
+ ddp->dd_kind == CTF_K_ARRAY ? DT_IDENT_ARRAY : DT_IDENT_SCALAR,
+ DT_IDFLG_INLINE | DT_IDFLG_REF | DT_IDFLG_DECL | DT_IDFLG_ORPHAN, 0,
+ _dtrace_defattr, 0, &dt_idops_inline, inp, dtp->dt_gen);
+
+ if (idp == NULL) {
+ free(inp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ /*
+ * If we're inlining an associative array, create a private identifier
+ * hash containing the named parameters and store it in inp->din_hash.
+ * We then push this hash on to the top of the pcb_globals stack.
+ */
+ if (ddp->dd_kind == CTF_K_ARRAY) {
+ dt_idnode_t *pinp;
+ dt_ident_t *pidp;
+ dt_node_t *pnp;
+ uint_t i = 0;
+
+ for (pnp = ddp->dd_node; pnp != NULL; pnp = pnp->dn_list)
+ i++; /* count up parameters for din_argv[] */
+
+ inp->din_hash = dt_idhash_create("inline args", NULL, 0, 0);
+ inp->din_argv = calloc(i, sizeof (dt_ident_t *));
+
+ if (inp->din_hash == NULL || inp->din_argv == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ /*
+ * Create an identifier for each parameter as a scalar inline,
+ * and store it in din_hash and in position in din_argv[]. The
+ * parameter identifiers also use dt_idops_inline, but we leave
+ * the dt_idnode_t argument 'pinp' zeroed. This will be filled
+ * in by the code generation pass with references to the args.
+ */
+ for (i = 0, pnp = ddp->dd_node;
+ pnp != NULL; pnp = pnp->dn_list, i++) {
+
+ if (pnp->dn_string == NULL)
+ continue; /* ignore anonymous parameters */
+
+ if ((pinp = malloc(sizeof (dt_idnode_t))) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ pidp = dt_idhash_insert(inp->din_hash, pnp->dn_string,
+ DT_IDENT_SCALAR, DT_IDFLG_DECL | DT_IDFLG_INLINE, 0,
+ _dtrace_defattr, 0, &dt_idops_inline,
+ pinp, dtp->dt_gen);
+
+ if (pidp == NULL) {
+ free(pinp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ }
+
+ inp->din_argv[i] = pidp;
+ bzero(pinp, sizeof (dt_idnode_t));
+ dt_ident_type_assign(pidp, pnp->dn_ctfp, pnp->dn_type);
+ }
+
+ dt_idstack_push(&yypcb->pcb_globals, inp->din_hash);
+ }
+
+ /*
+ * Unlike most constructors, we need to explicitly cook the right-hand
+ * side of the inline definition immediately to prevent recursion. If
+ * the right-hand side uses the inline itself, the cook will fail.
+ */
+ expr = dt_node_cook(expr, DT_IDFLG_REF);
+
+ if (ddp->dd_kind == CTF_K_ARRAY)
+ dt_idstack_pop(&yypcb->pcb_globals, inp->din_hash);
+
+ /*
+ * Set the type, attributes, and flags for the inline. If the right-
+ * hand expression has an identifier, propagate its flags. Then cook
+ * the identifier to fully initialize it: if we're declaring an inline
+ * associative array this will construct a type signature from 'ddp'.
+ */
+ if (dt_node_is_dynamic(expr))
+ rdp = dt_ident_resolve(expr->dn_ident);
+ else if (expr->dn_kind == DT_NODE_VAR || expr->dn_kind == DT_NODE_SYM)
+ rdp = expr->dn_ident;
+ else
+ rdp = NULL;
+
+ if (rdp != NULL) {
+ idp->di_flags |= (rdp->di_flags &
+ (DT_IDFLG_WRITE | DT_IDFLG_USER | DT_IDFLG_PRIM));
+ }
+
+ idp->di_attr = dt_attr_min(_dtrace_defattr, expr->dn_attr);
+ dt_ident_type_assign(idp, dtt.dtt_ctfp, dtt.dtt_type);
+ (void) dt_ident_cook(dnp, idp, &ddp->dd_node);
+
+ /*
+ * Store the parse tree nodes for 'expr' inside of idp->di_data ('inp')
+ * so that they will be preserved with this identifier. Then pop the
+ * inline declaration from the declaration stack and restore the lexer.
+ */
+ inp->din_list = yypcb->pcb_list;
+ inp->din_root = expr;
+
+ dt_decl_free(dt_decl_pop());
+ yybegin(YYS_CLAUSE);
+
+ /*
+ * Finally, insert the inline identifier into dt_globals to make it
+ * visible, and then cook 'dnp' to check its type against 'expr'.
+ */
+ dt_idhash_xinsert(dtp->dt_globals, idp);
+ return (dt_node_cook(dnp, DT_IDFLG_REF));
+}
+
+dt_node_t *
+dt_node_member(dt_decl_t *ddp, char *name, dt_node_t *expr)
+{
+ dtrace_typeinfo_t dtt;
+ dt_node_t *dnp;
+ int err;
+
+ if (ddp != NULL) {
+ err = dt_decl_type(ddp, &dtt);
+ dt_decl_free(ddp);
+
+ if (err != 0)
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+ }
+
+ dnp = dt_node_alloc(DT_NODE_MEMBER);
+ dnp->dn_membname = name;
+ dnp->dn_membexpr = expr;
+
+ if (ddp != NULL)
+ dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
+ dtt.dtt_flags);
+
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_xlator(dt_decl_t *ddp, dt_decl_t *sdp, char *name, dt_node_t *members)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dtrace_typeinfo_t src, dst;
+ dt_node_t sn, dn;
+ dt_xlator_t *dxp;
+ dt_node_t *dnp;
+ int edst, esrc;
+ uint_t kind;
+
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ edst = dt_decl_type(ddp, &dst);
+ dt_decl_free(ddp);
+
+ esrc = dt_decl_type(sdp, &src);
+ dt_decl_free(sdp);
+
+ if (edst != 0 || esrc != 0) {
+ free(name);
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+ }
+
+ bzero(&sn, sizeof (sn));
+ dt_node_type_assign(&sn, src.dtt_ctfp, src.dtt_type, B_FALSE);
+
+ bzero(&dn, sizeof (dn));
+ dt_node_type_assign(&dn, dst.dtt_ctfp, dst.dtt_type, B_FALSE);
+
+ if (dt_xlator_lookup(dtp, &sn, &dn, DT_XLATE_EXACT) != NULL) {
+ xyerror(D_XLATE_REDECL,
+ "translator from %s to %s has already been declared\n",
+ dt_node_type_name(&sn, n1, sizeof (n1)),
+ dt_node_type_name(&dn, n2, sizeof (n2)));
+ }
+
+ kind = ctf_type_kind(dst.dtt_ctfp,
+ ctf_type_resolve(dst.dtt_ctfp, dst.dtt_type));
+
+ if (kind == CTF_K_FORWARD) {
+ xyerror(D_XLATE_SOU, "incomplete struct/union/enum %s\n",
+ dt_type_name(dst.dtt_ctfp, dst.dtt_type, n1, sizeof (n1)));
+ }
+
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) {
+ xyerror(D_XLATE_SOU,
+ "translator output type must be a struct or union\n");
+ }
+
+ dxp = dt_xlator_create(dtp, &src, &dst, name, members, yypcb->pcb_list);
+ yybegin(YYS_CLAUSE);
+ free(name);
+
+ if (dxp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ dnp = dt_node_alloc(DT_NODE_XLATOR);
+ dnp->dn_xlator = dxp;
+ dnp->dn_members = members;
+
+ return (dt_node_cook(dnp, DT_IDFLG_REF));
+}
+
+dt_node_t *
+dt_node_probe(char *s, int protoc, dt_node_t *nargs, dt_node_t *xargs)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ int nargc, xargc;
+ dt_node_t *dnp;
+
+ size_t len = strlen(s) + 3; /* +3 for :: and \0 */
+ char *name = alloca(len);
+
+ (void) snprintf(name, len, "::%s", s);
+ (void) strhyphenate(name);
+ free(s);
+
+ if (strchr(name, '`') != NULL) {
+ xyerror(D_PROV_BADNAME, "probe name may not "
+ "contain scoping operator: %s\n", name);
+ }
+
+ if (strlen(name) - 2 >= DTRACE_NAMELEN) {
+ xyerror(D_PROV_BADNAME, "probe name may not exceed %d "
+ "characters: %s\n", DTRACE_NAMELEN - 1, name);
+ }
+
+ dnp = dt_node_alloc(DT_NODE_PROBE);
+
+ dnp->dn_ident = dt_ident_create(name, DT_IDENT_PROBE,
+ DT_IDFLG_ORPHAN, DTRACE_IDNONE, _dtrace_defattr, 0,
+ &dt_idops_probe, NULL, dtp->dt_gen);
+
+ nargc = dt_decl_prototype(nargs, nargs,
+ "probe input", DT_DP_VOID | DT_DP_ANON);
+
+ xargc = dt_decl_prototype(xargs, nargs,
+ "probe output", DT_DP_VOID);
+
+ if (nargc > UINT8_MAX) {
+ xyerror(D_PROV_PRARGLEN, "probe %s input prototype exceeds %u "
+ "parameters: %d params used\n", name, UINT8_MAX, nargc);
+ }
+
+ if (xargc > UINT8_MAX) {
+ xyerror(D_PROV_PRARGLEN, "probe %s output prototype exceeds %u "
+ "parameters: %d params used\n", name, UINT8_MAX, xargc);
+ }
+
+ if (dnp->dn_ident == NULL || dt_probe_create(dtp,
+ dnp->dn_ident, protoc, nargs, nargc, xargs, xargc) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_provider(char *name, dt_node_t *probes)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_node_t *dnp = dt_node_alloc(DT_NODE_PROVIDER);
+ dt_node_t *lnp;
+ size_t len;
+
+ dnp->dn_provname = name;
+ dnp->dn_probes = probes;
+
+ if (strchr(name, '`') != NULL) {
+ dnerror(dnp, D_PROV_BADNAME, "provider name may not "
+ "contain scoping operator: %s\n", name);
+ }
+
+ if ((len = strlen(name)) >= DTRACE_PROVNAMELEN) {
+ dnerror(dnp, D_PROV_BADNAME, "provider name may not exceed %d "
+ "characters: %s\n", DTRACE_PROVNAMELEN - 1, name);
+ }
+
+ if (isdigit(name[len - 1])) {
+ dnerror(dnp, D_PROV_BADNAME, "provider name may not "
+ "end with a digit: %s\n", name);
+ }
+
+ /*
+ * Check to see if the provider is already defined or visible through
+ * dtrace(7D). If so, set dn_provred to treat it as a re-declaration.
+ * If not, create a new provider and set its interface-only flag. This
+ * flag may be cleared later by calls made to dt_probe_declare().
+ */
+ if ((dnp->dn_provider = dt_provider_lookup(dtp, name)) != NULL)
+ dnp->dn_provred = B_TRUE;
+ else if ((dnp->dn_provider = dt_provider_create(dtp, name)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ else
+ dnp->dn_provider->pv_flags |= DT_PROVIDER_INTF;
+
+ /*
+ * Store all parse nodes created since we consumed the DT_KEY_PROVIDER
+ * token with the provider and then restore our lexing state to CLAUSE.
+ * Note that if dnp->dn_provred is true, we may end up storing dups of
+ * a provider's interface and implementation: we eat this space because
+ * the implementation will likely need to redeclare probe members, and
+ * therefore may result in those member nodes becoming persistent.
+ */
+ for (lnp = yypcb->pcb_list; lnp->dn_link != NULL; lnp = lnp->dn_link)
+ continue; /* skip to end of allocation list */
+
+ lnp->dn_link = dnp->dn_provider->pv_nodes;
+ dnp->dn_provider->pv_nodes = yypcb->pcb_list;
+
+ yybegin(YYS_CLAUSE);
+ return (dnp);
+}
+
+dt_node_t *
+dt_node_program(dt_node_t *lnp)
+{
+ dt_node_t *dnp = dt_node_alloc(DT_NODE_PROG);
+ dnp->dn_list = lnp;
+ return (dnp);
+}
+
+/*
+ * This function provides the underlying implementation of cooking an
+ * identifier given its node, a hash of dynamic identifiers, an identifier
+ * kind, and a boolean flag indicating whether we are allowed to instantiate
+ * a new identifier if the string is not found. This function is either
+ * called from dt_cook_ident(), below, or directly by the various cooking
+ * routines that are allowed to instantiate identifiers (e.g. op2 TOK_ASGN).
+ */
+static void
+dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ const char *sname = dt_idhash_name(dhp);
+ int uref = 0;
+
+ dtrace_attribute_t attr = _dtrace_defattr;
+ dt_ident_t *idp;
+ dtrace_syminfo_t dts;
+ GElf_Sym sym;
+
+ const char *scope, *mark;
+ uchar_t dnkind;
+ char *name;
+
+ /*
+ * Look for scoping marks in the identifier. If one is found, set our
+ * scope to either DTRACE_OBJ_KMODS or UMODS or to the first part of
+ * the string that specifies the scope using an explicit module name.
+ * If two marks in a row are found, set 'uref' (user symbol reference).
+ * Otherwise we set scope to DTRACE_OBJ_EXEC, indicating that normal
+ * scope is desired and we should search the specified idhash.
+ */
+ if ((name = strrchr(dnp->dn_string, '`')) != NULL) {
+ if (name > dnp->dn_string && name[-1] == '`') {
+ uref++;
+ name[-1] = '\0';
+ }
+
+ if (name == dnp->dn_string + uref)
+ scope = uref ? DTRACE_OBJ_UMODS : DTRACE_OBJ_KMODS;
+ else
+ scope = dnp->dn_string;
+
+ *name++ = '\0'; /* leave name pointing after scoping mark */
+ dnkind = DT_NODE_VAR;
+
+ } else if (idkind == DT_IDENT_AGG) {
+ scope = DTRACE_OBJ_EXEC;
+ name = dnp->dn_string + 1;
+ dnkind = DT_NODE_AGG;
+ } else {
+ scope = DTRACE_OBJ_EXEC;
+ name = dnp->dn_string;
+ dnkind = DT_NODE_VAR;
+ }
+
+ /*
+ * If create is set to false, and we fail our idhash lookup, preset
+ * the errno code to EDT_NOVAR for our final error message below.
+ * If we end up calling dtrace_lookup_by_name(), it will reset the
+ * errno appropriately and that error will be reported instead.
+ */
+ (void) dt_set_errno(dtp, EDT_NOVAR);
+ mark = uref ? "``" : "`";
+
+ if (scope == DTRACE_OBJ_EXEC && (
+ (dhp != dtp->dt_globals &&
+ (idp = dt_idhash_lookup(dhp, name)) != NULL) ||
+ (dhp == dtp->dt_globals &&
+ (idp = dt_idstack_lookup(&yypcb->pcb_globals, name)) != NULL))) {
+ /*
+ * Check that we are referencing the ident in the manner that
+ * matches its type if this is a global lookup. In the TLS or
+ * local case, we don't know how the ident will be used until
+ * the time operator -> is seen; more parsing is needed.
+ */
+ if (idp->di_kind != idkind && dhp == dtp->dt_globals) {
+ xyerror(D_IDENT_BADREF, "%s '%s' may not be referenced "
+ "as %s\n", dt_idkind_name(idp->di_kind),
+ idp->di_name, dt_idkind_name(idkind));
+ }
+
+ /*
+ * Arrays and aggregations are not cooked individually. They
+ * have dynamic types and must be referenced using operator [].
+ * This is handled explicitly by the code for DT_TOK_LBRAC.
+ */
+ if (idp->di_kind != DT_IDENT_ARRAY &&
+ idp->di_kind != DT_IDENT_AGG)
+ attr = dt_ident_cook(dnp, idp, NULL);
+ else {
+ dt_node_type_assign(dnp,
+ DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE);
+ attr = idp->di_attr;
+ }
+
+ free(dnp->dn_string);
+ dnp->dn_string = NULL;
+ dnp->dn_kind = dnkind;
+ dnp->dn_ident = idp;
+ dnp->dn_flags |= DT_NF_LVALUE;
+
+ if (idp->di_flags & DT_IDFLG_WRITE)
+ dnp->dn_flags |= DT_NF_WRITABLE;
+
+ dt_node_attr_assign(dnp, attr);
+
+ } else if (dhp == dtp->dt_globals && scope != DTRACE_OBJ_EXEC &&
+ dtrace_lookup_by_name(dtp, scope, name, &sym, &dts) == 0) {
+
+ dt_module_t *mp = dt_module_lookup_by_name(dtp, dts.dts_object);
+ int umod = (mp->dm_flags & DT_DM_KERNEL) == 0;
+ static const char *const kunames[] = { "kernel", "user" };
+
+ dtrace_typeinfo_t dtt;
+ dtrace_syminfo_t *sip;
+
+ if (uref ^ umod) {
+ xyerror(D_SYM_BADREF, "%s module '%s' symbol '%s' may "
+ "not be referenced as a %s symbol\n", kunames[umod],
+ dts.dts_object, dts.dts_name, kunames[uref]);
+ }
+
+ if (dtrace_symbol_type(dtp, &sym, &dts, &dtt) != 0) {
+ /*
+ * For now, we special-case EDT_DATAMODEL to clarify
+ * that mixed data models are not currently supported.
+ */
+ if (dtp->dt_errno == EDT_DATAMODEL) {
+ xyerror(D_SYM_MODEL, "cannot use %s symbol "
+ "%s%s%s in a %s D program\n",
+ dt_module_modelname(mp),
+ dts.dts_object, mark, dts.dts_name,
+ dt_module_modelname(dtp->dt_ddefs));
+ }
+
+ xyerror(D_SYM_NOTYPES,
+ "no symbolic type information is available for "
+ "%s%s%s: %s\n", dts.dts_object, mark, dts.dts_name,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+
+ idp = dt_ident_create(name, DT_IDENT_SYMBOL, 0, 0,
+ _dtrace_symattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
+
+ if (idp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ if (mp->dm_flags & DT_DM_PRIMARY)
+ idp->di_flags |= DT_IDFLG_PRIM;
+
+ idp->di_next = dtp->dt_externs;
+ dtp->dt_externs = idp;
+
+ if ((sip = malloc(sizeof (dtrace_syminfo_t))) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ bcopy(&dts, sip, sizeof (dtrace_syminfo_t));
+ idp->di_data = sip;
+ idp->di_ctfp = dtt.dtt_ctfp;
+ idp->di_type = dtt.dtt_type;
+
+ free(dnp->dn_string);
+ dnp->dn_string = NULL;
+ dnp->dn_kind = DT_NODE_SYM;
+ dnp->dn_ident = idp;
+ dnp->dn_flags |= DT_NF_LVALUE;
+
+ dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
+ dtt.dtt_flags);
+ dt_node_attr_assign(dnp, _dtrace_symattr);
+
+ if (uref) {
+ idp->di_flags |= DT_IDFLG_USER;
+ dnp->dn_flags |= DT_NF_USERLAND;
+ }
+
+ } else if (scope == DTRACE_OBJ_EXEC && create == B_TRUE) {
+ uint_t flags = DT_IDFLG_WRITE;
+ uint_t id;
+
+ if (dt_idhash_nextid(dhp, &id) == -1) {
+ xyerror(D_ID_OFLOW, "cannot create %s: limit on number "
+ "of %s variables exceeded\n", name, sname);
+ }
+
+ if (dhp == yypcb->pcb_locals)
+ flags |= DT_IDFLG_LOCAL;
+ else if (dhp == dtp->dt_tls)
+ flags |= DT_IDFLG_TLS;
+
+ dt_dprintf("create %s %s variable %s, id=%u\n",
+ sname, dt_idkind_name(idkind), name, id);
+
+ if (idkind == DT_IDENT_ARRAY || idkind == DT_IDENT_AGG) {
+ idp = dt_idhash_insert(dhp, name,
+ idkind, flags, id, _dtrace_defattr, 0,
+ &dt_idops_assc, NULL, dtp->dt_gen);
+ } else {
+ idp = dt_idhash_insert(dhp, name,
+ idkind, flags, id, _dtrace_defattr, 0,
+ &dt_idops_thaw, NULL, dtp->dt_gen);
+ }
+
+ if (idp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ /*
+ * Arrays and aggregations are not cooked individually. They
+ * have dynamic types and must be referenced using operator [].
+ * This is handled explicitly by the code for DT_TOK_LBRAC.
+ */
+ if (idp->di_kind != DT_IDENT_ARRAY &&
+ idp->di_kind != DT_IDENT_AGG)
+ attr = dt_ident_cook(dnp, idp, NULL);
+ else {
+ dt_node_type_assign(dnp,
+ DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE);
+ attr = idp->di_attr;
+ }
+
+ free(dnp->dn_string);
+ dnp->dn_string = NULL;
+ dnp->dn_kind = dnkind;
+ dnp->dn_ident = idp;
+ dnp->dn_flags |= DT_NF_LVALUE | DT_NF_WRITABLE;
+
+ dt_node_attr_assign(dnp, attr);
+
+ } else if (scope != DTRACE_OBJ_EXEC) {
+ xyerror(D_IDENT_UNDEF, "failed to resolve %s%s%s: %s\n",
+ dnp->dn_string, mark, name,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ } else {
+ xyerror(D_IDENT_UNDEF, "failed to resolve %s: %s\n",
+ dnp->dn_string, dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+}
+
+static dt_node_t *
+dt_cook_ident(dt_node_t *dnp, uint_t idflags)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+
+ if (dnp->dn_op == DT_TOK_AGG)
+ dt_xcook_ident(dnp, dtp->dt_aggs, DT_IDENT_AGG, B_FALSE);
+ else
+ dt_xcook_ident(dnp, dtp->dt_globals, DT_IDENT_SCALAR, B_FALSE);
+
+ return (dt_node_cook(dnp, idflags));
+}
+
+/*
+ * Since operators [ and -> can instantiate new variables before we know
+ * whether the reference is for a read or a write, we need to check read
+ * references to determine if the identifier is currently dt_ident_unref().
+ * If so, we report that this first access was to an undefined variable.
+ */
+static dt_node_t *
+dt_cook_var(dt_node_t *dnp, uint_t idflags)
+{
+ dt_ident_t *idp = dnp->dn_ident;
+
+ if ((idflags & DT_IDFLG_REF) && dt_ident_unref(idp)) {
+ dnerror(dnp, D_VAR_UNDEF,
+ "%s%s has not yet been declared or assigned\n",
+ (idp->di_flags & DT_IDFLG_LOCAL) ? "this->" :
+ (idp->di_flags & DT_IDFLG_TLS) ? "self->" : "",
+ idp->di_name);
+ }
+
+ dt_node_attr_assign(dnp, dt_ident_cook(dnp, idp, &dnp->dn_args));
+ return (dnp);
+}
+
+/*ARGSUSED*/
+static dt_node_t *
+dt_cook_func(dt_node_t *dnp, uint_t idflags)
+{
+ dt_node_attr_assign(dnp,
+ dt_ident_cook(dnp, dnp->dn_ident, &dnp->dn_args));
+
+ return (dnp);
+}
+
+static dt_node_t *
+dt_cook_op1(dt_node_t *dnp, uint_t idflags)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_node_t *cp = dnp->dn_child;
+
+ char n[DT_TYPE_NAMELEN];
+ dtrace_typeinfo_t dtt;
+ dt_ident_t *idp;
+
+ ctf_encoding_t e;
+ ctf_arinfo_t r;
+ ctf_id_t type, base;
+ uint_t kind;
+
+ if (dnp->dn_op == DT_TOK_PREINC || dnp->dn_op == DT_TOK_POSTINC ||
+ dnp->dn_op == DT_TOK_PREDEC || dnp->dn_op == DT_TOK_POSTDEC)
+ idflags = DT_IDFLG_REF | DT_IDFLG_MOD;
+ else
+ idflags = DT_IDFLG_REF;
+
+ /*
+ * We allow the unary ++ and -- operators to instantiate new scalar
+ * variables if applied to an identifier; otherwise just cook as usual.
+ */
+ if (cp->dn_kind == DT_NODE_IDENT && (idflags & DT_IDFLG_MOD))
+ dt_xcook_ident(cp, dtp->dt_globals, DT_IDENT_SCALAR, B_TRUE);
+
+ cp = dnp->dn_child = dt_node_cook(cp, 0); /* don't set idflags yet */
+
+ if (cp->dn_kind == DT_NODE_VAR && dt_ident_unref(cp->dn_ident)) {
+ if (dt_type_lookup("int64_t", &dtt) != 0)
+ xyerror(D_TYPE_ERR, "failed to lookup int64_t\n");
+
+ dt_ident_type_assign(cp->dn_ident, dtt.dtt_ctfp, dtt.dtt_type);
+ dt_node_type_assign(cp, dtt.dtt_ctfp, dtt.dtt_type,
+ dtt.dtt_flags);
+ }
+
+ if (cp->dn_kind == DT_NODE_VAR)
+ cp->dn_ident->di_flags |= idflags;
+
+ switch (dnp->dn_op) {
+ case DT_TOK_DEREF:
+ /*
+ * If the deref operator is applied to a translated pointer,
+ * we set our output type to the output of the translation.
+ */
+ if ((idp = dt_node_resolve(cp, DT_IDENT_XLPTR)) != NULL) {
+ dt_xlator_t *dxp = idp->di_data;
+
+ dnp->dn_ident = &dxp->dx_souid;
+ dt_node_type_assign(dnp,
+ dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type,
+ cp->dn_flags & DT_NF_USERLAND);
+ break;
+ }
+
+ type = ctf_type_resolve(cp->dn_ctfp, cp->dn_type);
+ kind = ctf_type_kind(cp->dn_ctfp, type);
+
+ if (kind == CTF_K_ARRAY) {
+ if (ctf_array_info(cp->dn_ctfp, type, &r) != 0) {
+ dtp->dt_ctferr = ctf_errno(cp->dn_ctfp);
+ longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
+ } else
+ type = r.ctr_contents;
+ } else if (kind == CTF_K_POINTER) {
+ type = ctf_type_reference(cp->dn_ctfp, type);
+ } else {
+ xyerror(D_DEREF_NONPTR,
+ "cannot dereference non-pointer type\n");
+ }
+
+ dt_node_type_assign(dnp, cp->dn_ctfp, type,
+ cp->dn_flags & DT_NF_USERLAND);
+ base = ctf_type_resolve(cp->dn_ctfp, type);
+ kind = ctf_type_kind(cp->dn_ctfp, base);
+
+ if (kind == CTF_K_INTEGER && ctf_type_encoding(cp->dn_ctfp,
+ base, &e) == 0 && IS_VOID(e)) {
+ xyerror(D_DEREF_VOID,
+ "cannot dereference pointer to void\n");
+ }
+
+ if (kind == CTF_K_FUNCTION) {
+ xyerror(D_DEREF_FUNC,
+ "cannot dereference pointer to function\n");
+ }
+
+ if (kind != CTF_K_ARRAY || dt_node_is_string(dnp))
+ dnp->dn_flags |= DT_NF_LVALUE; /* see K&R[A7.4.3] */
+
+ /*
+ * If we propagated the l-value bit and the child operand was
+ * a writable D variable or a binary operation of the form
+ * a + b where a is writable, then propagate the writable bit.
+ * This is necessary to permit assignments to scalar arrays,
+ * which are converted to expressions of the form *(a + i).
+ */
+ if ((cp->dn_flags & DT_NF_WRITABLE) ||
+ (cp->dn_kind == DT_NODE_OP2 && cp->dn_op == DT_TOK_ADD &&
+ (cp->dn_left->dn_flags & DT_NF_WRITABLE)))
+ dnp->dn_flags |= DT_NF_WRITABLE;
+
+ if ((cp->dn_flags & DT_NF_USERLAND) &&
+ (kind == CTF_K_POINTER || (dnp->dn_flags & DT_NF_REF)))
+ dnp->dn_flags |= DT_NF_USERLAND;
+ break;
+
+ case DT_TOK_IPOS:
+ case DT_TOK_INEG:
+ if (!dt_node_is_arith(cp)) {
+ xyerror(D_OP_ARITH, "operator %s requires an operand "
+ "of arithmetic type\n", opstr(dnp->dn_op));
+ }
+ dt_node_type_propagate(cp, dnp); /* see K&R[A7.4.4-6] */
+ break;
+
+ case DT_TOK_BNEG:
+ if (!dt_node_is_integer(cp)) {
+ xyerror(D_OP_INT, "operator %s requires an operand of "
+ "integral type\n", opstr(dnp->dn_op));
+ }
+ dt_node_type_propagate(cp, dnp); /* see K&R[A7.4.4-6] */
+ break;
+
+ case DT_TOK_LNEG:
+ if (!dt_node_is_scalar(cp)) {
+ xyerror(D_OP_SCALAR, "operator %s requires an operand "
+ "of scalar type\n", opstr(dnp->dn_op));
+ }
+ dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp),
+ B_FALSE);
+ break;
+
+ case DT_TOK_ADDROF:
+ if (cp->dn_kind == DT_NODE_VAR || cp->dn_kind == DT_NODE_AGG) {
+ xyerror(D_ADDROF_VAR,
+ "cannot take address of dynamic variable\n");
+ }
+
+ if (dt_node_is_dynamic(cp)) {
+ xyerror(D_ADDROF_VAR,
+ "cannot take address of dynamic object\n");
+ }
+
+ if (!(cp->dn_flags & DT_NF_LVALUE)) {
+ xyerror(D_ADDROF_LVAL, /* see K&R[A7.4.2] */
+ "unacceptable operand for unary & operator\n");
+ }
+
+ if (cp->dn_flags & DT_NF_BITFIELD) {
+ xyerror(D_ADDROF_BITFIELD,
+ "cannot take address of bit-field\n");
+ }
+
+ dtt = (dtrace_typeinfo_t){
+ .dtt_ctfp = cp->dn_ctfp,
+ .dtt_type = cp->dn_type,
+ };
+
+ if (dt_type_pointer(&dtt) == -1) {
+ xyerror(D_TYPE_ERR, "cannot find type for \"&\": %s*\n",
+ dt_node_type_name(cp, n, sizeof (n)));
+ }
+
+ dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
+ cp->dn_flags & DT_NF_USERLAND);
+ break;
+
+ case DT_TOK_SIZEOF:
+ if (cp->dn_flags & DT_NF_BITFIELD) {
+ xyerror(D_SIZEOF_BITFIELD,
+ "cannot apply sizeof to a bit-field\n");
+ }
+
+ if (dt_node_sizeof(cp) == 0) {
+ xyerror(D_SIZEOF_TYPE, "cannot apply sizeof to an "
+ "operand of unknown size\n");
+ }
+
+ dt_node_type_assign(dnp, dtp->dt_ddefs->dm_ctfp,
+ ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"),
+ B_FALSE);
+ break;
+
+ case DT_TOK_STRINGOF:
+ if (!dt_node_is_scalar(cp) && !dt_node_is_pointer(cp) &&
+ !dt_node_is_strcompat(cp)) {
+ xyerror(D_STRINGOF_TYPE,
+ "cannot apply stringof to a value of type %s\n",
+ dt_node_type_name(cp, n, sizeof (n)));
+ }
+ dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp),
+ cp->dn_flags & DT_NF_USERLAND);
+ break;
+
+ case DT_TOK_PREINC:
+ case DT_TOK_POSTINC:
+ case DT_TOK_PREDEC:
+ case DT_TOK_POSTDEC:
+ if (dt_node_is_scalar(cp) == 0) {
+ xyerror(D_OP_SCALAR, "operator %s requires operand of "
+ "scalar type\n", opstr(dnp->dn_op));
+ }
+
+ if (dt_node_is_vfptr(cp)) {
+ xyerror(D_OP_VFPTR, "operator %s requires an operand "
+ "of known size\n", opstr(dnp->dn_op));
+ }
+
+ if (!(cp->dn_flags & DT_NF_LVALUE)) {
+ xyerror(D_OP_LVAL, "operator %s requires modifiable "
+ "lvalue as an operand\n", opstr(dnp->dn_op));
+ }
+
+ if (!(cp->dn_flags & DT_NF_WRITABLE)) {
+ xyerror(D_OP_WRITE, "operator %s can only be applied "
+ "to a writable variable\n", opstr(dnp->dn_op));
+ }
+
+ dt_node_type_propagate(cp, dnp); /* see K&R[A7.4.1] */
+ break;
+
+ default:
+ xyerror(D_UNKNOWN, "invalid unary op %s\n", opstr(dnp->dn_op));
+ }
+
+ dt_node_attr_assign(dnp, cp->dn_attr);
+ return (dnp);
+}
+
+static void
+dt_assign_common(dt_node_t *dnp)
+{
+ dt_node_t *lp = dnp->dn_left;
+ dt_node_t *rp = dnp->dn_right;
+ int op = dnp->dn_op;
+
+ if (rp->dn_kind == DT_NODE_INT)
+ dt_cast(lp, rp);
+
+ if (!(lp->dn_flags & DT_NF_LVALUE)) {
+ xyerror(D_OP_LVAL, "operator %s requires modifiable "
+ "lvalue as an operand\n", opstr(op));
+ /* see K&R[A7.17] */
+ }
+
+ if (!(lp->dn_flags & DT_NF_WRITABLE)) {
+ xyerror(D_OP_WRITE, "operator %s can only be applied "
+ "to a writable variable\n", opstr(op));
+ }
+
+ dt_node_type_propagate(lp, dnp); /* see K&R[A7.17] */
+ dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+}
+
+static dt_node_t *
+dt_cook_op2(dt_node_t *dnp, uint_t idflags)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_node_t *lp = dnp->dn_left;
+ dt_node_t *rp = dnp->dn_right;
+ int op = dnp->dn_op;
+
+ ctf_membinfo_t m;
+ ctf_file_t *ctfp;
+ ctf_id_t type;
+ int kind, val, uref;
+ dt_ident_t *idp;
+
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ /*
+ * The expression E1[E2] is identical by definition to *((E1)+(E2)) so
+ * we convert "[" to "+" and glue on "*" at the end (see K&R[A7.3.1])
+ * unless the left-hand side is an untyped D scalar, associative array,
+ * or aggregation. In these cases, we proceed to case DT_TOK_LBRAC and
+ * handle associative array and aggregation references there.
+ */
+ if (op == DT_TOK_LBRAC) {
+ if (lp->dn_kind == DT_NODE_IDENT) {
+ dt_idhash_t *dhp;
+ uint_t idkind;
+
+ if (lp->dn_op == DT_TOK_AGG) {
+ dhp = dtp->dt_aggs;
+ idp = dt_idhash_lookup(dhp, lp->dn_string + 1);
+ idkind = DT_IDENT_AGG;
+ } else {
+ dhp = dtp->dt_globals;
+ idp = dt_idstack_lookup(
+ &yypcb->pcb_globals, lp->dn_string);
+ idkind = DT_IDENT_ARRAY;
+ }
+
+ if (idp == NULL || dt_ident_unref(idp))
+ dt_xcook_ident(lp, dhp, idkind, B_TRUE);
+ else
+ dt_xcook_ident(lp, dhp, idp->di_kind, B_FALSE);
+ } else {
+ lp = dnp->dn_left = dt_node_cook(lp, 0);
+ }
+
+ /*
+ * Switch op to '+' for *(E1 + E2) array mode in these cases:
+ * (a) lp is a DT_IDENT_ARRAY variable that has already been
+ * referenced using [] notation (dn_args != NULL).
+ * (b) lp is a non-ARRAY variable that has already been given
+ * a type by assignment or declaration (!dt_ident_unref())
+ * (c) lp is neither a variable nor an aggregation
+ */
+ if (lp->dn_kind == DT_NODE_VAR) {
+ if (lp->dn_ident->di_kind == DT_IDENT_ARRAY) {
+ if (lp->dn_args != NULL)
+ op = DT_TOK_ADD;
+ } else if (!dt_ident_unref(lp->dn_ident)) {
+ op = DT_TOK_ADD;
+ }
+ } else if (lp->dn_kind != DT_NODE_AGG) {
+ op = DT_TOK_ADD;
+ }
+ }
+
+ switch (op) {
+ case DT_TOK_BAND:
+ case DT_TOK_XOR:
+ case DT_TOK_BOR:
+ lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ if (!dt_node_is_integer(lp) || !dt_node_is_integer(rp)) {
+ xyerror(D_OP_INT, "operator %s requires operands of "
+ "integral type\n", opstr(op));
+ }
+
+ dt_node_promote(lp, rp, dnp); /* see K&R[A7.11-13] */
+ break;
+
+ case DT_TOK_LSH:
+ case DT_TOK_RSH:
+ lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ if (!dt_node_is_integer(lp) || !dt_node_is_integer(rp)) {
+ xyerror(D_OP_INT, "operator %s requires operands of "
+ "integral type\n", opstr(op));
+ }
+
+ dt_node_type_propagate(lp, dnp); /* see K&R[A7.8] */
+ dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+ break;
+
+ case DT_TOK_MOD:
+ lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ if (!dt_node_is_integer(lp) || !dt_node_is_integer(rp)) {
+ xyerror(D_OP_INT, "operator %s requires operands of "
+ "integral type\n", opstr(op));
+ }
+
+ dt_node_promote(lp, rp, dnp); /* see K&R[A7.6] */
+ break;
+
+ case DT_TOK_MUL:
+ case DT_TOK_DIV:
+ lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ if (!dt_node_is_arith(lp) || !dt_node_is_arith(rp)) {
+ xyerror(D_OP_ARITH, "operator %s requires operands of "
+ "arithmetic type\n", opstr(op));
+ }
+
+ dt_node_promote(lp, rp, dnp); /* see K&R[A7.6] */
+ break;
+
+ case DT_TOK_LAND:
+ case DT_TOK_LXOR:
+ case DT_TOK_LOR:
+ lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ if (!dt_node_is_scalar(lp) || !dt_node_is_scalar(rp)) {
+ xyerror(D_OP_SCALAR, "operator %s requires operands "
+ "of scalar type\n", opstr(op));
+ }
+
+ dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp),
+ B_FALSE);
+ dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+ break;
+
+ case DT_TOK_LT:
+ case DT_TOK_LE:
+ case DT_TOK_GT:
+ case DT_TOK_GE:
+ case DT_TOK_EQU:
+ case DT_TOK_NEQ:
+ /*
+ * The D comparison operators provide the ability to transform
+ * a right-hand identifier into a corresponding enum tag value
+ * if the left-hand side is an enum type. To do this, we cook
+ * the left-hand side, and then see if the right-hand side is
+ * an unscoped identifier defined in the enum. If so, we
+ * convert into an integer constant node with the tag's value.
+ */
+ lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
+
+ kind = ctf_type_kind(lp->dn_ctfp,
+ ctf_type_resolve(lp->dn_ctfp, lp->dn_type));
+
+ if (kind == CTF_K_ENUM && rp->dn_kind == DT_NODE_IDENT &&
+ strchr(rp->dn_string, '`') == NULL && ctf_enum_value(
+ lp->dn_ctfp, lp->dn_type, rp->dn_string, &val) == 0) {
+
+ if ((idp = dt_idstack_lookup(&yypcb->pcb_globals,
+ rp->dn_string)) != NULL) {
+ xyerror(D_IDENT_AMBIG,
+ "ambiguous use of operator %s: %s is "
+ "both a %s enum tag and a global %s\n",
+ opstr(op), rp->dn_string,
+ dt_node_type_name(lp, n1, sizeof (n1)),
+ dt_idkind_name(idp->di_kind));
+ }
+
+ free(rp->dn_string);
+ rp->dn_string = NULL;
+ rp->dn_kind = DT_NODE_INT;
+ rp->dn_flags |= DT_NF_COOKED;
+ rp->dn_op = DT_TOK_INT;
+ rp->dn_value = (intmax_t)val;
+
+ dt_node_type_assign(rp, lp->dn_ctfp, lp->dn_type,
+ B_FALSE);
+ dt_node_attr_assign(rp, _dtrace_symattr);
+ }
+
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ /*
+ * The rules for type checking for the relational operators are
+ * described in the ANSI-C spec (see K&R[A7.9-10]). We perform
+ * the various tests in order from least to most expensive. We
+ * also allow derived strings to be compared as a first-class
+ * type (resulting in a strcmp(3C)-style comparison), and we
+ * slightly relax the A7.9 rules to permit void pointer
+ * comparisons as in A7.10. Our users won't be confused by
+ * this since they understand pointers are just numbers, and
+ * relaxing this constraint simplifies the implementation.
+ */
+ if (ctf_type_compat(lp->dn_ctfp, lp->dn_type,
+ rp->dn_ctfp, rp->dn_type))
+ /*EMPTY*/;
+ else if (dt_node_is_integer(lp) && dt_node_is_integer(rp))
+ /*EMPTY*/;
+ else if (dt_node_is_strcompat(lp) && dt_node_is_strcompat(rp) &&
+ (dt_node_is_string(lp) || dt_node_is_string(rp)))
+ /*EMPTY*/;
+ else if (dt_node_is_ptrcompat(lp, rp, NULL, NULL) == 0) {
+ xyerror(D_OP_INCOMPAT, "operands have "
+ "incompatible types: \"%s\" %s \"%s\"\n",
+ dt_node_type_name(lp, n1, sizeof (n1)), opstr(op),
+ dt_node_type_name(rp, n2, sizeof (n2)));
+ }
+
+ dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp),
+ B_FALSE);
+ dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+ break;
+
+ case DT_TOK_ADD:
+ case DT_TOK_SUB: {
+ /*
+ * The rules for type checking for the additive operators are
+ * described in the ANSI-C spec (see K&R[A7.7]). Pointers and
+ * integers may be manipulated according to specific rules. In
+ * these cases D permits strings to be treated as pointers.
+ */
+ int lp_is_ptr, lp_is_int, rp_is_ptr, rp_is_int;
+
+ lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ lp_is_ptr = dt_node_is_string(lp) ||
+ (dt_node_is_pointer(lp) && !dt_node_is_vfptr(lp));
+ lp_is_int = dt_node_is_integer(lp);
+
+ rp_is_ptr = dt_node_is_string(rp) ||
+ (dt_node_is_pointer(rp) && !dt_node_is_vfptr(rp));
+ rp_is_int = dt_node_is_integer(rp);
+
+ if (lp_is_int && rp_is_int) {
+ dt_type_promote(lp, rp, &ctfp, &type);
+ uref = 0;
+ } else if (lp_is_ptr && rp_is_int) {
+ ctfp = lp->dn_ctfp;
+ type = lp->dn_type;
+ uref = lp->dn_flags & DT_NF_USERLAND;
+ } else if (lp_is_int && rp_is_ptr && op == DT_TOK_ADD) {
+ ctfp = rp->dn_ctfp;
+ type = rp->dn_type;
+ uref = rp->dn_flags & DT_NF_USERLAND;
+ } else if (lp_is_ptr && rp_is_ptr && op == DT_TOK_SUB &&
+ dt_node_is_ptrcompat(lp, rp, NULL, NULL)) {
+ ctfp = dtp->dt_ddefs->dm_ctfp;
+ type = ctf_lookup_by_name(ctfp, "ptrdiff_t");
+ uref = 0;
+ } else {
+ xyerror(D_OP_INCOMPAT, "operands have incompatible "
+ "types: \"%s\" %s \"%s\"\n",
+ dt_node_type_name(lp, n1, sizeof (n1)), opstr(op),
+ dt_node_type_name(rp, n2, sizeof (n2)));
+ }
+
+ dt_node_type_assign(dnp, ctfp, type, B_FALSE);
+ dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+
+ if (uref)
+ dnp->dn_flags |= DT_NF_USERLAND;
+ break;
+ }
+
+ case DT_TOK_OR_EQ:
+ case DT_TOK_XOR_EQ:
+ case DT_TOK_AND_EQ:
+ case DT_TOK_LSH_EQ:
+ case DT_TOK_RSH_EQ:
+ case DT_TOK_MOD_EQ:
+ if (lp->dn_kind == DT_NODE_IDENT) {
+ dt_xcook_ident(lp, dtp->dt_globals,
+ DT_IDENT_SCALAR, B_TRUE);
+ }
+
+ lp = dnp->dn_left =
+ dt_node_cook(lp, DT_IDFLG_REF | DT_IDFLG_MOD);
+
+ rp = dnp->dn_right =
+ dt_node_cook(rp, DT_IDFLG_REF | DT_IDFLG_MOD);
+
+ if (!dt_node_is_integer(lp) || !dt_node_is_integer(rp)) {
+ xyerror(D_OP_INT, "operator %s requires operands of "
+ "integral type\n", opstr(op));
+ }
+ goto asgn_common;
+
+ case DT_TOK_MUL_EQ:
+ case DT_TOK_DIV_EQ:
+ if (lp->dn_kind == DT_NODE_IDENT) {
+ dt_xcook_ident(lp, dtp->dt_globals,
+ DT_IDENT_SCALAR, B_TRUE);
+ }
+
+ lp = dnp->dn_left =
+ dt_node_cook(lp, DT_IDFLG_REF | DT_IDFLG_MOD);
+
+ rp = dnp->dn_right =
+ dt_node_cook(rp, DT_IDFLG_REF | DT_IDFLG_MOD);
+
+ if (!dt_node_is_arith(lp) || !dt_node_is_arith(rp)) {
+ xyerror(D_OP_ARITH, "operator %s requires operands of "
+ "arithmetic type\n", opstr(op));
+ }
+ goto asgn_common;
+
+ case DT_TOK_ASGN:
+ /*
+ * If the left-hand side is an identifier, attempt to resolve
+ * it as either an aggregation or scalar variable. We pass
+ * B_TRUE to dt_xcook_ident to indicate that a new variable can
+ * be created if no matching variable exists in the namespace.
+ */
+ if (lp->dn_kind == DT_NODE_IDENT) {
+ if (lp->dn_op == DT_TOK_AGG) {
+ dt_xcook_ident(lp, dtp->dt_aggs,
+ DT_IDENT_AGG, B_TRUE);
+ } else {
+ dt_xcook_ident(lp, dtp->dt_globals,
+ DT_IDENT_SCALAR, B_TRUE);
+ }
+ }
+
+ lp = dnp->dn_left = dt_node_cook(lp, 0); /* don't set mod yet */
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ /*
+ * If the left-hand side is an aggregation, verify that we are
+ * assigning it the result of an aggregating function. Once
+ * we've done so, hide the func node in the aggregation and
+ * return the aggregation itself up to the parse tree parent.
+ * This transformation is legal since the assigned function
+ * cannot change identity across disjoint cooking passes and
+ * the argument list subtree is retained for later cooking.
+ */
+ if (lp->dn_kind == DT_NODE_AGG) {
+ const char *aname = lp->dn_ident->di_name;
+ dt_ident_t *oid = lp->dn_ident->di_iarg;
+
+ if (rp->dn_kind != DT_NODE_FUNC ||
+ rp->dn_ident->di_kind != DT_IDENT_AGGFUNC) {
+ xyerror(D_AGG_FUNC,
+ "@%s must be assigned the result of "
+ "an aggregating function\n", aname);
+ }
+
+ if (oid != NULL && oid != rp->dn_ident) {
+ xyerror(D_AGG_REDEF,
+ "aggregation redefined: @%s\n\t "
+ "current: @%s = %s( )\n\tprevious: @%s = "
+ "%s( ) : line %d\n", aname, aname,
+ rp->dn_ident->di_name, aname, oid->di_name,
+ lp->dn_ident->di_lineno);
+ } else if (oid == NULL)
+ lp->dn_ident->di_iarg = rp->dn_ident;
+
+ /*
+ * Do not allow multiple aggregation assignments in a
+ * single statement, e.g. (@a = count()) = count();
+ * We produce a message as if the result of aggregating
+ * function does not propagate DT_NF_LVALUE.
+ */
+ if (lp->dn_aggfun != NULL) {
+ xyerror(D_OP_LVAL, "operator = requires "
+ "modifiable lvalue as an operand\n");
+ }
+
+ lp->dn_aggfun = rp;
+ lp = dt_node_cook(lp, DT_IDFLG_MOD);
+
+ dnp->dn_left = dnp->dn_right = NULL;
+ dt_node_free(dnp);
+
+ return (lp);
+ }
+
+ /*
+ * If the right-hand side is a dynamic variable that is the
+ * output of a translator, our result is the translated type.
+ */
+ if ((idp = dt_node_resolve(rp, DT_IDENT_XLSOU)) != NULL) {
+ ctfp = idp->di_ctfp;
+ type = idp->di_type;
+ uref = idp->di_flags & DT_IDFLG_USER;
+ } else {
+ ctfp = rp->dn_ctfp;
+ type = rp->dn_type;
+ uref = rp->dn_flags & DT_NF_USERLAND;
+ }
+
+ /*
+ * If the left-hand side of an assignment statement is a virgin
+ * variable created by this compilation pass, reset the type of
+ * this variable to the type of the right-hand side.
+ */
+ if (lp->dn_kind == DT_NODE_VAR &&
+ dt_ident_unref(lp->dn_ident)) {
+ dt_node_type_assign(lp, ctfp, type, B_FALSE);
+ dt_ident_type_assign(lp->dn_ident, ctfp, type);
+
+ if (uref) {
+ lp->dn_flags |= DT_NF_USERLAND;
+ lp->dn_ident->di_flags |= DT_IDFLG_USER;
+ }
+ }
+
+ if (lp->dn_kind == DT_NODE_VAR)
+ lp->dn_ident->di_flags |= DT_IDFLG_MOD;
+
+ /*
+ * The rules for type checking for the assignment operators are
+ * described in the ANSI-C spec (see K&R[A7.17]). We share
+ * most of this code with the argument list checking code.
+ */
+ if (!dt_node_is_string(lp)) {
+ kind = ctf_type_kind(lp->dn_ctfp,
+ ctf_type_resolve(lp->dn_ctfp, lp->dn_type));
+
+ if (kind == CTF_K_ARRAY || kind == CTF_K_FUNCTION) {
+ xyerror(D_OP_ARRFUN, "operator %s may not be "
+ "applied to operand of type \"%s\"\n",
+ opstr(op),
+ dt_node_type_name(lp, n1, sizeof (n1)));
+ }
+ }
+
+ if (idp != NULL && idp->di_kind == DT_IDENT_XLSOU &&
+ ctf_type_compat(lp->dn_ctfp, lp->dn_type, ctfp, type))
+ goto asgn_common;
+
+ if (dt_node_is_argcompat(lp, rp))
+ goto asgn_common;
+
+ xyerror(D_OP_INCOMPAT,
+ "operands have incompatible types: \"%s\" %s \"%s\"\n",
+ dt_node_type_name(lp, n1, sizeof (n1)), opstr(op),
+ dt_node_type_name(rp, n2, sizeof (n2)));
+ /*NOTREACHED*/
+
+ case DT_TOK_ADD_EQ:
+ case DT_TOK_SUB_EQ:
+ if (lp->dn_kind == DT_NODE_IDENT) {
+ dt_xcook_ident(lp, dtp->dt_globals,
+ DT_IDENT_SCALAR, B_TRUE);
+ }
+
+ lp = dnp->dn_left =
+ dt_node_cook(lp, DT_IDFLG_REF | DT_IDFLG_MOD);
+
+ rp = dnp->dn_right =
+ dt_node_cook(rp, DT_IDFLG_REF | DT_IDFLG_MOD);
+
+ if (dt_node_is_string(lp) || dt_node_is_string(rp)) {
+ xyerror(D_OP_INCOMPAT, "operands have "
+ "incompatible types: \"%s\" %s \"%s\"\n",
+ dt_node_type_name(lp, n1, sizeof (n1)), opstr(op),
+ dt_node_type_name(rp, n2, sizeof (n2)));
+ }
+
+ /*
+ * The rules for type checking for the assignment operators are
+ * described in the ANSI-C spec (see K&R[A7.17]). To these
+ * rules we add that only writable D nodes can be modified.
+ */
+ if (dt_node_is_integer(lp) == 0 ||
+ dt_node_is_integer(rp) == 0) {
+ if (!dt_node_is_pointer(lp) || dt_node_is_vfptr(lp)) {
+ xyerror(D_OP_VFPTR,
+ "operator %s requires left-hand scalar "
+ "operand of known size\n", opstr(op));
+ } else if (dt_node_is_integer(rp) == 0 &&
+ dt_node_is_ptrcompat(lp, rp, NULL, NULL) == 0) {
+ xyerror(D_OP_INCOMPAT, "operands have "
+ "incompatible types: \"%s\" %s \"%s\"\n",
+ dt_node_type_name(lp, n1, sizeof (n1)),
+ opstr(op),
+ dt_node_type_name(rp, n2, sizeof (n2)));
+ }
+ }
+asgn_common:
+ dt_assign_common(dnp);
+ break;
+
+ case DT_TOK_PTR:
+ /*
+ * If the left-hand side of operator -> is one of the scoping
+ * keywords, permit a local or thread variable to be created or
+ * referenced.
+ */
+ if (lp->dn_kind == DT_NODE_IDENT) {
+ dt_idhash_t *dhp = NULL;
+
+ if (strcmp(lp->dn_string, "self") == 0) {
+ dhp = dtp->dt_tls;
+ } else if (strcmp(lp->dn_string, "this") == 0) {
+ dhp = yypcb->pcb_locals;
+ }
+ if (dhp != NULL) {
+ if (rp->dn_kind != DT_NODE_VAR) {
+ dt_xcook_ident(rp, dhp,
+ DT_IDENT_SCALAR, B_TRUE);
+ }
+
+ if (idflags != 0)
+ rp = dt_node_cook(rp, idflags);
+
+ /* avoid freeing rp */
+ dnp->dn_right = dnp->dn_left;
+ dt_node_free(dnp);
+ return (rp);
+ }
+ }
+ /*FALLTHRU*/
+ case DT_TOK_DOT:
+ lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
+
+ if (rp->dn_kind != DT_NODE_IDENT) {
+ xyerror(D_OP_IDENT, "operator %s must be followed by "
+ "an identifier\n", opstr(op));
+ }
+
+ if ((idp = dt_node_resolve(lp, DT_IDENT_XLSOU)) != NULL ||
+ (idp = dt_node_resolve(lp, DT_IDENT_XLPTR)) != NULL) {
+ /*
+ * If the left-hand side is a translated struct or ptr,
+ * the type of the left is the translation output type.
+ */
+ dt_xlator_t *dxp = idp->di_data;
+
+ if (dt_xlator_member(dxp, rp->dn_string) == NULL) {
+ xyerror(D_XLATE_NOCONV,
+ "translator does not define conversion "
+ "for member: %s\n", rp->dn_string);
+ }
+
+ ctfp = idp->di_ctfp;
+ type = ctf_type_resolve(ctfp, idp->di_type);
+ uref = idp->di_flags & DT_IDFLG_USER;
+ } else {
+ ctfp = lp->dn_ctfp;
+ type = ctf_type_resolve(ctfp, lp->dn_type);
+ uref = lp->dn_flags & DT_NF_USERLAND;
+ }
+
+ kind = ctf_type_kind(ctfp, type);
+
+ if (op == DT_TOK_PTR) {
+ if (kind != CTF_K_POINTER) {
+ xyerror(D_OP_PTR, "operator %s must be "
+ "applied to a pointer\n", opstr(op));
+ }
+ type = ctf_type_reference(ctfp, type);
+ type = ctf_type_resolve(ctfp, type);
+ kind = ctf_type_kind(ctfp, type);
+ }
+
+ /*
+ * If we follow a reference to a forward declaration tag,
+ * search the entire type space for the actual definition.
+ */
+ while (kind == CTF_K_FORWARD) {
+ char *tag = ctf_type_name(ctfp, type, n1, sizeof (n1));
+ dtrace_typeinfo_t dtt;
+
+ if (tag != NULL && dt_type_lookup(tag, &dtt) == 0 &&
+ (dtt.dtt_ctfp != ctfp || dtt.dtt_type != type)) {
+ ctfp = dtt.dtt_ctfp;
+ type = ctf_type_resolve(ctfp, dtt.dtt_type);
+ kind = ctf_type_kind(ctfp, type);
+ } else {
+ xyerror(D_OP_INCOMPLETE,
+ "operator %s cannot be applied to a "
+ "forward declaration: no %s definition "
+ "is available\n", opstr(op), tag);
+ }
+ }
+
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) {
+ if (op == DT_TOK_PTR) {
+ xyerror(D_OP_SOU, "operator -> cannot be "
+ "applied to pointer to type \"%s\"; must "
+ "be applied to a struct or union pointer\n",
+ ctf_type_name(ctfp, type, n1, sizeof (n1)));
+ } else {
+ xyerror(D_OP_SOU, "operator %s cannot be "
+ "applied to type \"%s\"; must be applied "
+ "to a struct or union\n", opstr(op),
+ ctf_type_name(ctfp, type, n1, sizeof (n1)));
+ }
+ }
+
+ if (ctf_member_info(ctfp, type, rp->dn_string, &m) == CTF_ERR) {
+ xyerror(D_TYPE_MEMBER,
+ "%s is not a member of %s\n", rp->dn_string,
+ ctf_type_name(ctfp, type, n1, sizeof (n1)));
+ }
+
+ type = ctf_type_resolve(ctfp, m.ctm_type);
+ kind = ctf_type_kind(ctfp, type);
+
+ dt_node_type_assign(dnp, ctfp, m.ctm_type, B_FALSE);
+ dt_node_attr_assign(dnp, lp->dn_attr);
+
+ if (op == DT_TOK_PTR && (kind != CTF_K_ARRAY ||
+ dt_node_is_string(dnp)))
+ dnp->dn_flags |= DT_NF_LVALUE; /* see K&R[A7.3.3] */
+
+ if (op == DT_TOK_DOT && (lp->dn_flags & DT_NF_LVALUE) &&
+ (kind != CTF_K_ARRAY || dt_node_is_string(dnp)))
+ dnp->dn_flags |= DT_NF_LVALUE; /* see K&R[A7.3.3] */
+
+ if (lp->dn_flags & DT_NF_WRITABLE)
+ dnp->dn_flags |= DT_NF_WRITABLE;
+
+ if (uref && (kind == CTF_K_POINTER ||
+ (dnp->dn_flags & DT_NF_REF)))
+ dnp->dn_flags |= DT_NF_USERLAND;
+ break;
+
+ case DT_TOK_LBRAC: {
+ /*
+ * If op is DT_TOK_LBRAC, we know from the special-case code at
+ * the top that lp is either a D variable or an aggregation.
+ */
+ dt_node_t *lnp;
+
+ /*
+ * If the left-hand side is an aggregation, just set dn_aggtup
+ * to the right-hand side and return the cooked aggregation.
+ * This transformation is legal since we are just collapsing
+ * nodes to simplify later processing, and the entire aggtup
+ * parse subtree is retained for subsequent cooking passes.
+ */
+ if (lp->dn_kind == DT_NODE_AGG) {
+ if (lp->dn_aggtup != NULL) {
+ xyerror(D_AGG_MDIM, "improper attempt to "
+ "reference @%s as a multi-dimensional "
+ "array\n", lp->dn_ident->di_name);
+ }
+
+ lp->dn_aggtup = rp;
+ lp = dt_node_cook(lp, 0);
+
+ dnp->dn_left = dnp->dn_right = NULL;
+ dt_node_free(dnp);
+
+ return (lp);
+ }
+
+ assert(lp->dn_kind == DT_NODE_VAR);
+ idp = lp->dn_ident;
+
+ /*
+ * If the left-hand side is a non-global scalar that hasn't yet
+ * been referenced or modified, it was just created by self->
+ * or this-> and we can convert it from scalar to assoc array.
+ */
+ if (idp->di_kind == DT_IDENT_SCALAR && dt_ident_unref(idp) &&
+ (idp->di_flags & (DT_IDFLG_LOCAL | DT_IDFLG_TLS)) != 0) {
+
+ if (idp->di_flags & DT_IDFLG_LOCAL) {
+ xyerror(D_ARR_LOCAL,
+ "local variables may not be used as "
+ "associative arrays: %s\n", idp->di_name);
+ }
+
+ dt_dprintf("morph variable %s (id %u) from scalar to "
+ "array\n", idp->di_name, idp->di_id);
+
+ dt_ident_morph(idp, DT_IDENT_ARRAY,
+ &dt_idops_assc, NULL);
+ }
+
+ if (idp->di_kind != DT_IDENT_ARRAY) {
+ xyerror(D_IDENT_BADREF, "%s '%s' may not be referenced "
+ "as %s\n", dt_idkind_name(idp->di_kind),
+ idp->di_name, dt_idkind_name(DT_IDENT_ARRAY));
+ }
+
+ /*
+ * Now that we've confirmed our left-hand side is a DT_NODE_VAR
+ * of idkind DT_IDENT_ARRAY, we need to splice the [ node from
+ * the parse tree and leave a cooked DT_NODE_VAR in its place
+ * where dn_args for the VAR node is the right-hand 'rp' tree,
+ * as shown in the parse tree diagram below:
+ *
+ * / /
+ * [ OP2 "[" ]=dnp [ VAR ]=dnp
+ * / \ => |
+ * / \ +- dn_args -> [ ??? ]=rp
+ * [ VAR ]=lp [ ??? ]=rp
+ *
+ * Since the final dt_node_cook(dnp) can fail using longjmp we
+ * must perform the transformations as a group first by over-
+ * writing 'dnp' to become the VAR node, so that the parse tree
+ * is guaranteed to be in a consistent state if the cook fails.
+ */
+ assert(lp->dn_kind == DT_NODE_VAR);
+ assert(lp->dn_args == NULL);
+
+ lnp = dnp->dn_link;
+ bcopy(lp, dnp, sizeof (dt_node_t));
+ dnp->dn_link = lnp;
+
+ dnp->dn_args = rp;
+ dnp->dn_list = NULL;
+
+ dt_node_free(lp);
+ return (dt_node_cook(dnp, idflags));
+ }
+
+ case DT_TOK_XLATE: {
+ dt_xlator_t *dxp;
+
+ assert(lp->dn_kind == DT_NODE_TYPE);
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+ dxp = dt_xlator_lookup(dtp, rp, lp, DT_XLATE_FUZZY);
+
+ if (dxp == NULL) {
+ xyerror(D_XLATE_NONE,
+ "cannot translate from \"%s\" to \"%s\"\n",
+ dt_node_type_name(rp, n1, sizeof (n1)),
+ dt_node_type_name(lp, n2, sizeof (n2)));
+ }
+
+ dnp->dn_ident = dt_xlator_ident(dxp, lp->dn_ctfp, lp->dn_type);
+ dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp),
+ B_FALSE);
+ dt_node_attr_assign(dnp,
+ dt_attr_min(rp->dn_attr, dnp->dn_ident->di_attr));
+ break;
+ }
+
+ case DT_TOK_LPAR: {
+ ctf_id_t ltype, rtype;
+ uint_t lkind, rkind;
+
+ assert(lp->dn_kind == DT_NODE_TYPE);
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ ltype = ctf_type_resolve(lp->dn_ctfp, lp->dn_type);
+ lkind = ctf_type_kind(lp->dn_ctfp, ltype);
+
+ rtype = ctf_type_resolve(rp->dn_ctfp, rp->dn_type);
+ rkind = ctf_type_kind(rp->dn_ctfp, rtype);
+
+ /*
+ * The rules for casting are loosely explained in K&R[A7.5]
+ * and K&R[A6]. Basically, we can cast to the same type or
+ * same base type, between any kind of scalar values, from
+ * arrays to pointers, and we can cast anything to void.
+ * To these rules D adds casts from scalars to strings.
+ */
+ if (ctf_type_compat(lp->dn_ctfp, lp->dn_type,
+ rp->dn_ctfp, rp->dn_type))
+ /*EMPTY*/;
+ else if (dt_node_is_scalar(lp) &&
+ (dt_node_is_scalar(rp) || rkind == CTF_K_FUNCTION))
+ /*EMPTY*/;
+ else if (dt_node_is_void(lp))
+ /*EMPTY*/;
+ else if (lkind == CTF_K_POINTER && dt_node_is_pointer(rp))
+ /*EMPTY*/;
+ else if (dt_node_is_string(lp) && (dt_node_is_scalar(rp) ||
+ dt_node_is_pointer(rp) || dt_node_is_strcompat(rp)))
+ /*EMPTY*/;
+ else {
+ xyerror(D_CAST_INVAL,
+ "invalid cast expression: \"%s\" to \"%s\"\n",
+ dt_node_type_name(rp, n1, sizeof (n1)),
+ dt_node_type_name(lp, n2, sizeof (n2)));
+ }
+
+ dt_node_type_propagate(lp, dnp); /* see K&R[A7.5] */
+ dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+
+ /*
+ * If it's a pointer then should be able to (attempt to)
+ * assign to it.
+ */
+ if (lkind == CTF_K_POINTER)
+ dnp->dn_flags |= DT_NF_WRITABLE;
+
+ break;
+ }
+
+ case DT_TOK_COMMA:
+ lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
+ rp = dnp->dn_right = dt_node_cook(rp, DT_IDFLG_REF);
+
+ if (dt_node_is_dynamic(lp) || dt_node_is_dynamic(rp)) {
+ xyerror(D_OP_DYN, "operator %s operands "
+ "cannot be of dynamic type\n", opstr(op));
+ }
+
+ if (dt_node_is_actfunc(lp) || dt_node_is_actfunc(rp)) {
+ xyerror(D_OP_ACT, "operator %s operands "
+ "cannot be actions\n", opstr(op));
+ }
+
+ dt_node_type_propagate(rp, dnp); /* see K&R[A7.18] */
+ dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+ break;
+
+ default:
+ xyerror(D_UNKNOWN, "invalid binary op %s\n", opstr(op));
+ }
+
+ /*
+ * Complete the conversion of E1[E2] to *((E1)+(E2)) that we started
+ * at the top of our switch() above (see K&R[A7.3.1]). Since E2 is
+ * parsed as an argument_expression_list by dt_grammar.y, we can
+ * end up with a comma-separated list inside of a non-associative
+ * array reference. We check for this and report an appropriate error.
+ */
+ if (dnp->dn_op == DT_TOK_LBRAC && op == DT_TOK_ADD) {
+ dt_node_t *pnp;
+
+ if (rp->dn_list != NULL) {
+ xyerror(D_ARR_BADREF,
+ "cannot access %s as an associative array\n",
+ dt_node_name(lp, n1, sizeof (n1)));
+ }
+
+ dnp->dn_op = DT_TOK_ADD;
+ pnp = dt_node_op1(DT_TOK_DEREF, dnp);
+
+ /*
+ * Cook callbacks are not typically permitted to allocate nodes.
+ * When we do, we must insert them in the middle of an existing
+ * allocation list rather than having them appended to the pcb
+ * list because the sub-expression may be part of a definition.
+ */
+ assert(yypcb->pcb_list == pnp);
+ yypcb->pcb_list = pnp->dn_link;
+
+ pnp->dn_link = dnp->dn_link;
+ dnp->dn_link = pnp;
+
+ return (dt_node_cook(pnp, DT_IDFLG_REF));
+ }
+
+ return (dnp);
+}
+
+/*ARGSUSED*/
+static dt_node_t *
+dt_cook_op3(dt_node_t *dnp, uint_t idflags)
+{
+ dt_node_t *lp, *rp;
+ ctf_file_t *ctfp;
+ ctf_id_t type;
+
+ dnp->dn_expr = dt_node_cook(dnp->dn_expr, DT_IDFLG_REF);
+ lp = dnp->dn_left = dt_node_cook(dnp->dn_left, DT_IDFLG_REF);
+ rp = dnp->dn_right = dt_node_cook(dnp->dn_right, DT_IDFLG_REF);
+
+ if (!dt_node_is_scalar(dnp->dn_expr)) {
+ xyerror(D_OP_SCALAR,
+ "operator ?: expression must be of scalar type\n");
+ }
+
+ if (dt_node_is_dynamic(lp) || dt_node_is_dynamic(rp)) {
+ xyerror(D_OP_DYN,
+ "operator ?: operands cannot be of dynamic type\n");
+ }
+
+ /*
+ * The rules for type checking for the ternary operator are complex and
+ * are described in the ANSI-C spec (see K&R[A7.16]). We implement
+ * the various tests in order from least to most expensive.
+ */
+ if (ctf_type_compat(lp->dn_ctfp, lp->dn_type,
+ rp->dn_ctfp, rp->dn_type)) {
+ ctfp = lp->dn_ctfp;
+ type = lp->dn_type;
+ } else if (dt_node_is_integer(lp) && dt_node_is_integer(rp)) {
+ dt_type_promote(lp, rp, &ctfp, &type);
+ } else if (dt_node_is_strcompat(lp) && dt_node_is_strcompat(rp) &&
+ (dt_node_is_string(lp) || dt_node_is_string(rp))) {
+ ctfp = DT_STR_CTFP(yypcb->pcb_hdl);
+ type = DT_STR_TYPE(yypcb->pcb_hdl);
+ } else if (dt_node_is_ptrcompat(lp, rp, &ctfp, &type) == 0) {
+ xyerror(D_OP_INCOMPAT,
+ "operator ?: operands must have compatible types\n");
+ }
+
+ if (dt_node_is_actfunc(lp) || dt_node_is_actfunc(rp)) {
+ xyerror(D_OP_ACT, "action cannot be "
+ "used in a conditional context\n");
+ }
+
+ dt_node_type_assign(dnp, ctfp, type, B_FALSE);
+ dt_node_attr_assign(dnp, dt_attr_min(dnp->dn_expr->dn_attr,
+ dt_attr_min(lp->dn_attr, rp->dn_attr)));
+
+ return (dnp);
+}
+
+static dt_node_t *
+dt_cook_statement(dt_node_t *dnp, uint_t idflags)
+{
+ dnp->dn_expr = dt_node_cook(dnp->dn_expr, idflags);
+ dt_node_attr_assign(dnp, dnp->dn_expr->dn_attr);
+
+ return (dnp);
+}
+
+/*
+ * If dn_aggfun is set, this node is a collapsed aggregation assignment (see
+ * the special case code for DT_TOK_ASGN in dt_cook_op2() above), in which
+ * case we cook both the tuple and the function call. If dn_aggfun is NULL,
+ * this node is just a reference to the aggregation's type and attributes.
+ */
+/*ARGSUSED*/
+static dt_node_t *
+dt_cook_aggregation(dt_node_t *dnp, uint_t idflags)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+
+ if (dnp->dn_aggfun != NULL) {
+ dnp->dn_aggfun = dt_node_cook(dnp->dn_aggfun, DT_IDFLG_REF);
+ dt_node_attr_assign(dnp, dt_ident_cook(dnp,
+ dnp->dn_ident, &dnp->dn_aggtup));
+ } else {
+ dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp),
+ B_FALSE);
+ dt_node_attr_assign(dnp, dnp->dn_ident->di_attr);
+ }
+
+ return (dnp);
+}
+
+/*
+ * Since D permits new variable identifiers to be instantiated in any program
+ * expression, we may need to cook a clause's predicate either before or after
+ * the action list depending on the program code in question. Consider:
+ *
+ * probe-description-list probe-description-list
+ * /x++/ /x == 0/
+ * { {
+ * trace(x); trace(x++);
+ * } }
+ *
+ * In the left-hand example, the predicate uses operator ++ to instantiate 'x'
+ * as a variable of type int64_t. The predicate must be cooked first because
+ * otherwise the statement trace(x) refers to an unknown identifier. In the
+ * right-hand example, the action list uses ++ to instantiate 'x'; the action
+ * list must be cooked first because otherwise the predicate x == 0 refers to
+ * an unknown identifier. In order to simplify programming, we support both.
+ *
+ * When cooking a clause, we cook the action statements before the predicate by
+ * default, since it seems more common to create or modify identifiers in the
+ * action list. If cooking fails due to an unknown identifier, we attempt to
+ * cook the predicate (i.e. do it first) and then go back and cook the actions.
+ * If this, too, fails (or if we get an error other than D_IDENT_UNDEF) we give
+ * up and report failure back to the user. There are five possible paths:
+ *
+ * cook actions = OK, cook predicate = OK -> OK
+ * cook actions = OK, cook predicate = ERR -> ERR
+ * cook actions = ERR, cook predicate = ERR -> ERR
+ * cook actions = ERR, cook predicate = OK, cook actions = OK -> OK
+ * cook actions = ERR, cook predicate = OK, cook actions = ERR -> ERR
+ *
+ * The programmer can still defeat our scheme by creating circular definition
+ * dependencies between predicates and actions, as in this example clause:
+ *
+ * probe-description-list
+ * /x++ && y == 0/
+ * {
+ * trace(x + y++);
+ * }
+ *
+ * but it doesn't seem worth the complexity to handle such rare cases. The
+ * user can simply use the D variable declaration syntax to work around them.
+ */
+static dt_node_t *
+dt_cook_clause(dt_node_t *dnp, uint_t idflags)
+{
+ volatile int err, tries;
+ jmp_buf ojb;
+
+ /*
+ * Before assigning dn_ctxattr, temporarily assign the probe attribute
+ * to 'dnp' itself to force an attribute check and minimum violation.
+ */
+ dt_node_attr_assign(dnp, yypcb->pcb_pinfo.dtp_attr);
+ dnp->dn_ctxattr = yypcb->pcb_pinfo.dtp_attr;
+
+ bcopy(yypcb->pcb_jmpbuf, ojb, sizeof (jmp_buf));
+ tries = 0;
+
+ if (dnp->dn_pred != NULL && (err = setjmp(yypcb->pcb_jmpbuf)) != 0) {
+ bcopy(ojb, yypcb->pcb_jmpbuf, sizeof (jmp_buf));
+ if (tries++ != 0 || err != EDT_COMPILER || (
+ yypcb->pcb_hdl->dt_errtag != dt_errtag(D_IDENT_UNDEF) &&
+ yypcb->pcb_hdl->dt_errtag != dt_errtag(D_VAR_UNDEF)))
+ longjmp(yypcb->pcb_jmpbuf, err);
+ }
+
+ if (tries == 0) {
+ yylabel("action list");
+
+ dt_node_attr_assign(dnp,
+ dt_node_list_cook(&dnp->dn_acts, idflags));
+
+ bcopy(ojb, yypcb->pcb_jmpbuf, sizeof (jmp_buf));
+ yylabel(NULL);
+ }
+
+ if (dnp->dn_pred != NULL) {
+ yylabel("predicate");
+
+ dnp->dn_pred = dt_node_cook(dnp->dn_pred, idflags);
+ dt_node_attr_assign(dnp,
+ dt_attr_min(dnp->dn_attr, dnp->dn_pred->dn_attr));
+
+ if (!dt_node_is_scalar(dnp->dn_pred)) {
+ xyerror(D_PRED_SCALAR,
+ "predicate result must be of scalar type\n");
+ }
+
+ yylabel(NULL);
+ }
+
+ if (tries != 0) {
+ yylabel("action list");
+
+ dt_node_attr_assign(dnp,
+ dt_node_list_cook(&dnp->dn_acts, idflags));
+
+ yylabel(NULL);
+ }
+
+ return (dnp);
+}
+
+/*ARGSUSED*/
+static dt_node_t *
+dt_cook_inline(dt_node_t *dnp, uint_t idflags)
+{
+ dt_idnode_t *inp = dnp->dn_ident->di_iarg;
+ dt_ident_t *rdp;
+
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ assert(dnp->dn_ident->di_flags & DT_IDFLG_INLINE);
+ assert(inp->din_root->dn_flags & DT_NF_COOKED);
+
+ /*
+ * If we are inlining a translation, verify that the inline declaration
+ * type exactly matches the type that is returned by the translation.
+ * Otherwise just use dt_node_is_argcompat() to check the types.
+ */
+ if ((rdp = dt_node_resolve(inp->din_root, DT_IDENT_XLSOU)) != NULL ||
+ (rdp = dt_node_resolve(inp->din_root, DT_IDENT_XLPTR)) != NULL) {
+
+ ctf_file_t *lctfp = dnp->dn_ctfp;
+ ctf_id_t ltype = ctf_type_resolve(lctfp, dnp->dn_type);
+
+ dt_xlator_t *dxp = rdp->di_data;
+ ctf_file_t *rctfp = dxp->dx_dst_ctfp;
+ ctf_id_t rtype = dxp->dx_dst_base;
+
+ if (ctf_type_kind(lctfp, ltype) == CTF_K_POINTER) {
+ ltype = ctf_type_reference(lctfp, ltype);
+ ltype = ctf_type_resolve(lctfp, ltype);
+ }
+
+ if (ctf_type_compat(lctfp, ltype, rctfp, rtype) == 0) {
+ dnerror(dnp, D_OP_INCOMPAT,
+ "inline %s definition uses incompatible types: "
+ "\"%s\" = \"%s\"\n", dnp->dn_ident->di_name,
+ dt_type_name(lctfp, ltype, n1, sizeof (n1)),
+ dt_type_name(rctfp, rtype, n2, sizeof (n2)));
+ }
+
+ } else if (dt_node_is_argcompat(dnp, inp->din_root) == 0) {
+ dnerror(dnp, D_OP_INCOMPAT,
+ "inline %s definition uses incompatible types: "
+ "\"%s\" = \"%s\"\n", dnp->dn_ident->di_name,
+ dt_node_type_name(dnp, n1, sizeof (n1)),
+ dt_node_type_name(inp->din_root, n2, sizeof (n2)));
+ }
+
+ return (dnp);
+}
+
+static dt_node_t *
+dt_cook_member(dt_node_t *dnp, uint_t idflags)
+{
+ dnp->dn_membexpr = dt_node_cook(dnp->dn_membexpr, idflags);
+ dt_node_attr_assign(dnp, dnp->dn_membexpr->dn_attr);
+ return (dnp);
+}
+
+/*ARGSUSED*/
+static dt_node_t *
+dt_cook_xlator(dt_node_t *dnp, uint_t idflags)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_xlator_t *dxp = dnp->dn_xlator;
+ dt_node_t *mnp;
+
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ dtrace_attribute_t attr = _dtrace_maxattr;
+ ctf_membinfo_t ctm;
+
+ /*
+ * Before cooking each translator member, we push a reference to the
+ * hash containing translator-local identifiers on to pcb_globals to
+ * temporarily interpose these identifiers in front of other globals.
+ */
+ dt_idstack_push(&yypcb->pcb_globals, dxp->dx_locals);
+
+ for (mnp = dnp->dn_members; mnp != NULL; mnp = mnp->dn_list) {
+ if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_type,
+ mnp->dn_membname, &ctm) == CTF_ERR) {
+ xyerror(D_XLATE_MEMB,
+ "translator member %s is not a member of %s\n",
+ mnp->dn_membname, ctf_type_name(dxp->dx_dst_ctfp,
+ dxp->dx_dst_type, n1, sizeof (n1)));
+ }
+
+ (void) dt_node_cook(mnp, DT_IDFLG_REF);
+ dt_node_type_assign(mnp, dxp->dx_dst_ctfp, ctm.ctm_type,
+ B_FALSE);
+ attr = dt_attr_min(attr, mnp->dn_attr);
+
+ if (dt_node_is_argcompat(mnp, mnp->dn_membexpr) == 0) {
+ xyerror(D_XLATE_INCOMPAT,
+ "translator member %s definition uses "
+ "incompatible types: \"%s\" = \"%s\"\n",
+ mnp->dn_membname,
+ dt_node_type_name(mnp, n1, sizeof (n1)),
+ dt_node_type_name(mnp->dn_membexpr,
+ n2, sizeof (n2)));
+ }
+ }
+
+ dt_idstack_pop(&yypcb->pcb_globals, dxp->dx_locals);
+
+ dxp->dx_souid.di_attr = attr;
+ dxp->dx_ptrid.di_attr = attr;
+
+ dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE);
+ dt_node_attr_assign(dnp, _dtrace_defattr);
+
+ return (dnp);
+}
+
+static void
+dt_node_provider_cmp_argv(dt_provider_t *pvp, dt_node_t *pnp, const char *kind,
+ uint_t old_argc, dt_node_t *old_argv, uint_t new_argc, dt_node_t *new_argv)
+{
+ dt_probe_t *prp = pnp->dn_ident->di_data;
+ uint_t i;
+
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ if (old_argc != new_argc) {
+ dnerror(pnp, D_PROV_INCOMPAT,
+ "probe %s:%s %s prototype mismatch:\n"
+ "\t current: %u arg%s\n\tprevious: %u arg%s\n",
+ pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, kind,
+ new_argc, new_argc != 1 ? "s" : "",
+ old_argc, old_argc != 1 ? "s" : "");
+ }
+
+ for (i = 0; i < old_argc; i++,
+ old_argv = old_argv->dn_list, new_argv = new_argv->dn_list) {
+ if (ctf_type_cmp(old_argv->dn_ctfp, old_argv->dn_type,
+ new_argv->dn_ctfp, new_argv->dn_type) == 0)
+ continue;
+
+ dnerror(pnp, D_PROV_INCOMPAT,
+ "probe %s:%s %s prototype argument #%u mismatch:\n"
+ "\t current: %s\n\tprevious: %s\n",
+ pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, kind, i + 1,
+ dt_node_type_name(new_argv, n1, sizeof (n1)),
+ dt_node_type_name(old_argv, n2, sizeof (n2)));
+ }
+}
+
+/*
+ * Compare a new probe declaration with an existing probe definition (either
+ * from a previous declaration or cached from the kernel). If the existing
+ * definition and declaration both have an input and output parameter list,
+ * compare both lists. Otherwise compare only the output parameter lists.
+ */
+static void
+dt_node_provider_cmp(dt_provider_t *pvp, dt_node_t *pnp,
+ dt_probe_t *old, dt_probe_t *new)
+{
+ dt_node_provider_cmp_argv(pvp, pnp, "output",
+ old->pr_xargc, old->pr_xargs, new->pr_xargc, new->pr_xargs);
+
+ if (old->pr_nargs != old->pr_xargs && new->pr_nargs != new->pr_xargs) {
+ dt_node_provider_cmp_argv(pvp, pnp, "input",
+ old->pr_nargc, old->pr_nargs, new->pr_nargc, new->pr_nargs);
+ }
+
+ if (old->pr_nargs == old->pr_xargs && new->pr_nargs != new->pr_xargs) {
+ if (pvp->pv_flags & DT_PROVIDER_IMPL) {
+ dnerror(pnp, D_PROV_INCOMPAT,
+ "provider interface mismatch: %s\n"
+ "\t current: probe %s:%s has an output prototype\n"
+ "\tprevious: probe %s:%s has no output prototype\n",
+ pvp->pv_desc.dtvd_name, pvp->pv_desc.dtvd_name,
+ new->pr_ident->di_name, pvp->pv_desc.dtvd_name,
+ old->pr_ident->di_name);
+ }
+
+ if (old->pr_ident->di_gen == yypcb->pcb_hdl->dt_gen)
+ old->pr_ident->di_flags |= DT_IDFLG_ORPHAN;
+
+ dt_idhash_delete(pvp->pv_probes, old->pr_ident);
+ dt_probe_declare(pvp, new);
+ }
+}
+
+static void
+dt_cook_probe(dt_node_t *dnp, dt_provider_t *pvp)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_probe_t *prp = dnp->dn_ident->di_data;
+
+ dt_xlator_t *dxp;
+ uint_t i;
+
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ if (prp->pr_nargs == prp->pr_xargs)
+ return;
+
+ for (i = 0; i < prp->pr_xargc; i++) {
+ dt_node_t *xnp = prp->pr_xargv[i];
+ dt_node_t *nnp = prp->pr_nargv[prp->pr_mapping[i]];
+
+ if ((dxp = dt_xlator_lookup(dtp,
+ nnp, xnp, DT_XLATE_FUZZY)) != NULL) {
+ if (dt_provider_xref(dtp, pvp, dxp->dx_id) != 0)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ continue;
+ }
+
+ if (dt_node_is_argcompat(nnp, xnp))
+ continue; /* no translator defined and none required */
+
+ dnerror(dnp, D_PROV_PRXLATOR, "translator for %s:%s output "
+ "argument #%u from %s to %s is not defined\n",
+ pvp->pv_desc.dtvd_name, dnp->dn_ident->di_name, i + 1,
+ dt_node_type_name(nnp, n1, sizeof (n1)),
+ dt_node_type_name(xnp, n2, sizeof (n2)));
+ }
+}
+
+/*ARGSUSED*/
+static dt_node_t *
+dt_cook_provider(dt_node_t *dnp, uint_t idflags)
+{
+ dt_provider_t *pvp = dnp->dn_provider;
+ dt_node_t *pnp;
+
+ /*
+ * If we're declaring a provider for the first time and it is unknown
+ * to dtrace(7D), insert the probe definitions into the provider's hash.
+ * If we're redeclaring a known provider, verify the interface matches.
+ */
+ for (pnp = dnp->dn_probes; pnp != NULL; pnp = pnp->dn_list) {
+ const char *probename = pnp->dn_ident->di_name;
+ dt_probe_t *prp = dt_probe_lookup(pvp, probename);
+
+ assert(pnp->dn_kind == DT_NODE_PROBE);
+
+ if (prp != NULL && dnp->dn_provred) {
+ dt_node_provider_cmp(pvp, pnp,
+ prp, pnp->dn_ident->di_data);
+ } else if (prp == NULL && dnp->dn_provred) {
+ dnerror(pnp, D_PROV_INCOMPAT,
+ "provider interface mismatch: %s\n"
+ "\t current: probe %s:%s defined\n"
+ "\tprevious: probe %s:%s not defined\n",
+ dnp->dn_provname, dnp->dn_provname,
+ probename, dnp->dn_provname, probename);
+ } else if (prp != NULL) {
+ dnerror(pnp, D_PROV_PRDUP, "probe redeclared: %s:%s\n",
+ dnp->dn_provname, probename);
+ } else
+ dt_probe_declare(pvp, pnp->dn_ident->di_data);
+
+ dt_cook_probe(pnp, pvp);
+ }
+
+ return (dnp);
+}
+
+/*ARGSUSED*/
+static dt_node_t *
+dt_cook_none(dt_node_t *dnp, uint_t idflags)
+{
+ return (dnp);
+}
+
+static dt_node_t *(*dt_cook_funcs[])(dt_node_t *, uint_t) = {
+ dt_cook_none, /* DT_NODE_FREE */
+ dt_cook_none, /* DT_NODE_INT */
+ dt_cook_none, /* DT_NODE_STRING */
+ dt_cook_ident, /* DT_NODE_IDENT */
+ dt_cook_var, /* DT_NODE_VAR */
+ dt_cook_none, /* DT_NODE_SYM */
+ dt_cook_none, /* DT_NODE_TYPE */
+ dt_cook_func, /* DT_NODE_FUNC */
+ dt_cook_op1, /* DT_NODE_OP1 */
+ dt_cook_op2, /* DT_NODE_OP2 */
+ dt_cook_op3, /* DT_NODE_OP3 */
+ dt_cook_statement, /* DT_NODE_DEXPR */
+ dt_cook_statement, /* DT_NODE_DFUNC */
+ dt_cook_aggregation, /* DT_NODE_AGG */
+ dt_cook_none, /* DT_NODE_PDESC */
+ dt_cook_clause, /* DT_NODE_CLAUSE */
+ dt_cook_inline, /* DT_NODE_INLINE */
+ dt_cook_member, /* DT_NODE_MEMBER */
+ dt_cook_xlator, /* DT_NODE_XLATOR */
+ dt_cook_none, /* DT_NODE_PROBE */
+ dt_cook_provider, /* DT_NODE_PROVIDER */
+ dt_cook_none, /* DT_NODE_PROG */
+ dt_cook_none, /* DT_NODE_IF */
+};
+
+/*
+ * Recursively cook the parse tree starting at the specified node. The idflags
+ * parameter is used to indicate the type of reference (r/w) and is applied to
+ * the resulting identifier if it is a D variable or D aggregation.
+ */
+dt_node_t *
+dt_node_cook(dt_node_t *dnp, uint_t idflags)
+{
+ int oldlineno = yylineno;
+
+ yylineno = dnp->dn_line;
+
+ assert(dnp->dn_kind <
+ sizeof (dt_cook_funcs) / sizeof (dt_cook_funcs[0]));
+ dnp = dt_cook_funcs[dnp->dn_kind](dnp, idflags);
+ dnp->dn_flags |= DT_NF_COOKED;
+
+ if (dnp->dn_kind == DT_NODE_VAR || dnp->dn_kind == DT_NODE_AGG)
+ dnp->dn_ident->di_flags |= idflags;
+
+ yylineno = oldlineno;
+ return (dnp);
+}
+
+dtrace_attribute_t
+dt_node_list_cook(dt_node_t **pnp, uint_t idflags)
+{
+ dtrace_attribute_t attr = _dtrace_defattr;
+ dt_node_t *dnp, *nnp;
+
+ for (dnp = (pnp != NULL ? *pnp : NULL); dnp != NULL; dnp = nnp) {
+ nnp = dnp->dn_list;
+ dnp = *pnp = dt_node_cook(dnp, idflags);
+ attr = dt_attr_min(attr, dnp->dn_attr);
+ dnp->dn_list = nnp;
+ pnp = &dnp->dn_list;
+ }
+
+ return (attr);
+}
+
+void
+dt_node_list_free(dt_node_t **pnp)
+{
+ dt_node_t *dnp, *nnp;
+
+ for (dnp = (pnp != NULL ? *pnp : NULL); dnp != NULL; dnp = nnp) {
+ nnp = dnp->dn_list;
+ dt_node_free(dnp);
+ }
+
+ if (pnp != NULL)
+ *pnp = NULL;
+}
+
+void
+dt_node_link_free(dt_node_t **pnp)
+{
+ dt_node_t *dnp, *nnp;
+
+ for (dnp = (pnp != NULL ? *pnp : NULL); dnp != NULL; dnp = nnp) {
+ nnp = dnp->dn_link;
+ dt_node_free(dnp);
+ }
+
+ for (dnp = (pnp != NULL ? *pnp : NULL); dnp != NULL; dnp = nnp) {
+ nnp = dnp->dn_link;
+ free(dnp);
+ }
+
+ if (pnp != NULL)
+ *pnp = NULL;
+}
+
+dt_node_t *
+dt_node_link(dt_node_t *lp, dt_node_t *rp)
+{
+ dt_node_t *dnp;
+
+ if (lp == NULL)
+ return (rp);
+ else if (rp == NULL)
+ return (lp);
+
+ for (dnp = lp; dnp->dn_list != NULL; dnp = dnp->dn_list)
+ continue;
+
+ dnp->dn_list = rp;
+ return (lp);
+}
+
+/*
+ * Compute the DOF dtrace_diftype_t representation of a node's type. This is
+ * called from a variety of places in the library so it cannot assume yypcb
+ * is valid: any references to handle-specific data must be made through 'dtp'.
+ */
+void
+dt_node_diftype(dtrace_hdl_t *dtp, const dt_node_t *dnp, dtrace_diftype_t *tp)
+{
+ if (dnp->dn_ctfp == DT_STR_CTFP(dtp) &&
+ dnp->dn_type == DT_STR_TYPE(dtp)) {
+ tp->dtdt_kind = DIF_TYPE_STRING;
+ tp->dtdt_ckind = CTF_K_UNKNOWN;
+ } else {
+ tp->dtdt_kind = DIF_TYPE_CTF;
+ tp->dtdt_ckind = ctf_type_kind(dnp->dn_ctfp,
+ ctf_type_resolve(dnp->dn_ctfp, dnp->dn_type));
+ }
+
+ tp->dtdt_flags = (dnp->dn_flags & DT_NF_REF) ?
+ (dnp->dn_flags & DT_NF_USERLAND) ? DIF_TF_BYUREF :
+ DIF_TF_BYREF : 0;
+ tp->dtdt_pad = 0;
+ tp->dtdt_size = ctf_type_size(dnp->dn_ctfp, dnp->dn_type);
+}
+
+/*
+ * Output the parse tree as D. The "-xtree=8" argument will call this
+ * function to print out the program after any syntactic sugar
+ * transformations have been applied (e.g. to implement "if"). The
+ * resulting output can be used to understand the transformations
+ * applied by these features, or to run such a script on a system that
+ * does not support these features
+ *
+ * Note that the output does not express precisely the same program as
+ * the input. In particular:
+ * - Only the clauses are output. #pragma options, variable
+ * declarations, etc. are excluded.
+ * - Command argument substitution has already been done, so the output
+ * will not contain e.g. $$1, but rather the substituted string.
+ */
+void
+dt_printd(dt_node_t *dnp, FILE *fp, int depth)
+{
+ dt_node_t *arg;
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_INT:
+ (void) fprintf(fp, "0x%llx", (u_longlong_t)dnp->dn_value);
+ if (!(dnp->dn_flags & DT_NF_SIGNED))
+ (void) fprintf(fp, "u");
+ break;
+
+ case DT_NODE_STRING: {
+ char *escd = strchr2esc(dnp->dn_string, strlen(dnp->dn_string));
+ (void) fprintf(fp, "\"%s\"", escd);
+ free(escd);
+ break;
+ }
+
+ case DT_NODE_IDENT:
+ (void) fprintf(fp, "%s", dnp->dn_string);
+ break;
+
+ case DT_NODE_VAR:
+ (void) fprintf(fp, "%s%s",
+ (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL) ? "this->" :
+ (dnp->dn_ident->di_flags & DT_IDFLG_TLS) ? "self->" : "",
+ dnp->dn_ident->di_name);
+
+ if (dnp->dn_args != NULL) {
+ (void) fprintf(fp, "[");
+
+ for (arg = dnp->dn_args; arg != NULL;
+ arg = arg->dn_list) {
+ dt_printd(arg, fp, 0);
+ if (arg->dn_list != NULL)
+ (void) fprintf(fp, ", ");
+ }
+
+ (void) fprintf(fp, "]");
+ }
+ break;
+
+ case DT_NODE_SYM: {
+ const dtrace_syminfo_t *dts = dnp->dn_ident->di_data;
+ (void) fprintf(fp, "%s`%s", dts->dts_object, dts->dts_name);
+ break;
+ }
+ case DT_NODE_FUNC:
+ (void) fprintf(fp, "%s(", dnp->dn_ident->di_name);
+
+ for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list) {
+ dt_printd(arg, fp, 0);
+ if (arg->dn_list != NULL)
+ (void) fprintf(fp, ", ");
+ }
+ (void) fprintf(fp, ")");
+ break;
+
+ case DT_NODE_OP1:
+ (void) fprintf(fp, "%s(", opstr(dnp->dn_op));
+ dt_printd(dnp->dn_child, fp, 0);
+ (void) fprintf(fp, ")");
+ break;
+
+ case DT_NODE_OP2:
+ (void) fprintf(fp, "(");
+ dt_printd(dnp->dn_left, fp, 0);
+ if (dnp->dn_op == DT_TOK_LPAR) {
+ (void) fprintf(fp, ")");
+ dt_printd(dnp->dn_right, fp, 0);
+ break;
+ }
+ if (dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT ||
+ dnp->dn_op == DT_TOK_LBRAC)
+ (void) fprintf(fp, "%s", opstr(dnp->dn_op));
+ else
+ (void) fprintf(fp, " %s ", opstr(dnp->dn_op));
+ dt_printd(dnp->dn_right, fp, 0);
+ if (dnp->dn_op == DT_TOK_LBRAC) {
+ dt_node_t *ln = dnp->dn_right;
+ while (ln->dn_list != NULL) {
+ (void) fprintf(fp, ", ");
+ dt_printd(ln->dn_list, fp, depth);
+ ln = ln->dn_list;
+ }
+ (void) fprintf(fp, "]");
+ }
+ (void) fprintf(fp, ")");
+ break;
+
+ case DT_NODE_OP3:
+ (void) fprintf(fp, "(");
+ dt_printd(dnp->dn_expr, fp, 0);
+ (void) fprintf(fp, " ? ");
+ dt_printd(dnp->dn_left, fp, 0);
+ (void) fprintf(fp, " : ");
+ dt_printd(dnp->dn_right, fp, 0);
+ (void) fprintf(fp, ")");
+ break;
+
+ case DT_NODE_DEXPR:
+ case DT_NODE_DFUNC:
+ (void) fprintf(fp, "%*s", depth * 8, "");
+ dt_printd(dnp->dn_expr, fp, depth + 1);
+ (void) fprintf(fp, ";\n");
+ break;
+
+ case DT_NODE_PDESC:
+ (void) fprintf(fp, "%s:%s:%s:%s",
+ dnp->dn_desc->dtpd_provider, dnp->dn_desc->dtpd_mod,
+ dnp->dn_desc->dtpd_func, dnp->dn_desc->dtpd_name);
+ break;
+
+ case DT_NODE_CLAUSE:
+ for (arg = dnp->dn_pdescs; arg != NULL; arg = arg->dn_list) {
+ dt_printd(arg, fp, 0);
+ if (arg->dn_list != NULL)
+ (void) fprintf(fp, ",");
+ (void) fprintf(fp, "\n");
+ }
+
+ if (dnp->dn_pred != NULL) {
+ (void) fprintf(fp, "/");
+ dt_printd(dnp->dn_pred, fp, 0);
+ (void) fprintf(fp, "/\n");
+ }
+ (void) fprintf(fp, "{\n");
+
+ for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list)
+ dt_printd(arg, fp, depth + 1);
+ (void) fprintf(fp, "}\n");
+ (void) fprintf(fp, "\n");
+ break;
+
+ case DT_NODE_IF:
+ (void) fprintf(fp, "%*sif (", depth * 8, "");
+ dt_printd(dnp->dn_conditional, fp, 0);
+ (void) fprintf(fp, ") {\n");
+
+ for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list)
+ dt_printd(arg, fp, depth + 1);
+ if (dnp->dn_alternate_body == NULL) {
+ (void) fprintf(fp, "%*s}\n", depth * 8, "");
+ } else {
+ (void) fprintf(fp, "%*s} else {\n", depth * 8, "");
+ for (arg = dnp->dn_alternate_body; arg != NULL;
+ arg = arg->dn_list)
+ dt_printd(arg, fp, depth + 1);
+ (void) fprintf(fp, "%*s}\n", depth * 8, "");
+ }
+
+ break;
+
+ default:
+ (void) fprintf(fp, "/* bad node %p, kind %d */\n",
+ (void *)dnp, dnp->dn_kind);
+ }
+}
+
+void
+dt_node_printr(dt_node_t *dnp, FILE *fp, int depth)
+{
+ char n[DT_TYPE_NAMELEN], buf[BUFSIZ], a[8];
+ const dtrace_syminfo_t *dts;
+ const dt_idnode_t *inp;
+ dt_node_t *arg;
+
+ (void) fprintf(fp, "%*s", depth * 2, "");
+ (void) dt_attr_str(dnp->dn_attr, a, sizeof (a));
+
+ if (dnp->dn_ctfp != NULL && dnp->dn_type != CTF_ERR &&
+ ctf_type_name(dnp->dn_ctfp, dnp->dn_type, n, sizeof (n)) != NULL) {
+ (void) snprintf(buf, BUFSIZ, "type=<%s> attr=%s flags=", n, a);
+ } else {
+ (void) snprintf(buf, BUFSIZ, "type=<%ld> attr=%s flags=",
+ dnp->dn_type, a);
+ }
+
+ if (dnp->dn_flags != 0) {
+ n[0] = '\0';
+ if (dnp->dn_flags & DT_NF_SIGNED)
+ (void) strcat(n, ",SIGN");
+ if (dnp->dn_flags & DT_NF_COOKED)
+ (void) strcat(n, ",COOK");
+ if (dnp->dn_flags & DT_NF_REF)
+ (void) strcat(n, ",REF");
+ if (dnp->dn_flags & DT_NF_LVALUE)
+ (void) strcat(n, ",LVAL");
+ if (dnp->dn_flags & DT_NF_WRITABLE)
+ (void) strcat(n, ",WRITE");
+ if (dnp->dn_flags & DT_NF_BITFIELD)
+ (void) strcat(n, ",BITF");
+ if (dnp->dn_flags & DT_NF_USERLAND)
+ (void) strcat(n, ",USER");
+ (void) strcat(buf, n + 1);
+ } else
+ (void) strcat(buf, "0");
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_FREE:
+ (void) fprintf(fp, "FREE <node %p>\n", (void *)dnp);
+ break;
+
+ case DT_NODE_INT:
+ (void) fprintf(fp, "INT 0x%llx (%s)\n",
+ (u_longlong_t)dnp->dn_value, buf);
+ break;
+
+ case DT_NODE_STRING:
+ (void) fprintf(fp, "STRING \"%s\" (%s)\n", dnp->dn_string, buf);
+ break;
+
+ case DT_NODE_IDENT:
+ (void) fprintf(fp, "IDENT %s (%s)\n", dnp->dn_string, buf);
+ break;
+
+ case DT_NODE_VAR:
+ (void) fprintf(fp, "VARIABLE %s%s (%s)\n",
+ (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL) ? "this->" :
+ (dnp->dn_ident->di_flags & DT_IDFLG_TLS) ? "self->" : "",
+ dnp->dn_ident->di_name, buf);
+
+ if (dnp->dn_args != NULL)
+ (void) fprintf(fp, "%*s[\n", depth * 2, "");
+
+ for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list) {
+ dt_node_printr(arg, fp, depth + 1);
+ if (arg->dn_list != NULL)
+ (void) fprintf(fp, "%*s,\n", depth * 2, "");
+ }
+
+ if (dnp->dn_args != NULL)
+ (void) fprintf(fp, "%*s]\n", depth * 2, "");
+ break;
+
+ case DT_NODE_SYM:
+ dts = dnp->dn_ident->di_data;
+ (void) fprintf(fp, "SYMBOL %s`%s (%s)\n",
+ dts->dts_object, dts->dts_name, buf);
+ break;
+
+ case DT_NODE_TYPE:
+ if (dnp->dn_string != NULL) {
+ (void) fprintf(fp, "TYPE (%s) %s\n",
+ buf, dnp->dn_string);
+ } else
+ (void) fprintf(fp, "TYPE (%s)\n", buf);
+ break;
+
+ case DT_NODE_FUNC:
+ (void) fprintf(fp, "FUNC %s (%s)\n",
+ dnp->dn_ident->di_name, buf);
+
+ for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list) {
+ dt_node_printr(arg, fp, depth + 1);
+ if (arg->dn_list != NULL)
+ (void) fprintf(fp, "%*s,\n", depth * 2, "");
+ }
+ break;
+
+ case DT_NODE_OP1:
+ (void) fprintf(fp, "OP1 %s (%s)\n", opstr(dnp->dn_op), buf);
+ dt_node_printr(dnp->dn_child, fp, depth + 1);
+ break;
+
+ case DT_NODE_OP2:
+ (void) fprintf(fp, "OP2 %s (%s)\n", opstr(dnp->dn_op), buf);
+ dt_node_printr(dnp->dn_left, fp, depth + 1);
+ dt_node_printr(dnp->dn_right, fp, depth + 1);
+ if (dnp->dn_op == DT_TOK_LBRAC) {
+ dt_node_t *ln = dnp->dn_right;
+ while (ln->dn_list != NULL) {
+ dt_node_printr(ln->dn_list, fp, depth + 1);
+ ln = ln->dn_list;
+ }
+ }
+ break;
+
+ case DT_NODE_OP3:
+ (void) fprintf(fp, "OP3 (%s)\n", buf);
+ dt_node_printr(dnp->dn_expr, fp, depth + 1);
+ (void) fprintf(fp, "%*s?\n", depth * 2, "");
+ dt_node_printr(dnp->dn_left, fp, depth + 1);
+ (void) fprintf(fp, "%*s:\n", depth * 2, "");
+ dt_node_printr(dnp->dn_right, fp, depth + 1);
+ break;
+
+ case DT_NODE_DEXPR:
+ case DT_NODE_DFUNC:
+ (void) fprintf(fp, "D EXPRESSION attr=%s\n", a);
+ dt_node_printr(dnp->dn_expr, fp, depth + 1);
+ break;
+
+ case DT_NODE_AGG:
+ (void) fprintf(fp, "AGGREGATE @%s attr=%s [\n",
+ dnp->dn_ident->di_name, a);
+
+ for (arg = dnp->dn_aggtup; arg != NULL; arg = arg->dn_list) {
+ dt_node_printr(arg, fp, depth + 1);
+ if (arg->dn_list != NULL)
+ (void) fprintf(fp, "%*s,\n", depth * 2, "");
+ }
+
+ if (dnp->dn_aggfun) {
+ (void) fprintf(fp, "%*s] = ", depth * 2, "");
+ dt_node_printr(dnp->dn_aggfun, fp, depth + 1);
+ } else
+ (void) fprintf(fp, "%*s]\n", depth * 2, "");
+
+ if (dnp->dn_aggfun)
+ (void) fprintf(fp, "%*s)\n", depth * 2, "");
+ break;
+
+ case DT_NODE_PDESC:
+ (void) fprintf(fp, "PDESC %s:%s:%s:%s [%u]\n",
+ dnp->dn_desc->dtpd_provider, dnp->dn_desc->dtpd_mod,
+ dnp->dn_desc->dtpd_func, dnp->dn_desc->dtpd_name,
+ dnp->dn_desc->dtpd_id);
+ break;
+
+ case DT_NODE_CLAUSE:
+ (void) fprintf(fp, "CLAUSE attr=%s\n", a);
+
+ for (arg = dnp->dn_pdescs; arg != NULL; arg = arg->dn_list)
+ dt_node_printr(arg, fp, depth + 1);
+
+ (void) fprintf(fp, "%*sCTXATTR %s\n", depth * 2, "",
+ dt_attr_str(dnp->dn_ctxattr, a, sizeof (a)));
+
+ if (dnp->dn_pred != NULL) {
+ (void) fprintf(fp, "%*sPREDICATE /\n", depth * 2, "");
+ dt_node_printr(dnp->dn_pred, fp, depth + 1);
+ (void) fprintf(fp, "%*s/\n", depth * 2, "");
+ }
+
+ for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list)
+ dt_node_printr(arg, fp, depth + 1);
+ (void) fprintf(fp, "\n");
+ break;
+
+ case DT_NODE_INLINE:
+ inp = dnp->dn_ident->di_iarg;
+
+ (void) fprintf(fp, "INLINE %s (%s)\n",
+ dnp->dn_ident->di_name, buf);
+ dt_node_printr(inp->din_root, fp, depth + 1);
+ break;
+
+ case DT_NODE_MEMBER:
+ (void) fprintf(fp, "MEMBER %s (%s)\n", dnp->dn_membname, buf);
+ if (dnp->dn_membexpr)
+ dt_node_printr(dnp->dn_membexpr, fp, depth + 1);
+ break;
+
+ case DT_NODE_XLATOR:
+ (void) fprintf(fp, "XLATOR (%s)", buf);
+
+ if (ctf_type_name(dnp->dn_xlator->dx_src_ctfp,
+ dnp->dn_xlator->dx_src_type, n, sizeof (n)) != NULL)
+ (void) fprintf(fp, " from <%s>", n);
+
+ if (ctf_type_name(dnp->dn_xlator->dx_dst_ctfp,
+ dnp->dn_xlator->dx_dst_type, n, sizeof (n)) != NULL)
+ (void) fprintf(fp, " to <%s>", n);
+
+ (void) fprintf(fp, "\n");
+
+ for (arg = dnp->dn_members; arg != NULL; arg = arg->dn_list)
+ dt_node_printr(arg, fp, depth + 1);
+ break;
+
+ case DT_NODE_PROBE:
+ (void) fprintf(fp, "PROBE %s\n", dnp->dn_ident->di_name);
+ break;
+
+ case DT_NODE_PROVIDER:
+ (void) fprintf(fp, "PROVIDER %s (%s)\n",
+ dnp->dn_provname, dnp->dn_provred ? "redecl" : "decl");
+ for (arg = dnp->dn_probes; arg != NULL; arg = arg->dn_list)
+ dt_node_printr(arg, fp, depth + 1);
+ break;
+
+ case DT_NODE_PROG:
+ (void) fprintf(fp, "PROGRAM attr=%s\n", a);
+ for (arg = dnp->dn_list; arg != NULL; arg = arg->dn_list)
+ dt_node_printr(arg, fp, depth + 1);
+ break;
+
+ case DT_NODE_IF:
+ (void) fprintf(fp, "IF attr=%s CONDITION:\n", a);
+
+ dt_node_printr(dnp->dn_conditional, fp, depth + 1);
+
+ (void) fprintf(fp, "%*sIF BODY: \n", depth * 2, "");
+ for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list)
+ dt_node_printr(arg, fp, depth + 1);
+
+ if (dnp->dn_alternate_body != NULL) {
+ (void) fprintf(fp, "%*sIF ELSE: \n", depth * 2, "");
+ for (arg = dnp->dn_alternate_body; arg != NULL;
+ arg = arg->dn_list)
+ dt_node_printr(arg, fp, depth + 1);
+ }
+
+ break;
+
+ default:
+ (void) fprintf(fp, "<bad node %p, kind %d>\n",
+ (void *)dnp, dnp->dn_kind);
+ }
+}
+
+int
+dt_node_root(dt_node_t *dnp)
+{
+ yypcb->pcb_root = dnp;
+ return (0);
+}
+
+/*PRINTFLIKE3*/
+void
+dnerror(const dt_node_t *dnp, dt_errtag_t tag, const char *format, ...)
+{
+ int oldlineno = yylineno;
+ va_list ap;
+
+ yylineno = dnp->dn_line;
+
+ va_start(ap, format);
+ xyvwarn(tag, format, ap);
+ va_end(ap);
+
+ yylineno = oldlineno;
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+}
+
+/*PRINTFLIKE3*/
+void
+dnwarn(const dt_node_t *dnp, dt_errtag_t tag, const char *format, ...)
+{
+ int oldlineno = yylineno;
+ va_list ap;
+
+ yylineno = dnp->dn_line;
+
+ va_start(ap, format);
+ xyvwarn(tag, format, ap);
+ va_end(ap);
+
+ yylineno = oldlineno;
+}
+
+/*PRINTFLIKE2*/
+void
+xyerror(dt_errtag_t tag, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ xyvwarn(tag, format, ap);
+ va_end(ap);
+
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+}
+
+/*PRINTFLIKE2*/
+void
+xywarn(dt_errtag_t tag, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ xyvwarn(tag, format, ap);
+ va_end(ap);
+}
+
+void
+xyvwarn(dt_errtag_t tag, const char *format, va_list ap)
+{
+ if (yypcb == NULL)
+ return; /* compiler is not currently active: act as a no-op */
+
+ dt_set_errmsg(yypcb->pcb_hdl, dt_errtag(tag), yypcb->pcb_region,
+ yypcb->pcb_filetag, yypcb->pcb_fileptr ? yylineno : 0, format, ap);
+}
+
+/*PRINTFLIKE1*/
+void
+yyerror(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ yyvwarn(format, ap);
+ va_end(ap);
+
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+}
+
+/*PRINTFLIKE1*/
+void
+yywarn(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ yyvwarn(format, ap);
+ va_end(ap);
+}
+
+void
+yyvwarn(const char *format, va_list ap)
+{
+ if (yypcb == NULL)
+ return; /* compiler is not currently active: act as a no-op */
+
+ dt_set_errmsg(yypcb->pcb_hdl, dt_errtag(D_SYNTAX), yypcb->pcb_region,
+ yypcb->pcb_filetag, yypcb->pcb_fileptr ? yylineno : 0, format, ap);
+
+ if (strchr(format, '\n') == NULL) {
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ size_t len = strlen(dtp->dt_errmsg);
+ char *p, *s = dtp->dt_errmsg + len;
+ size_t n = sizeof (dtp->dt_errmsg) - len;
+
+ if (yytext[0] == '\0')
+ (void) snprintf(s, n, " near end of input");
+ else if (yytext[0] == '\n')
+ (void) snprintf(s, n, " near end of line");
+ else {
+ if ((p = strchr(yytext, '\n')) != NULL)
+ *p = '\0'; /* crop at newline */
+ (void) snprintf(s, n, " near \"%s\"", yytext);
+ }
+ }
+}
+
+void
+yylabel(const char *label)
+{
+ dt_dprintf("set label to <%s>\n", label ? label : "NULL");
+ yypcb->pcb_region = label;
+}
+
+int
+yywrap(void)
+{
+ return (1); /* indicate that lex should return a zero token for EOF */
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
new file mode 100644
index 000000000000..3a146c5d2592
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
@@ -0,0 +1,301 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _DT_PARSER_H
+#define _DT_PARSER_H
+
+#include <sys/types.h>
+#include <sys/dtrace.h>
+
+#include <libctf.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dt_errtags.h>
+#include <dt_ident.h>
+#include <dt_decl.h>
+#include <dt_xlator.h>
+#include <dt_list.h>
+
+typedef struct dt_node {
+ ctf_file_t *dn_ctfp; /* CTF type container for node's type */
+ ctf_id_t dn_type; /* CTF type reference for node's type */
+ uchar_t dn_kind; /* node kind (DT_NODE_*, defined below) */
+ uchar_t dn_flags; /* node flags (DT_NF_*, defined below) */
+ ushort_t dn_op; /* operator (DT_TOK_*, defined by lex) */
+ int dn_line; /* line number for error messages */
+ int dn_reg; /* register allocated by cg */
+ dtrace_attribute_t dn_attr; /* node stability attributes */
+
+ /*
+ * D compiler nodes, as is the usual style, contain a union of the
+ * different sub-elements required by the various kinds of nodes.
+ * These sub-elements are accessed using the macros defined below.
+ */
+ union {
+ struct {
+ uintmax_t _value; /* integer value */
+ char *_string; /* string value */
+ } _const;
+
+ struct {
+ dt_ident_t *_ident; /* identifier reference */
+ struct dt_node *_links[3]; /* child node pointers */
+ } _nodes;
+
+ struct {
+ struct dt_node *_descs; /* list of descriptions */
+ struct dt_node *_pred; /* predicate expression */
+ struct dt_node *_acts; /* action statement list */
+ dt_idhash_t *_locals; /* local variable hash */
+ dtrace_attribute_t _attr; /* context attributes */
+ } _clause;
+
+ struct {
+ char *_spec; /* specifier string (if any) */
+ dtrace_probedesc_t *_desc; /* final probe description */
+ } _pdesc;
+
+ struct {
+ char *_name; /* string name of member */
+ struct dt_node *_expr; /* expression node pointer */
+ dt_xlator_t *_xlator; /* translator reference */
+ uint_t _id; /* member identifier */
+ } _member;
+
+ struct {
+ dt_xlator_t *_xlator; /* translator reference */
+ struct dt_node *_xmemb; /* individual xlator member */
+ struct dt_node *_membs; /* list of member nodes */
+ } _xlator;
+
+ struct {
+ char *_name; /* string name of provider */
+ struct dt_provider *_pvp; /* provider references */
+ struct dt_node *_probes; /* list of probe nodes */
+ int _redecl; /* provider redeclared */
+ } _provider;
+
+ struct {
+ struct dt_node *_conditional;
+ struct dt_node *_body;
+ struct dt_node *_alternate_body;
+ } _conditional;
+ } dn_u;
+
+ struct dt_node *dn_list; /* parse tree list link */
+ struct dt_node *dn_link; /* allocation list link */
+} dt_node_t;
+
+#define dn_value dn_u._const._value /* DT_NODE_INT */
+#define dn_string dn_u._const._string /* STRING, IDENT, TYPE */
+#define dn_ident dn_u._nodes._ident /* VAR,SYM,FUN,AGG,INL,PROBE */
+#define dn_args dn_u._nodes._links[0] /* DT_NODE_VAR, FUNC */
+#define dn_child dn_u._nodes._links[0] /* DT_NODE_OP1 */
+#define dn_left dn_u._nodes._links[0] /* DT_NODE_OP2, OP3 */
+#define dn_right dn_u._nodes._links[1] /* DT_NODE_OP2, OP3 */
+#define dn_expr dn_u._nodes._links[2] /* DT_NODE_OP3, DEXPR */
+#define dn_aggfun dn_u._nodes._links[0] /* DT_NODE_AGG */
+#define dn_aggtup dn_u._nodes._links[1] /* DT_NODE_AGG */
+#define dn_pdescs dn_u._clause._descs /* DT_NODE_CLAUSE */
+#define dn_pred dn_u._clause._pred /* DT_NODE_CLAUSE */
+#define dn_acts dn_u._clause._acts /* DT_NODE_CLAUSE */
+#define dn_locals dn_u._clause._locals /* DT_NODE_CLAUSE */
+#define dn_ctxattr dn_u._clause._attr /* DT_NODE_CLAUSE */
+#define dn_spec dn_u._pdesc._spec /* DT_NODE_PDESC */
+#define dn_desc dn_u._pdesc._desc /* DT_NODE_PDESC */
+#define dn_membname dn_u._member._name /* DT_NODE_MEMBER */
+#define dn_membexpr dn_u._member._expr /* DT_NODE_MEMBER */
+#define dn_membxlator dn_u._member._xlator /* DT_NODE_MEMBER */
+#define dn_membid dn_u._member._id /* DT_NODE_MEMBER */
+#define dn_xlator dn_u._xlator._xlator /* DT_NODE_XLATOR */
+#define dn_xmember dn_u._xlator._xmemb /* DT_NODE_XLATOR */
+#define dn_members dn_u._xlator._membs /* DT_NODE_XLATOR */
+#define dn_provname dn_u._provider._name /* DT_NODE_PROVIDER */
+#define dn_provider dn_u._provider._pvp /* DT_NODE_PROVIDER */
+#define dn_provred dn_u._provider._redecl /* DT_NODE_PROVIDER */
+#define dn_probes dn_u._provider._probes /* DT_NODE_PROVIDER */
+
+/* DT_NODE_IF: */
+#define dn_conditional dn_u._conditional._conditional
+#define dn_body dn_u._conditional._body
+#define dn_alternate_body dn_u._conditional._alternate_body
+
+#define DT_NODE_FREE 0 /* unused node (waiting to be freed) */
+#define DT_NODE_INT 1 /* integer value */
+#define DT_NODE_STRING 2 /* string value */
+#define DT_NODE_IDENT 3 /* identifier */
+#define DT_NODE_VAR 4 /* variable reference */
+#define DT_NODE_SYM 5 /* symbol reference */
+#define DT_NODE_TYPE 6 /* type reference or formal parameter */
+#define DT_NODE_FUNC 7 /* function call */
+#define DT_NODE_OP1 8 /* unary operator */
+#define DT_NODE_OP2 9 /* binary operator */
+#define DT_NODE_OP3 10 /* ternary operator */
+#define DT_NODE_DEXPR 11 /* D expression action */
+#define DT_NODE_DFUNC 12 /* D function action */
+#define DT_NODE_AGG 13 /* aggregation */
+#define DT_NODE_PDESC 14 /* probe description */
+#define DT_NODE_CLAUSE 15 /* clause definition */
+#define DT_NODE_INLINE 16 /* inline definition */
+#define DT_NODE_MEMBER 17 /* member definition */
+#define DT_NODE_XLATOR 18 /* translator definition */
+#define DT_NODE_PROBE 19 /* probe definition */
+#define DT_NODE_PROVIDER 20 /* provider definition */
+#define DT_NODE_PROG 21 /* program translation unit */
+#define DT_NODE_IF 22 /* if statement */
+
+#define DT_NF_SIGNED 0x01 /* data is a signed quantity (else unsigned) */
+#define DT_NF_COOKED 0x02 /* data is a known type (else still cooking) */
+#define DT_NF_REF 0x04 /* pass by reference (array, struct, union) */
+#define DT_NF_LVALUE 0x08 /* node is an l-value according to ANSI-C */
+#define DT_NF_WRITABLE 0x10 /* node is writable (can be modified) */
+#define DT_NF_BITFIELD 0x20 /* node is an integer bitfield */
+#define DT_NF_USERLAND 0x40 /* data is a userland address */
+
+#define DT_TYPE_NAMELEN 128 /* reasonable size for ctf_type_name() */
+
+extern int dt_node_is_integer(const dt_node_t *);
+extern int dt_node_is_float(const dt_node_t *);
+extern int dt_node_is_scalar(const dt_node_t *);
+extern int dt_node_is_arith(const dt_node_t *);
+extern int dt_node_is_vfptr(const dt_node_t *);
+extern int dt_node_is_dynamic(const dt_node_t *);
+extern int dt_node_is_stack(const dt_node_t *);
+extern int dt_node_is_symaddr(const dt_node_t *);
+extern int dt_node_is_usymaddr(const dt_node_t *);
+extern int dt_node_is_string(const dt_node_t *);
+extern int dt_node_is_strcompat(const dt_node_t *);
+extern int dt_node_is_pointer(const dt_node_t *);
+extern int dt_node_is_void(const dt_node_t *);
+extern int dt_node_is_ptrcompat(const dt_node_t *, const dt_node_t *,
+ ctf_file_t **, ctf_id_t *);
+extern int dt_node_is_argcompat(const dt_node_t *, const dt_node_t *);
+extern int dt_node_is_posconst(const dt_node_t *);
+extern int dt_node_is_actfunc(const dt_node_t *);
+
+extern dt_node_t *dt_node_int(uintmax_t);
+extern dt_node_t *dt_node_string(char *);
+extern dt_node_t *dt_node_ident(char *);
+extern dt_node_t *dt_node_type(dt_decl_t *);
+extern dt_node_t *dt_node_vatype(void);
+extern dt_node_t *dt_node_decl(void);
+extern dt_node_t *dt_node_func(dt_node_t *, dt_node_t *);
+extern dt_node_t *dt_node_offsetof(dt_decl_t *, char *);
+extern dt_node_t *dt_node_op1(int, dt_node_t *);
+extern dt_node_t *dt_node_op2(int, dt_node_t *, dt_node_t *);
+extern dt_node_t *dt_node_op3(dt_node_t *, dt_node_t *, dt_node_t *);
+extern dt_node_t *dt_node_statement(dt_node_t *);
+extern dt_node_t *dt_node_pdesc_by_name(char *);
+extern dt_node_t *dt_node_pdesc_by_id(uintmax_t);
+extern dt_node_t *dt_node_clause(dt_node_t *, dt_node_t *, dt_node_t *);
+extern dt_node_t *dt_node_inline(dt_node_t *);
+extern dt_node_t *dt_node_member(dt_decl_t *, char *, dt_node_t *);
+extern dt_node_t *dt_node_xlator(dt_decl_t *, dt_decl_t *, char *, dt_node_t *);
+extern dt_node_t *dt_node_probe(char *, int, dt_node_t *, dt_node_t *);
+extern dt_node_t *dt_node_provider(char *, dt_node_t *);
+extern dt_node_t *dt_node_program(dt_node_t *);
+extern dt_node_t *dt_node_if(dt_node_t *, dt_node_t *, dt_node_t *);
+
+extern dt_node_t *dt_node_link(dt_node_t *, dt_node_t *);
+extern dt_node_t *dt_node_cook(dt_node_t *, uint_t);
+
+extern dt_node_t *dt_node_xalloc(dtrace_hdl_t *, int);
+extern void dt_node_free(dt_node_t *);
+
+extern dtrace_attribute_t dt_node_list_cook(dt_node_t **, uint_t);
+extern void dt_node_list_free(dt_node_t **);
+extern void dt_node_link_free(dt_node_t **);
+
+extern void dt_node_attr_assign(dt_node_t *, dtrace_attribute_t);
+extern void dt_node_type_assign(dt_node_t *, ctf_file_t *, ctf_id_t, boolean_t);
+extern void dt_node_type_propagate(const dt_node_t *, dt_node_t *);
+extern const char *dt_node_type_name(const dt_node_t *, char *, size_t);
+extern size_t dt_node_type_size(const dt_node_t *);
+
+extern dt_ident_t *dt_node_resolve(const dt_node_t *, uint_t);
+extern size_t dt_node_sizeof(const dt_node_t *);
+extern void dt_node_promote(dt_node_t *, dt_node_t *, dt_node_t *);
+
+extern void dt_node_diftype(dtrace_hdl_t *,
+ const dt_node_t *, dtrace_diftype_t *);
+extern void dt_node_printr(dt_node_t *, FILE *, int);
+extern void dt_printd(dt_node_t *, FILE *, int);
+extern const char *dt_node_name(const dt_node_t *, char *, size_t);
+extern int dt_node_root(dt_node_t *);
+
+struct dtrace_typeinfo; /* see <dtrace.h> */
+struct dt_pcb; /* see <dt_impl.h> */
+
+#define IS_CHAR(e) \
+ (((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
+ (CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
+
+#define IS_VOID(e) \
+ ((e).cte_offset == 0 && (e).cte_bits == 0)
+
+extern int dt_type_lookup(const char *, struct dtrace_typeinfo *);
+extern int dt_type_pointer(struct dtrace_typeinfo *);
+extern const char *dt_type_name(ctf_file_t *, ctf_id_t, char *, size_t);
+
+typedef enum {
+ YYS_CLAUSE, /* lex/yacc state for finding program clauses */
+ YYS_DEFINE, /* lex/yacc state for parsing persistent definitions */
+ YYS_EXPR, /* lex/yacc state for parsing D expressions */
+ YYS_DONE, /* lex/yacc state for indicating parse tree is done */
+ YYS_CONTROL /* lex/yacc state for parsing control lines */
+} yystate_t;
+
+extern void dnerror(const dt_node_t *, dt_errtag_t, const char *, ...);
+extern void dnwarn(const dt_node_t *, dt_errtag_t, const char *, ...);
+
+extern void xyerror(dt_errtag_t, const char *, ...);
+extern void xywarn(dt_errtag_t, const char *, ...);
+extern void xyvwarn(dt_errtag_t, const char *, va_list);
+
+extern void yyerror(const char *, ...);
+extern void yywarn(const char *, ...);
+extern void yyvwarn(const char *, va_list);
+
+extern void yylabel(const char *);
+extern void yybegin(yystate_t);
+extern void yyinit(struct dt_pcb *);
+
+extern int yyparse(void);
+extern int yyinput(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_PARSER_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.c
new file mode 100644
index 000000000000..d80c359bc15a
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.c
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * DTrace Parsing Control Block
+ *
+ * A DTrace Parsing Control Block (PCB) contains all of the state that is used
+ * by a single pass of the D compiler, other than the global variables used by
+ * lex and yacc. The routines in this file are used to set up and tear down
+ * PCBs, which are kept on a stack pointed to by the libdtrace global 'yypcb'.
+ * The main engine of the compiler, dt_compile(), is located in dt_cc.c and is
+ * responsible for calling these routines to begin and end a compilation pass.
+ *
+ * Sun's lex/yacc are not MT-safe or re-entrant, but we permit limited nested
+ * use of dt_compile() once the entire parse tree has been constructed but has
+ * not yet executed the "cooking" pass (see dt_cc.c for more information). The
+ * PCB design also makes it easier to debug (since all global state is kept in
+ * one place) and could permit us to make the D compiler MT-safe or re-entrant
+ * in the future by adding locks to libdtrace or switching to Flex and Bison.
+ */
+
+#include <strings.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <dt_impl.h>
+#include <dt_program.h>
+#include <dt_provider.h>
+#include <dt_pcb.h>
+
+/*
+ * Initialize the specified PCB by zeroing it and filling in a few default
+ * members, and then pushing it on to the top of the PCB stack and setting
+ * yypcb to point to it. Increment the current handle's generation count.
+ */
+void
+dt_pcb_push(dtrace_hdl_t *dtp, dt_pcb_t *pcb)
+{
+ /*
+ * Since lex/yacc are not re-entrant and we don't implement state save,
+ * assert that if another PCB is active, it is from the same handle and
+ * has completed execution of yyparse(). If the first assertion fires,
+ * the caller is calling libdtrace without proper MT locking. If the
+ * second assertion fires, dt_compile() is being called recursively
+ * from an illegal location in libdtrace, or a dt_pcb_pop() is missing.
+ */
+ if (yypcb != NULL) {
+ assert(yypcb->pcb_hdl == dtp);
+ assert(yypcb->pcb_yystate == YYS_DONE);
+ }
+
+ bzero(pcb, sizeof (dt_pcb_t));
+
+ dt_scope_create(&pcb->pcb_dstack);
+ dt_idstack_push(&pcb->pcb_globals, dtp->dt_globals);
+ dt_irlist_create(&pcb->pcb_ir);
+
+ pcb->pcb_hdl = dtp;
+ pcb->pcb_prev = dtp->dt_pcb;
+
+ dtp->dt_pcb = pcb;
+ dtp->dt_gen++;
+
+ yyinit(pcb);
+}
+
+static int
+dt_pcb_pop_ident(dt_idhash_t *dhp, dt_ident_t *idp, void *arg)
+{
+ dtrace_hdl_t *dtp = arg;
+
+ if (idp->di_gen == dtp->dt_gen)
+ dt_idhash_delete(dhp, idp);
+
+ return (0);
+}
+
+/*
+ * Pop the topmost PCB from the PCB stack and destroy any data structures that
+ * are associated with it. If 'err' is non-zero, destroy any intermediate
+ * state that is left behind as part of a compilation that has failed.
+ */
+void
+dt_pcb_pop(dtrace_hdl_t *dtp, int err)
+{
+ dt_pcb_t *pcb = yypcb;
+ uint_t i;
+
+ assert(pcb != NULL);
+ assert(pcb == dtp->dt_pcb);
+
+ while (pcb->pcb_dstack.ds_next != NULL)
+ (void) dt_scope_pop();
+
+ dt_scope_destroy(&pcb->pcb_dstack);
+ dt_irlist_destroy(&pcb->pcb_ir);
+
+ dt_node_link_free(&pcb->pcb_list);
+ dt_node_link_free(&pcb->pcb_hold);
+
+ if (err != 0) {
+ dt_xlator_t *dxp, *nxp;
+ dt_provider_t *pvp, *nvp;
+
+ if (pcb->pcb_prog != NULL)
+ dt_program_destroy(dtp, pcb->pcb_prog);
+ if (pcb->pcb_stmt != NULL)
+ dtrace_stmt_destroy(dtp, pcb->pcb_stmt);
+ if (pcb->pcb_ecbdesc != NULL)
+ dt_ecbdesc_release(dtp, pcb->pcb_ecbdesc);
+
+ for (dxp = dt_list_next(&dtp->dt_xlators); dxp; dxp = nxp) {
+ nxp = dt_list_next(dxp);
+ if (dxp->dx_gen == dtp->dt_gen)
+ dt_xlator_destroy(dtp, dxp);
+ }
+
+ for (pvp = dt_list_next(&dtp->dt_provlist); pvp; pvp = nvp) {
+ nvp = dt_list_next(pvp);
+ if (pvp->pv_gen == dtp->dt_gen)
+ dt_provider_destroy(dtp, pvp);
+ }
+
+ (void) dt_idhash_iter(dtp->dt_aggs, dt_pcb_pop_ident, dtp);
+ dt_idhash_update(dtp->dt_aggs);
+
+ (void) dt_idhash_iter(dtp->dt_globals, dt_pcb_pop_ident, dtp);
+ dt_idhash_update(dtp->dt_globals);
+
+ (void) dt_idhash_iter(dtp->dt_tls, dt_pcb_pop_ident, dtp);
+ dt_idhash_update(dtp->dt_tls);
+
+ (void) ctf_discard(dtp->dt_cdefs->dm_ctfp);
+ (void) ctf_discard(dtp->dt_ddefs->dm_ctfp);
+ }
+
+ if (pcb->pcb_pragmas != NULL)
+ dt_idhash_destroy(pcb->pcb_pragmas);
+ if (pcb->pcb_locals != NULL)
+ dt_idhash_destroy(pcb->pcb_locals);
+ if (pcb->pcb_idents != NULL)
+ dt_idhash_destroy(pcb->pcb_idents);
+ if (pcb->pcb_inttab != NULL)
+ dt_inttab_destroy(pcb->pcb_inttab);
+ if (pcb->pcb_strtab != NULL)
+ dt_strtab_destroy(pcb->pcb_strtab);
+ if (pcb->pcb_regs != NULL)
+ dt_regset_destroy(pcb->pcb_regs);
+
+ for (i = 0; i < pcb->pcb_asxreflen; i++)
+ dt_free(dtp, pcb->pcb_asxrefs[i]);
+
+ dt_free(dtp, pcb->pcb_asxrefs);
+ dt_difo_free(dtp, pcb->pcb_difo);
+
+ free(pcb->pcb_filetag);
+ free(pcb->pcb_sflagv);
+
+ dtp->dt_pcb = pcb->pcb_prev;
+ bzero(pcb, sizeof (dt_pcb_t));
+ yyinit(dtp->dt_pcb);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.h
new file mode 100644
index 000000000000..0ba2c6b59c3b
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_PCB_H
+#define _DT_PCB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <dtrace.h>
+#include <setjmp.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dt_parser.h>
+#include <dt_regset.h>
+#include <dt_inttab.h>
+#include <dt_strtab.h>
+#include <dt_decl.h>
+#include <dt_as.h>
+
+typedef struct dt_pcb {
+ dtrace_hdl_t *pcb_hdl; /* pointer to library handle */
+ struct dt_pcb *pcb_prev; /* pointer to previous pcb in stack */
+ FILE *pcb_fileptr; /* pointer to input file (or NULL) */
+ char *pcb_filetag; /* optional file name string (or NULL) */
+ const char *pcb_string; /* pointer to input string (or NULL) */
+ const char *pcb_strptr; /* pointer to input position */
+ size_t pcb_strlen; /* length of pcb_string */
+ int pcb_sargc; /* number of script arguments (if any) */
+ char *const *pcb_sargv; /* script argument strings (if any) */
+ ushort_t *pcb_sflagv; /* script argument flags (DT_IDFLG_* bits) */
+ dt_scope_t pcb_dstack; /* declaration processing stack */
+ dt_node_t *pcb_list; /* list of allocated parse tree nodes */
+ dt_node_t *pcb_hold; /* parse tree nodes on hold until end of defn */
+ dt_node_t *pcb_root; /* root of current parse tree */
+ dt_idstack_t pcb_globals; /* stack of global identifier hash tables */
+ dt_idhash_t *pcb_locals; /* current hash table of local identifiers */
+ dt_idhash_t *pcb_idents; /* current hash table of ambiguous idents */
+ dt_idhash_t *pcb_pragmas; /* current hash table of pending pragmas */
+ dt_inttab_t *pcb_inttab; /* integer table for constant references */
+ dt_strtab_t *pcb_strtab; /* string table for string references */
+ dt_regset_t *pcb_regs; /* register set for code generation */
+ dt_irlist_t pcb_ir; /* list of unrelocated IR instructions */
+ uint_t pcb_asvidx; /* assembler vartab index (see dt_as.c) */
+ ulong_t **pcb_asxrefs; /* assembler imported xlators (see dt_as.c) */
+ uint_t pcb_asxreflen; /* assembler xlator map length (see dt_as.c) */
+ const dtrace_probedesc_t *pcb_pdesc; /* probedesc for current context */
+ struct dt_probe *pcb_probe; /* probe associated with current context */
+ dtrace_probeinfo_t pcb_pinfo; /* info associated with current context */
+ dtrace_attribute_t pcb_amin; /* stability minimum for compilation */
+ dt_node_t *pcb_dret; /* node containing return type for assembler */
+ dtrace_difo_t *pcb_difo; /* intermediate DIF object made by assembler */
+ dtrace_prog_t *pcb_prog; /* intermediate program made by compiler */
+ dtrace_stmtdesc_t *pcb_stmt; /* intermediate stmt made by compiler */
+ dtrace_ecbdesc_t *pcb_ecbdesc; /* intermediate ecbdesc made by cmplr */
+ jmp_buf pcb_jmpbuf; /* setjmp(3C) buffer for error return */
+ const char *pcb_region; /* optional region name for yyerror() suffix */
+ dtrace_probespec_t pcb_pspec; /* probe description evaluation context */
+ uint_t pcb_cflags; /* optional compilation flags (see dtrace.h) */
+ uint_t pcb_idepth; /* preprocessor #include nesting depth */
+ yystate_t pcb_yystate; /* lex/yacc parsing state (see yybegin()) */
+ int pcb_context; /* yyparse() rules context (DT_CTX_* value) */
+ int pcb_token; /* token to be returned by yylex() (if != 0) */
+ int pcb_cstate; /* state to be restored by lexer at state end */
+ int pcb_braces; /* number of open curly braces in lexer */
+ int pcb_brackets; /* number of open square brackets in lexer */
+ int pcb_parens; /* number of open parentheses in lexer */
+} dt_pcb_t;
+
+extern void dt_pcb_push(dtrace_hdl_t *, dt_pcb_t *);
+extern void dt_pcb_pop(dtrace_hdl_t *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_PCB_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c
new file mode 100644
index 000000000000..fcbea77f95a2
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c
@@ -0,0 +1,999 @@
+/*
+ * 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 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <assert.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <libgen.h>
+#include <stddef.h>
+#include <sys/sysmacros.h>
+
+#include <dt_impl.h>
+#include <dt_program.h>
+#include <dt_pid.h>
+#include <dt_string.h>
+#include <dt_module.h>
+
+#ifndef illumos
+#include <sys/sysctl.h>
+#include <unistd.h>
+#include <libproc_compat.h>
+#include <libelf.h>
+#include <gelf.h>
+#endif
+
+typedef struct dt_pid_probe {
+ dtrace_hdl_t *dpp_dtp;
+ dt_pcb_t *dpp_pcb;
+ dt_proc_t *dpp_dpr;
+ struct ps_prochandle *dpp_pr;
+ const char *dpp_mod;
+ char *dpp_func;
+ const char *dpp_name;
+ const char *dpp_obj;
+ uintptr_t dpp_pc;
+ size_t dpp_size;
+ Lmid_t dpp_lmid;
+ uint_t dpp_nmatches;
+ uint64_t dpp_stret[4];
+ GElf_Sym dpp_last;
+ uint_t dpp_last_taken;
+} dt_pid_probe_t;
+
+/*
+ * Compose the lmid and object name into the canonical representation. We
+ * omit the lmid for the default link map for convenience.
+ */
+static void
+dt_pid_objname(char *buf, size_t len, Lmid_t lmid, const char *obj)
+{
+#ifdef illumos
+ if (lmid == LM_ID_BASE)
+ (void) strncpy(buf, obj, len);
+ else
+ (void) snprintf(buf, len, "LM%lx`%s", lmid, obj);
+#else
+ (void) strncpy(buf, obj, len);
+#endif
+}
+
+static int
+dt_pid_error(dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr,
+ fasttrap_probe_spec_t *ftp, dt_errtag_t tag, const char *fmt, ...)
+{
+ va_list ap;
+ int len;
+
+ if (ftp != NULL)
+ dt_free(dtp, ftp);
+
+ va_start(ap, fmt);
+ if (pcb == NULL) {
+ assert(dpr != NULL);
+ len = vsnprintf(dpr->dpr_errmsg, sizeof (dpr->dpr_errmsg),
+ fmt, ap);
+ assert(len >= 2);
+ if (dpr->dpr_errmsg[len - 2] == '\n')
+ dpr->dpr_errmsg[len - 2] = '\0';
+ } else {
+ dt_set_errmsg(dtp, dt_errtag(tag), pcb->pcb_region,
+ pcb->pcb_filetag, pcb->pcb_fileptr ? yylineno : 0, fmt, ap);
+ }
+ va_end(ap);
+
+ return (1);
+}
+
+static int
+dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
+{
+ dtrace_hdl_t *dtp = pp->dpp_dtp;
+ dt_pcb_t *pcb = pp->dpp_pcb;
+ dt_proc_t *dpr = pp->dpp_dpr;
+ fasttrap_probe_spec_t *ftp;
+ uint64_t off;
+ char *end;
+ uint_t nmatches = 0;
+ ulong_t sz;
+ int glob, err;
+ int isdash = strcmp("-", func) == 0;
+ pid_t pid;
+
+#ifdef illumos
+ pid = Pstatus(pp->dpp_pr)->pr_pid;
+#else
+ pid = proc_getpid(pp->dpp_pr);
+#endif
+
+ dt_dprintf("creating probe pid%d:%s:%s:%s\n", (int)pid, pp->dpp_obj,
+ func, pp->dpp_name);
+
+ sz = sizeof (fasttrap_probe_spec_t) + (isdash ? 4 :
+ (symp->st_size - 1) * sizeof (ftp->ftps_offs[0]));
+
+ if ((ftp = dt_alloc(dtp, sz)) == NULL) {
+ dt_dprintf("proc_per_sym: dt_alloc(%lu) failed\n", sz);
+ return (1); /* errno is set for us */
+ }
+
+ ftp->ftps_pid = pid;
+ (void) strncpy(ftp->ftps_func, func, sizeof (ftp->ftps_func));
+
+ dt_pid_objname(ftp->ftps_mod, sizeof (ftp->ftps_mod), pp->dpp_lmid,
+ pp->dpp_obj);
+
+ if (!isdash && gmatch("return", pp->dpp_name)) {
+ if (dt_pid_create_return_probe(pp->dpp_pr, dtp, ftp, symp,
+ pp->dpp_stret) < 0) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp,
+ D_PROC_CREATEFAIL, "failed to create return probe "
+ "for '%s': %s", func,
+ dtrace_errmsg(dtp, dtrace_errno(dtp))));
+ }
+
+ nmatches++;
+ }
+
+ if (!isdash && gmatch("entry", pp->dpp_name)) {
+ if (dt_pid_create_entry_probe(pp->dpp_pr, dtp, ftp, symp) < 0) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp,
+ D_PROC_CREATEFAIL, "failed to create entry probe "
+ "for '%s': %s", func,
+ dtrace_errmsg(dtp, dtrace_errno(dtp))));
+ }
+
+ nmatches++;
+ }
+
+ glob = strisglob(pp->dpp_name);
+ if (!glob && nmatches == 0) {
+ off = strtoull(pp->dpp_name, &end, 16);
+ if (*end != '\0') {
+ return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_NAME,
+ "'%s' is an invalid probe name", pp->dpp_name));
+ }
+
+ if (off >= symp->st_size) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_OFF,
+ "offset 0x%llx outside of function '%s'",
+ (u_longlong_t)off, func));
+ }
+
+ err = dt_pid_create_offset_probe(pp->dpp_pr, pp->dpp_dtp, ftp,
+ symp, off);
+
+ if (err == DT_PROC_ERR) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp,
+ D_PROC_CREATEFAIL, "failed to create probe at "
+ "'%s+0x%llx': %s", func, (u_longlong_t)off,
+ dtrace_errmsg(dtp, dtrace_errno(dtp))));
+ }
+
+ if (err == DT_PROC_ALIGN) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_ALIGN,
+ "offset 0x%llx is not aligned on an instruction",
+ (u_longlong_t)off));
+ }
+
+ nmatches++;
+
+ } else if (glob && !isdash) {
+ if (dt_pid_create_glob_offset_probes(pp->dpp_pr,
+ pp->dpp_dtp, ftp, symp, pp->dpp_name) < 0) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp,
+ D_PROC_CREATEFAIL,
+ "failed to create offset probes in '%s': %s", func,
+ dtrace_errmsg(dtp, dtrace_errno(dtp))));
+ }
+
+ nmatches++;
+ }
+
+ pp->dpp_nmatches += nmatches;
+
+ dt_free(dtp, ftp);
+
+ return (0);
+}
+
+static int
+dt_pid_sym_filt(void *arg, const GElf_Sym *symp, const char *func)
+{
+ dt_pid_probe_t *pp = arg;
+
+ if (symp->st_shndx == SHN_UNDEF)
+ return (0);
+
+ if (symp->st_size == 0) {
+ dt_dprintf("st_size of %s is zero\n", func);
+ return (0);
+ }
+
+ if (pp->dpp_last_taken == 0 ||
+ symp->st_value != pp->dpp_last.st_value ||
+ symp->st_size != pp->dpp_last.st_size) {
+ /*
+ * Due to 4524008, _init and _fini may have a bloated st_size.
+ * While this bug has been fixed for a while, old binaries
+ * may exist that still exhibit this problem. As a result, we
+ * don't match _init and _fini though we allow users to
+ * specify them explicitly.
+ */
+ if (strcmp(func, "_init") == 0 || strcmp(func, "_fini") == 0)
+ return (0);
+
+ if ((pp->dpp_last_taken = gmatch(func, pp->dpp_func)) != 0) {
+ pp->dpp_last = *symp;
+ return (dt_pid_per_sym(pp, symp, func));
+ }
+ }
+
+ return (0);
+}
+
+static int
+dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
+{
+ dt_pid_probe_t *pp = arg;
+ dtrace_hdl_t *dtp = pp->dpp_dtp;
+ dt_pcb_t *pcb = pp->dpp_pcb;
+ dt_proc_t *dpr = pp->dpp_dpr;
+ GElf_Sym sym;
+
+ if (obj == NULL)
+ return (0);
+
+#ifdef illumos
+ (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
+#endif
+
+
+ if ((pp->dpp_obj = strrchr(obj, '/')) == NULL)
+ pp->dpp_obj = obj;
+ else
+ pp->dpp_obj++;
+#ifdef illumos
+ if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret1", &sym,
+ NULL) == 0)
+ pp->dpp_stret[0] = sym.st_value;
+ else
+ pp->dpp_stret[0] = 0;
+
+ if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret2", &sym,
+ NULL) == 0)
+ pp->dpp_stret[1] = sym.st_value;
+ else
+ pp->dpp_stret[1] = 0;
+
+ if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret4", &sym,
+ NULL) == 0)
+ pp->dpp_stret[2] = sym.st_value;
+ else
+ pp->dpp_stret[2] = 0;
+
+ if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret8", &sym,
+ NULL) == 0)
+ pp->dpp_stret[3] = sym.st_value;
+ else
+ pp->dpp_stret[3] = 0;
+#else
+ pp->dpp_stret[0] = 0;
+ pp->dpp_stret[1] = 0;
+ pp->dpp_stret[2] = 0;
+ pp->dpp_stret[3] = 0;
+#endif
+
+ dt_dprintf("%s stret %llx %llx %llx %llx\n", obj,
+ (u_longlong_t)pp->dpp_stret[0], (u_longlong_t)pp->dpp_stret[1],
+ (u_longlong_t)pp->dpp_stret[2], (u_longlong_t)pp->dpp_stret[3]);
+
+ /*
+ * If pp->dpp_func contains any globbing meta-characters, we need
+ * to iterate over the symbol table and compare each function name
+ * against the pattern.
+ */
+ if (!strisglob(pp->dpp_func)) {
+ /*
+ * If we fail to lookup the symbol, try interpreting the
+ * function as the special "-" function that indicates that the
+ * probe name should be interpreted as a absolute virtual
+ * address. If that fails and we were matching a specific
+ * function in a specific module, report the error, otherwise
+ * just fail silently in the hopes that some other object will
+ * contain the desired symbol.
+ */
+ if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj,
+ pp->dpp_func, &sym, NULL) != 0) {
+ if (strcmp("-", pp->dpp_func) == 0) {
+ sym.st_name = 0;
+ sym.st_info =
+ GELF_ST_INFO(STB_LOCAL, STT_FUNC);
+ sym.st_other = 0;
+ sym.st_value = 0;
+#ifdef illumos
+ sym.st_size = Pstatus(pp->dpp_pr)->pr_dmodel ==
+ PR_MODEL_ILP32 ? -1U : -1ULL;
+#else
+ sym.st_size = ~((Elf64_Xword) 0);
+#endif
+
+ } else if (!strisglob(pp->dpp_mod)) {
+ return (dt_pid_error(dtp, pcb, dpr, NULL,
+ D_PROC_FUNC,
+ "failed to lookup '%s' in module '%s'",
+ pp->dpp_func, pp->dpp_mod));
+ } else {
+ return (0);
+ }
+ }
+
+ /*
+ * Only match defined functions of non-zero size.
+ */
+ if (GELF_ST_TYPE(sym.st_info) != STT_FUNC ||
+ sym.st_shndx == SHN_UNDEF || sym.st_size == 0)
+ return (0);
+
+ /*
+ * We don't instrument PLTs -- they're dynamically rewritten,
+ * and, so, inherently dicey to instrument.
+ */
+#ifdef DOODAD
+ if (Ppltdest(pp->dpp_pr, sym.st_value) != NULL)
+ return (0);
+#endif
+
+ (void) Plookup_by_addr(pp->dpp_pr, sym.st_value, pp->dpp_func,
+ DTRACE_FUNCNAMELEN, &sym);
+
+ return (dt_pid_per_sym(pp, &sym, pp->dpp_func));
+ } else {
+ uint_t nmatches = pp->dpp_nmatches;
+
+ if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_SYMTAB,
+ BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
+ return (1);
+
+ if (nmatches == pp->dpp_nmatches) {
+ /*
+ * If we didn't match anything in the PR_SYMTAB, try
+ * the PR_DYNSYM.
+ */
+ if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_DYNSYM,
+ BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+static int
+dt_pid_mod_filt(void *arg, const prmap_t *pmp, const char *obj)
+{
+ char name[DTRACE_MODNAMELEN];
+ dt_pid_probe_t *pp = arg;
+
+ if (gmatch(obj, pp->dpp_mod))
+ return (dt_pid_per_mod(pp, pmp, obj));
+
+#ifdef illumos
+ (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
+#else
+ pp->dpp_lmid = 0;
+#endif
+
+ if ((pp->dpp_obj = strrchr(obj, '/')) == NULL)
+ pp->dpp_obj = obj;
+ else
+ pp->dpp_obj++;
+
+ if (gmatch(pp->dpp_obj, pp->dpp_mod))
+ return (dt_pid_per_mod(pp, pmp, obj));
+
+#ifdef illumos
+ (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
+#endif
+
+ dt_pid_objname(name, sizeof (name), pp->dpp_lmid, pp->dpp_obj);
+
+ if (gmatch(name, pp->dpp_mod))
+ return (dt_pid_per_mod(pp, pmp, obj));
+
+ return (0);
+}
+
+static const prmap_t *
+dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
+{
+ char m[MAXPATHLEN];
+ Lmid_t lmid = PR_LMID_EVERY;
+ const char *obj;
+ const prmap_t *pmp;
+
+ /*
+ * Pick apart the link map from the library name.
+ */
+ if (strchr(pdp->dtpd_mod, '`') != NULL) {
+ char *end;
+
+ if (strncmp(pdp->dtpd_mod, "LM", 2) != 0 ||
+ !isdigit(pdp->dtpd_mod[2]))
+ return (NULL);
+
+ lmid = strtoul(&pdp->dtpd_mod[2], &end, 16);
+
+ obj = end + 1;
+
+ if (*end != '`' || strchr(obj, '`') != NULL)
+ return (NULL);
+
+ } else {
+ obj = pdp->dtpd_mod;
+ }
+
+ if ((pmp = Plmid_to_map(P, lmid, obj)) == NULL)
+ return (NULL);
+
+ (void) Pobjname(P, pmp->pr_vaddr, m, sizeof (m));
+ if ((obj = strrchr(m, '/')) == NULL)
+ obj = &m[0];
+ else
+ obj++;
+
+#ifdef illumos
+ (void) Plmid(P, pmp->pr_vaddr, &lmid);
+#endif
+
+ dt_pid_objname(pdp->dtpd_mod, sizeof (pdp->dtpd_mod), lmid, obj);
+
+ return (pmp);
+}
+
+
+static int
+dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
+ dt_pcb_t *pcb, dt_proc_t *dpr)
+{
+ dt_pid_probe_t pp;
+ int ret = 0;
+
+ pp.dpp_dtp = dtp;
+ pp.dpp_dpr = dpr;
+ pp.dpp_pr = dpr->dpr_proc;
+ pp.dpp_pcb = pcb;
+
+#ifdef DOODAD
+ /*
+ * We can only trace dynamically-linked executables (since we've
+ * hidden some magic in ld.so.1 as well as libc.so.1).
+ */
+ if (Pname_to_map(pp.dpp_pr, PR_OBJ_LDSO) == NULL) {
+ return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_DYN,
+ "process %s is not a dynamically-linked executable",
+ &pdp->dtpd_provider[3]));
+ }
+#endif
+
+ pp.dpp_mod = pdp->dtpd_mod[0] != '\0' ? pdp->dtpd_mod : "*";
+ pp.dpp_func = pdp->dtpd_func[0] != '\0' ? pdp->dtpd_func : "*";
+ pp.dpp_name = pdp->dtpd_name[0] != '\0' ? pdp->dtpd_name : "*";
+ pp.dpp_last_taken = 0;
+
+ if (strcmp(pp.dpp_func, "-") == 0) {
+ const prmap_t *aout, *pmp;
+
+ if (pdp->dtpd_mod[0] == '\0') {
+ pp.dpp_mod = pdp->dtpd_mod;
+ (void) strcpy(pdp->dtpd_mod, "a.out");
+ } else if (strisglob(pp.dpp_mod) ||
+ (aout = Pname_to_map(pp.dpp_pr, "a.out")) == NULL ||
+ (pmp = Pname_to_map(pp.dpp_pr, pp.dpp_mod)) == NULL ||
+ aout->pr_vaddr != pmp->pr_vaddr) {
+ return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_LIB,
+ "only the a.out module is valid with the "
+ "'-' function"));
+ }
+
+ if (strisglob(pp.dpp_name)) {
+ return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_NAME,
+ "only individual addresses may be specified "
+ "with the '-' function"));
+ }
+ }
+
+ /*
+ * If pp.dpp_mod contains any globbing meta-characters, we need
+ * to iterate over each module and compare its name against the
+ * pattern. An empty module name is treated as '*'.
+ */
+ if (strisglob(pp.dpp_mod)) {
+ ret = Pobject_iter(pp.dpp_pr, dt_pid_mod_filt, &pp);
+ } else {
+ const prmap_t *pmp;
+ char *obj;
+
+ /*
+ * If we can't find a matching module, don't sweat it -- either
+ * we'll fail the enabling because the probes don't exist or
+ * we'll wait for that module to come along.
+ */
+ if ((pmp = dt_pid_fix_mod(pdp, pp.dpp_pr)) != NULL) {
+ if ((obj = strchr(pdp->dtpd_mod, '`')) == NULL)
+ obj = pdp->dtpd_mod;
+ else
+ obj++;
+
+ ret = dt_pid_per_mod(&pp, pmp, obj);
+ }
+ }
+
+ return (ret);
+}
+
+static int
+dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
+{
+ struct ps_prochandle *P = data;
+ GElf_Sym sym;
+ prsyminfo_t sip;
+ dof_helper_t dh;
+ GElf_Half e_type;
+ const char *mname;
+ const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
+ int i, fd = -1;
+
+ /*
+ * The symbol ___SUNW_dof is for lazy-loaded DOF sections, and
+ * __SUNW_dof is for actively-loaded DOF sections. We try to force
+ * in both types of DOF section since the process may not yet have
+ * run the code to instantiate these providers.
+ */
+ for (i = 0; i < 2; i++) {
+ if (Pxlookup_by_name(P, PR_LMID_EVERY, oname, syms[i], &sym,
+ &sip) != 0) {
+ continue;
+ }
+
+ if ((mname = strrchr(oname, '/')) == NULL)
+ mname = oname;
+ else
+ mname++;
+
+ dt_dprintf("lookup of %s succeeded for %s\n", syms[i], mname);
+
+ if (Pread(P, &e_type, sizeof (e_type), pmp->pr_vaddr +
+ offsetof(Elf64_Ehdr, e_type)) != sizeof (e_type)) {
+ dt_dprintf("read of ELF header failed");
+ continue;
+ }
+
+ dh.dofhp_dof = sym.st_value;
+ dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
+
+ dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
+ sip.prs_lmid, mname);
+
+#ifdef __FreeBSD__
+ dh.dofhp_pid = proc_getpid(P);
+
+ if (fd == -1 &&
+ (fd = open("/dev/dtrace/helper", O_RDWR, 0)) < 0) {
+ dt_dprintf("open of helper device failed: %s\n",
+ strerror(errno));
+ return (-1); /* errno is set for us */
+ }
+
+ if (ioctl(fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
+ dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
+#else
+ if (fd == -1 &&
+ (fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
+ dt_dprintf("pr_open of helper device failed: %s\n",
+ strerror(errno));
+ return (-1); /* errno is set for us */
+ }
+
+ if (pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
+ dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
+#endif
+ }
+
+ if (fd != -1)
+#ifdef __FreeBSD__
+ (void) close(fd);
+#else
+ (void) pr_close(P, fd);
+#endif
+
+ return (0);
+}
+
+static int
+dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
+ dt_pcb_t *pcb, dt_proc_t *dpr)
+{
+ struct ps_prochandle *P = dpr->dpr_proc;
+ int ret = 0;
+
+ assert(DT_MUTEX_HELD(&dpr->dpr_lock));
+ (void) Pupdate_maps(P);
+ if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
+ ret = -1;
+ (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
+ "failed to instantiate probes for pid %d: %s",
+#ifdef illumos
+ (int)Pstatus(P)->pr_pid, strerror(errno));
+#else
+ (int)proc_getpid(P), strerror(errno));
+#endif
+ }
+
+ /*
+ * Put the module name in its canonical form.
+ */
+ (void) dt_pid_fix_mod(pdp, P);
+
+ return (ret);
+}
+
+static pid_t
+dt_pid_get_pid(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
+ dt_proc_t *dpr)
+{
+ pid_t pid;
+ char *c, *last = NULL, *end;
+
+ for (c = &pdp->dtpd_provider[0]; *c != '\0'; c++) {
+ if (!isdigit(*c))
+ last = c;
+ }
+
+ if (last == NULL || (*(++last) == '\0')) {
+ (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_BADPROV,
+ "'%s' is not a valid provider", pdp->dtpd_provider);
+ return (-1);
+ }
+
+ errno = 0;
+ pid = strtol(last, &end, 10);
+
+ if (errno != 0 || end == last || end[0] != '\0' || pid <= 0) {
+ (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_BADPID,
+ "'%s' does not contain a valid pid", pdp->dtpd_provider);
+ return (-1);
+ }
+
+ return (pid);
+}
+
+int
+dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
+{
+ char provname[DTRACE_PROVNAMELEN];
+ struct ps_prochandle *P;
+ dt_proc_t *dpr;
+ pid_t pid;
+ int err = 0;
+
+ assert(pcb != NULL);
+
+ if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1)
+ return (-1);
+
+ if (dtp->dt_ftfd == -1) {
+ if (dtp->dt_fterr == ENOENT) {
+ (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
+ "pid provider is not installed on this system");
+ } else {
+ (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
+ "pid provider is not available: %s",
+ strerror(dtp->dt_fterr));
+ }
+
+ return (-1);
+ }
+
+ (void) snprintf(provname, sizeof (provname), "pid%d", (int)pid);
+
+ if (gmatch(provname, pdp->dtpd_provider) != 0) {
+#ifdef __FreeBSD__
+ if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL)
+#else
+ if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE,
+ 0)) == NULL)
+#endif
+ {
+ (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
+ "failed to grab process %d", (int)pid);
+ return (-1);
+ }
+
+ dpr = dt_proc_lookup(dtp, P, 0);
+ assert(dpr != NULL);
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+
+ if ((err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr)) == 0) {
+ /*
+ * Alert other retained enablings which may match
+ * against the newly created probes.
+ */
+ (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL);
+ }
+
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+ dt_proc_release(dtp, P);
+ }
+
+ /*
+ * If it's not strictly a pid provider, we might match a USDT provider.
+ */
+ if (strcmp(provname, pdp->dtpd_provider) != 0) {
+ if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL) {
+ (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
+ "failed to grab process %d", (int)pid);
+ return (-1);
+ }
+
+ dpr = dt_proc_lookup(dtp, P, 0);
+ assert(dpr != NULL);
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+
+ if (!dpr->dpr_usdt) {
+ err = dt_pid_create_usdt_probes(pdp, dtp, pcb, dpr);
+ dpr->dpr_usdt = B_TRUE;
+ }
+
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+ dt_proc_release(dtp, P);
+ }
+
+ return (err ? -1 : 0);
+}
+
+int
+dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr)
+{
+ dtrace_enable_io_t args;
+ dtrace_prog_t *pgp;
+ dt_stmt_t *stp;
+ dtrace_probedesc_t *pdp, pd;
+ pid_t pid;
+ int ret = 0, found = B_FALSE;
+ char provname[DTRACE_PROVNAMELEN];
+
+ (void) snprintf(provname, sizeof (provname), "pid%d",
+ (int)dpr->dpr_pid);
+
+ for (pgp = dt_list_next(&dtp->dt_programs); pgp != NULL;
+ pgp = dt_list_next(pgp)) {
+
+ for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL;
+ stp = dt_list_next(stp)) {
+
+ pdp = &stp->ds_desc->dtsd_ecbdesc->dted_probe;
+ pid = dt_pid_get_pid(pdp, dtp, NULL, dpr);
+ if (pid != dpr->dpr_pid)
+ continue;
+
+ found = B_TRUE;
+
+ pd = *pdp;
+
+ if (gmatch(provname, pdp->dtpd_provider) != 0 &&
+ dt_pid_create_pid_probes(&pd, dtp, NULL, dpr) != 0)
+ ret = 1;
+
+ /*
+ * If it's not strictly a pid provider, we might match
+ * a USDT provider.
+ */
+ if (strcmp(provname, pdp->dtpd_provider) != 0 &&
+ dt_pid_create_usdt_probes(&pd, dtp, NULL, dpr) != 0)
+ ret = 1;
+ }
+ }
+
+ if (found) {
+ /*
+ * Give DTrace a shot to the ribs to get it to check
+ * out the newly created probes.
+ */
+ args.dof = NULL;
+ args.n_matched = 0;
+ (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
+ }
+
+ return (ret);
+}
+
+/*
+ * libdtrace has a backroom deal with us to ask us for type information on
+ * behalf of pid provider probes when fasttrap doesn't return any type
+ * information. Instead we'll look up the module and see if there is type
+ * information available. However, if there is no type information available due
+ * to a lack of CTF data, then we want to make sure that DTrace still carries on
+ * in face of that. As such we don't have a meaningful exit code about failure.
+ * We emit information about why we failed to the dtrace debug log so someone
+ * can figure it out by asking nicely for DTRACE_DEBUG.
+ */
+void
+dt_pid_get_types(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
+ dtrace_argdesc_t *adp, int *nargs)
+{
+ dt_module_t *dmp;
+ ctf_file_t *fp;
+ ctf_funcinfo_t f;
+ ctf_id_t argv[32];
+ GElf_Sym sym;
+ prsyminfo_t si;
+ struct ps_prochandle *p;
+ int i, args;
+ char buf[DTRACE_ARGTYPELEN];
+ const char *mptr;
+ char *eptr;
+ int ret = 0;
+ int argc = sizeof (argv) / sizeof (ctf_id_t);
+ Lmid_t lmid;
+
+ /* Set up a potential outcome */
+ args = *nargs;
+ *nargs = 0;
+
+ /*
+ * If we don't have an entry or return probe then we can just stop right
+ * now as we don't have arguments for offset probes.
+ */
+ if (strcmp(pdp->dtpd_name, "entry") != 0 &&
+ strcmp(pdp->dtpd_name, "return") != 0)
+ return;
+
+ dmp = dt_module_create(dtp, pdp->dtpd_provider);
+ if (dmp == NULL) {
+ dt_dprintf("failed to find module for %s\n",
+ pdp->dtpd_provider);
+ return;
+ }
+ if (dt_module_load(dtp, dmp) != 0) {
+ dt_dprintf("failed to load module for %s\n",
+ pdp->dtpd_provider);
+ return;
+ }
+
+ /*
+ * We may be working with a module that doesn't have ctf. If that's the
+ * case then we just return now and move on with life.
+ */
+ fp = dt_module_getctflib(dtp, dmp, pdp->dtpd_mod);
+ if (fp == NULL) {
+ dt_dprintf("no ctf container for %s\n",
+ pdp->dtpd_mod);
+ return;
+ }
+ p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE);
+ if (p == NULL) {
+ dt_dprintf("failed to grab pid\n");
+ return;
+ }
+ dt_proc_lock(dtp, p);
+
+ /*
+ * Check to see if the D module has a link map ID and separate that out
+ * for properly interrogating libproc.
+ */
+ if ((mptr = strchr(pdp->dtpd_mod, '`')) != NULL) {
+ if (strlen(pdp->dtpd_mod) < 3) {
+ dt_dprintf("found weird modname with linkmap, "
+ "aborting: %s\n", pdp->dtpd_mod);
+ goto out;
+ }
+ if (pdp->dtpd_mod[0] != 'L' || pdp->dtpd_mod[1] != 'M') {
+ dt_dprintf("missing leading 'LM', "
+ "aborting: %s\n", pdp->dtpd_mod);
+ goto out;
+ }
+ errno = 0;
+ lmid = strtol(pdp->dtpd_mod + 2, &eptr, 16);
+ if (errno == ERANGE || eptr != mptr) {
+ dt_dprintf("failed to parse out lmid, aborting: %s\n",
+ pdp->dtpd_mod);
+ goto out;
+ }
+ mptr++;
+ } else {
+ mptr = pdp->dtpd_mod;
+ lmid = 0;
+ }
+
+ if (Pxlookup_by_name(p, lmid, mptr, pdp->dtpd_func,
+ &sym, &si) != 0) {
+ dt_dprintf("failed to find function %s in %s`%s\n",
+ pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
+ goto out;
+ }
+ if (ctf_func_info(fp, si.prs_id, &f) == CTF_ERR) {
+ dt_dprintf("failed to get ctf information for %s in %s`%s\n",
+ pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
+ goto out;
+ }
+
+ (void) snprintf(buf, sizeof (buf), "%s`%s", pdp->dtpd_provider,
+ pdp->dtpd_mod);
+
+ if (strcmp(pdp->dtpd_name, "return") == 0) {
+ if (args < 2)
+ goto out;
+
+ bzero(adp, sizeof (dtrace_argdesc_t));
+ adp->dtargd_ndx = 0;
+ adp->dtargd_id = pdp->dtpd_id;
+ adp->dtargd_mapping = adp->dtargd_ndx;
+ /*
+ * We explicitly leave out the library here, we only care that
+ * it is some int. We are assuming that there is no ctf
+ * container in here that is lying about what an int is.
+ */
+ (void) snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
+ "user %s`%s", pdp->dtpd_provider, "int");
+ adp++;
+ bzero(adp, sizeof (dtrace_argdesc_t));
+ adp->dtargd_ndx = 1;
+ adp->dtargd_id = pdp->dtpd_id;
+ adp->dtargd_mapping = adp->dtargd_ndx;
+ ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
+ "userland ");
+ (void) ctf_type_qname(fp, f.ctc_return, adp->dtargd_native +
+ ret, DTRACE_ARGTYPELEN - ret, buf);
+ *nargs = 2;
+ } else {
+ if (ctf_func_args(fp, si.prs_id, argc, argv) == CTF_ERR)
+ goto out;
+
+ *nargs = MIN(args, f.ctc_argc);
+ for (i = 0; i < *nargs; i++, adp++) {
+ bzero(adp, sizeof (dtrace_argdesc_t));
+ adp->dtargd_ndx = i;
+ adp->dtargd_id = pdp->dtpd_id;
+ adp->dtargd_mapping = adp->dtargd_ndx;
+ ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
+ "userland ");
+ (void) ctf_type_qname(fp, argv[i], adp->dtargd_native +
+ ret, DTRACE_ARGTYPELEN - ret, buf);
+ }
+ }
+out:
+ dt_proc_unlock(dtp, p);
+ dt_proc_release(dtp, p);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h
new file mode 100644
index 000000000000..4bf39c864580
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _DT_PID_H
+#define _DT_PID_H
+
+#include <libproc.h>
+#include <sys/fasttrap.h>
+#include <dt_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DT_PROC_ERR (-1)
+#define DT_PROC_ALIGN (-2)
+
+extern int dt_pid_create_probes(dtrace_probedesc_t *, dtrace_hdl_t *,
+ dt_pcb_t *pcb);
+extern int dt_pid_create_probes_module(dtrace_hdl_t *, dt_proc_t *);
+
+extern int dt_pid_create_entry_probe(struct ps_prochandle *, dtrace_hdl_t *,
+ fasttrap_probe_spec_t *, const GElf_Sym *);
+
+extern int dt_pid_create_return_probe(struct ps_prochandle *, dtrace_hdl_t *,
+ fasttrap_probe_spec_t *, const GElf_Sym *, uint64_t *);
+
+extern int dt_pid_create_offset_probe(struct ps_prochandle *, dtrace_hdl_t *,
+ fasttrap_probe_spec_t *, const GElf_Sym *, ulong_t);
+
+extern int dt_pid_create_glob_offset_probes(struct ps_prochandle *,
+ dtrace_hdl_t *, fasttrap_probe_spec_t *, const GElf_Sym *, const char *);
+
+extern void dt_pid_get_types(dtrace_hdl_t *, const dtrace_probedesc_t *,
+ dtrace_argdesc_t *, int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_PID_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.c
new file mode 100644
index 000000000000..0cd556abd8f5
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.c
@@ -0,0 +1,157 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <dtrace.h>
+#include <dt_impl.h>
+#include <dt_pq.h>
+#include <assert.h>
+
+/*
+ * Create a new priority queue.
+ *
+ * size is the maximum number of items that will be stored in the priority
+ * queue at one time.
+ */
+dt_pq_t *
+dt_pq_init(dtrace_hdl_t *dtp, uint_t size, dt_pq_value_f value_cb, void *cb_arg)
+{
+ dt_pq_t *p;
+ assert(size > 1);
+
+ if ((p = dt_zalloc(dtp, sizeof (dt_pq_t))) == NULL)
+ return (NULL);
+
+ p->dtpq_items = dt_zalloc(dtp, size * sizeof (p->dtpq_items[0]));
+ if (p->dtpq_items == NULL) {
+ dt_free(dtp, p);
+ return (NULL);
+ }
+
+ p->dtpq_hdl = dtp;
+ p->dtpq_size = size;
+ p->dtpq_last = 1;
+ p->dtpq_value = value_cb;
+ p->dtpq_arg = cb_arg;
+
+ return (p);
+}
+
+void
+dt_pq_fini(dt_pq_t *p)
+{
+ dtrace_hdl_t *dtp = p->dtpq_hdl;
+
+ dt_free(dtp, p->dtpq_items);
+ dt_free(dtp, p);
+}
+
+static uint64_t
+dt_pq_getvalue(dt_pq_t *p, uint_t index)
+{
+ void *item = p->dtpq_items[index];
+ return (p->dtpq_value(item, p->dtpq_arg));
+}
+
+void
+dt_pq_insert(dt_pq_t *p, void *item)
+{
+ uint_t i;
+
+ assert(p->dtpq_last < p->dtpq_size);
+
+ i = p->dtpq_last++;
+ p->dtpq_items[i] = item;
+
+ while (i > 1 && dt_pq_getvalue(p, i) < dt_pq_getvalue(p, i / 2)) {
+ void *tmp = p->dtpq_items[i];
+ p->dtpq_items[i] = p->dtpq_items[i / 2];
+ p->dtpq_items[i / 2] = tmp;
+ i /= 2;
+ }
+}
+
+/*
+ * Return elements from the priority queue. *cookie should be zero when first
+ * called. Returns NULL when there are no more elements.
+ */
+void *
+dt_pq_walk(dt_pq_t *p, uint_t *cookie)
+{
+ (*cookie)++;
+ if (*cookie >= p->dtpq_last)
+ return (NULL);
+
+ return (p->dtpq_items[*cookie]);
+}
+
+void *
+dt_pq_pop(dt_pq_t *p)
+{
+ uint_t i = 1;
+ void *ret;
+
+ assert(p->dtpq_last > 0);
+
+ if (p->dtpq_last == 1)
+ return (NULL);
+
+ ret = p->dtpq_items[1];
+
+ p->dtpq_last--;
+ p->dtpq_items[1] = p->dtpq_items[p->dtpq_last];
+ p->dtpq_items[p->dtpq_last] = NULL;
+
+ for (;;) {
+ uint_t lc = i * 2;
+ uint_t rc = i * 2 + 1;
+ uint_t c;
+ uint64_t v;
+ void *tmp;
+
+ if (lc >= p->dtpq_last)
+ break;
+
+ if (rc >= p->dtpq_last) {
+ c = lc;
+ v = dt_pq_getvalue(p, lc);
+ } else {
+ uint64_t lv = dt_pq_getvalue(p, lc);
+ uint64_t rv = dt_pq_getvalue(p, rc);
+
+ if (lv < rv) {
+ c = lc;
+ v = lv;
+ } else {
+ c = rc;
+ v = rv;
+ }
+ }
+
+ if (v >= dt_pq_getvalue(p, i))
+ break;
+
+ tmp = p->dtpq_items[i];
+ p->dtpq_items[i] = p->dtpq_items[c];
+ p->dtpq_items[c] = tmp;
+
+ i = c;
+ }
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.h
new file mode 100644
index 000000000000..8184a90c6656
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.h
@@ -0,0 +1,51 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#ifndef _DT_PQ_H
+#define _DT_PQ_H
+
+#include <dtrace.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint64_t (*dt_pq_value_f)(void *, void *);
+
+typedef struct dt_pq {
+ dtrace_hdl_t *dtpq_hdl; /* dtrace handle */
+ void **dtpq_items; /* array of elements */
+ uint_t dtpq_size; /* count of allocated elements */
+ uint_t dtpq_last; /* next free slot */
+ dt_pq_value_f dtpq_value; /* callback to get the value */
+ void *dtpq_arg; /* callback argument */
+} dt_pq_t;
+
+extern dt_pq_t *dt_pq_init(dtrace_hdl_t *, uint_t size, dt_pq_value_f, void *);
+extern void dt_pq_fini(dt_pq_t *);
+
+extern void dt_pq_insert(dt_pq_t *, void *);
+extern void *dt_pq_pop(dt_pq_t *);
+extern void *dt_pq_walk(dt_pq_t *, uint_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_PQ_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c
new file mode 100644
index 000000000000..550a436e0b0c
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c
@@ -0,0 +1,564 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <assert.h>
+#include <strings.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+
+#include <dt_parser.h>
+#include <dt_impl.h>
+#include <dt_provider.h>
+#include <dt_module.h>
+
+/*
+ * This callback function is installed in a given identifier hash to search for
+ * and apply deferred pragmas that are pending for a given new identifier name.
+ * Multiple pragmas may be pending for a given name; we processs all of them.
+ */
+/*ARGSUSED*/
+static void
+dt_pragma_apply(dt_idhash_t *dhp, dt_ident_t *idp)
+{
+ dt_idhash_t *php;
+ dt_ident_t *pdp;
+
+ if ((php = yypcb->pcb_pragmas) == NULL)
+ return; /* no pragmas pending for current compilation pass */
+
+ while ((pdp = dt_idhash_lookup(php, idp->di_name)) != NULL) {
+ switch (pdp->di_kind) {
+ case DT_IDENT_PRAGAT:
+ idp->di_attr = pdp->di_attr;
+ break;
+ case DT_IDENT_PRAGBN:
+ idp->di_vers = pdp->di_vers;
+ break;
+ }
+ dt_idhash_delete(php, pdp);
+ }
+}
+
+/*
+ * The #pragma attributes directive can be used to reset stability attributes
+ * on a global identifier or inline definition. If the identifier is already
+ * defined, we can just change di_attr. If not, we insert the pragma into a
+ * hash table of the current pcb's deferred pragmas for later processing.
+ */
+static void
+dt_pragma_attributes(const char *prname, dt_node_t *dnp)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dtrace_attribute_t attr, *a;
+ dt_provider_t *pvp;
+ const char *name, *part;
+ dt_ident_t *idp;
+
+ if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT ||
+ dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) {
+ xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
+ "<attributes> <ident>\n", prname);
+ }
+
+ if (dtrace_str2attr(dnp->dn_string, &attr) == -1) {
+ xyerror(D_PRAGMA_INVAL, "invalid attributes "
+ "specified by #pragma %s\n", prname);
+ }
+
+ dnp = dnp->dn_list;
+ name = dnp->dn_string;
+
+ if (strcmp(name, "provider") == 0) {
+ dnp = dnp->dn_list;
+ name = dnp->dn_string;
+
+ dnp = dnp->dn_list;
+ part = dnp->dn_string;
+
+ if ((pvp = dt_provider_lookup(dtp, name)) != NULL) {
+ if (strcmp(part, "provider") == 0) {
+ a = &pvp->pv_desc.dtvd_attr.dtpa_provider;
+ } else if (strcmp(part, "module") == 0) {
+ a = &pvp->pv_desc.dtvd_attr.dtpa_mod;
+ } else if (strcmp(part, "function") == 0) {
+ a = &pvp->pv_desc.dtvd_attr.dtpa_func;
+ } else if (strcmp(part, "name") == 0) {
+ a = &pvp->pv_desc.dtvd_attr.dtpa_name;
+ } else if (strcmp(part, "args") == 0) {
+ a = &pvp->pv_desc.dtvd_attr.dtpa_args;
+ } else {
+ xyerror(D_PRAGMA_INVAL, "invalid component "
+ "\"%s\" in attribute #pragma "
+ "for provider %s\n", name, part);
+ }
+
+ *a = attr;
+ return;
+ }
+
+ } else if ((idp = dt_idstack_lookup(
+ &yypcb->pcb_globals, name)) != NULL) {
+
+ if (idp->di_gen != dtp->dt_gen) {
+ xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify "
+ "entity defined outside program scope\n", prname);
+ }
+
+ idp->di_attr = attr;
+ return;
+ }
+
+ if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas =
+ dt_idhash_create("pragma", NULL, 0, 0)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGAT, 0, 0,
+ attr, 0, &dt_idops_thaw, (void *)prname, dtp->dt_gen);
+
+ if (idp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ if (dtp->dt_globals->dh_defer == NULL)
+ dtp->dt_globals->dh_defer = &dt_pragma_apply;
+}
+
+/*
+ * The #pragma binding directive can be used to reset the version binding
+ * on a global identifier or inline definition. If the identifier is already
+ * defined, we can just change di_vers. If not, we insert the pragma into a
+ * hash table of the current pcb's deferred pragmas for later processing.
+ */
+static void
+dt_pragma_binding(const char *prname, dt_node_t *dnp)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_version_t vers;
+ const char *name;
+ dt_ident_t *idp;
+
+ if (dnp == NULL || dnp->dn_kind != DT_NODE_STRING ||
+ dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) {
+ xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
+ "\"version\" <ident>\n", prname);
+ }
+
+ if (dt_version_str2num(dnp->dn_string, &vers) == -1) {
+ xyerror(D_PRAGMA_INVAL, "invalid version string "
+ "specified by #pragma %s\n", prname);
+ }
+
+ name = dnp->dn_list->dn_string;
+ idp = dt_idstack_lookup(&yypcb->pcb_globals, name);
+
+ if (idp != NULL) {
+ if (idp->di_gen != dtp->dt_gen) {
+ xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify "
+ "entity defined outside program scope\n", prname);
+ }
+ idp->di_vers = vers;
+ return;
+ }
+
+ if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas =
+ dt_idhash_create("pragma", NULL, 0, 0)) == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGBN, 0, 0,
+ _dtrace_defattr, vers, &dt_idops_thaw, (void *)prname, dtp->dt_gen);
+
+ if (idp == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+
+ if (dtp->dt_globals->dh_defer == NULL)
+ dtp->dt_globals->dh_defer = &dt_pragma_apply;
+}
+
+static void
+dt_pragma_depends_finddep(dtrace_hdl_t *dtp, const char *lname, char *lib,
+ size_t len)
+{
+ dt_dirpath_t *dirp;
+ struct stat sbuf;
+ int found = 0;
+
+ for (dirp = dt_list_next(&dtp->dt_lib_path); dirp != NULL;
+ dirp = dt_list_next(dirp)) {
+ (void) snprintf(lib, len, "%s/%s", dirp->dir_path, lname);
+
+ if (stat(lib, &sbuf) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ xyerror(D_PRAGMA_DEPEND,
+ "failed to find dependency in libpath: %s", lname);
+}
+
+/*
+ * The #pragma depends_on directive can be used to express a dependency on a
+ * module, provider or library which if not present will cause processing to
+ * abort.
+ */
+static void
+dt_pragma_depends(const char *prname, dt_node_t *cnp)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ dt_node_t *nnp = cnp ? cnp->dn_list : NULL;
+ int found;
+ dt_lib_depend_t *dld;
+ char lib[MAXPATHLEN];
+ size_t plen;
+ char *provs, *cpy, *tok;
+
+ if (cnp == NULL || nnp == NULL ||
+ cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) {
+ xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
+ "<class> <name>\n", prname);
+ }
+
+ if (strcmp(cnp->dn_string, "provider") == 0) {
+ /*
+ * First try to get the provider list using the
+ * debug.dtrace.providers sysctl, since that'll work even if
+ * we're not running as root.
+ */
+ provs = NULL;
+ if (sysctlbyname("debug.dtrace.providers", NULL, &plen, NULL, 0) ||
+ ((provs = dt_alloc(dtp, plen)) == NULL) ||
+ sysctlbyname("debug.dtrace.providers", provs, &plen, NULL, 0))
+ found = dt_provider_lookup(dtp, nnp->dn_string) != NULL;
+ else {
+ found = B_FALSE;
+ for (cpy = provs; (tok = strsep(&cpy, " ")) != NULL; )
+ if (strcmp(tok, nnp->dn_string) == 0) {
+ found = B_TRUE;
+ break;
+ }
+ if (found == B_FALSE)
+ found = dt_provider_lookup(dtp,
+ nnp->dn_string) != NULL;
+ }
+ if (provs != NULL)
+ dt_free(dtp, provs);
+ } else if (strcmp(cnp->dn_string, "module") == 0) {
+ dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string);
+ found = mp != NULL && dt_module_getctf(dtp, mp) != NULL;
+#ifdef __FreeBSD__
+ if (!found) {
+ dt_kmodule_t *dkmp = dt_kmodule_lookup(dtp,
+ nnp->dn_string);
+ found = dkmp != NULL &&
+ dt_module_getctf(dtp, dkmp->dkm_module) != NULL;
+ }
+#endif
+ } else if (strcmp(cnp->dn_string, "library") == 0) {
+ if (yypcb->pcb_cflags & DTRACE_C_CTL) {
+ assert(dtp->dt_filetag != NULL);
+
+ dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
+ sizeof (lib));
+
+ dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
+ dtp->dt_filetag);
+ assert(dld != NULL);
+
+ if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies,
+ lib)) != 0) {
+ xyerror(D_PRAGMA_DEPEND,
+ "failed to add dependency %s:%s\n", lib,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+ } else {
+ /*
+ * By this point we have already performed a topological
+ * sort of the dependencies; we process this directive
+ * as satisfied as long as the dependency was properly
+ * loaded.
+ */
+ if (dtp->dt_filetag == NULL)
+ xyerror(D_PRAGMA_DEPEND, "main program may "
+ "not explicitly depend on a library");
+
+ dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
+ dtp->dt_filetag);
+ assert(dld != NULL);
+
+ dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
+ sizeof (lib));
+ dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted,
+ lib);
+ assert(dld != NULL);
+
+ if (!dld->dtld_loaded)
+ xyerror(D_PRAGMA_DEPEND, "program requires "
+ "library \"%s\" which failed to load",
+ lib);
+ }
+
+ found = B_TRUE;
+ } else {
+ xyerror(D_PRAGMA_INVAL, "invalid class %s "
+ "specified by #pragma %s\n", cnp->dn_string, prname);
+ }
+
+ if (!found) {
+ xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n",
+ cnp->dn_string, nnp->dn_string);
+ }
+}
+
+/*
+ * The #pragma error directive can be followed by any list of tokens, which we
+ * just concatenate and print as part of our error message.
+ */
+static void
+dt_pragma_error(const char *prname, dt_node_t *dnp)
+{
+ dt_node_t *enp;
+ size_t n = 0;
+ char *s;
+
+ for (enp = dnp; enp != NULL; enp = enp->dn_list) {
+ if (enp->dn_kind == DT_NODE_IDENT ||
+ enp->dn_kind == DT_NODE_STRING)
+ n += strlen(enp->dn_string) + 1;
+ }
+
+ s = alloca(n + 1);
+ s[0] = '\0';
+
+ for (enp = dnp; enp != NULL; enp = enp->dn_list) {
+ if (enp->dn_kind == DT_NODE_IDENT ||
+ enp->dn_kind == DT_NODE_STRING) {
+ (void) strcat(s, enp->dn_string);
+ (void) strcat(s, " ");
+ }
+ }
+
+ xyerror(D_PRAGERR, "#%s: %s\n", prname, s);
+}
+
+/*ARGSUSED*/
+static void
+dt_pragma_ident(const char *prname, dt_node_t *dnp)
+{
+ /* ignore any #ident or #pragma ident lines */
+}
+
+static void
+dt_pragma_option(const char *prname, dt_node_t *dnp)
+{
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+ char *opt, *val;
+
+ if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT) {
+ xyerror(D_PRAGMA_MALFORM,
+ "malformed #pragma %s <option>=<val>\n", prname);
+ }
+
+ if (dnp->dn_list != NULL) {
+ xyerror(D_PRAGMA_MALFORM,
+ "superfluous arguments specified for #pragma %s\n", prname);
+ }
+
+ opt = alloca(strlen(dnp->dn_string) + 1);
+ (void) strcpy(opt, dnp->dn_string);
+
+ if ((val = strchr(opt, '=')) != NULL)
+ *val++ = '\0';
+
+ if (dtrace_setopt(dtp, opt, val) == -1) {
+ if (val == NULL) {
+ xyerror(D_PRAGMA_OPTSET,
+ "failed to set option '%s': %s\n", opt,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ } else {
+ xyerror(D_PRAGMA_OPTSET,
+ "failed to set option '%s' to '%s': %s\n",
+ opt, val, dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
+ }
+}
+
+/*
+ * The #line directive is used to reset the input line number and to optionally
+ * note the file name for use in error messages. Sun cpp(1) also produces a
+ * third integer token after the filename which is one of the following:
+ *
+ * 0 - line change has nothing to do with an #include file
+ * 1 - line change because we just entered a #include file
+ * 2 - line change because we just exited a #include file
+ *
+ * We use these state tokens to adjust pcb_idepth, which in turn controls
+ * whether type lookups access the global type space or not.
+ */
+static void
+dt_pragma_line(const char *prname, dt_node_t *dnp)
+{
+ dt_node_t *fnp = dnp ? dnp->dn_list : NULL;
+ dt_node_t *inp = fnp ? fnp->dn_list : NULL;
+
+ if ((dnp == NULL || dnp->dn_kind != DT_NODE_INT) ||
+ (fnp != NULL && fnp->dn_kind != DT_NODE_STRING) ||
+ (inp != NULL && inp->dn_kind != DT_NODE_INT)) {
+ xyerror(D_PRAGMA_MALFORM, "malformed #%s "
+ "<line> [ [\"file\"] state ]\n", prname);
+ }
+
+ /*
+ * If a file is specified, free any old pcb_filetag and swap fnp's
+ * dn_string into pcb_filetag as the new filename for error messages.
+ */
+ if (fnp != NULL) {
+ if (yypcb->pcb_filetag != NULL)
+ free(yypcb->pcb_filetag);
+
+ /*
+ * This is not pretty, but is a necessary evil until we either
+ * write "dpp" or get a useful standalone cpp from DevPro. If
+ * the filename begins with /dev/fd, we know it's the master
+ * input file (see dt_preproc() in dt_cc.c), so just clear the
+ * dt_filetag pointer so error messages refer to the main file.
+ */
+ if (strncmp(fnp->dn_string, "/dev/fd/", 8) != 0) {
+ yypcb->pcb_filetag = fnp->dn_string;
+ fnp->dn_string = NULL;
+ } else
+ yypcb->pcb_filetag = NULL;
+ }
+
+ if (inp != NULL) {
+ if (inp->dn_value == 1)
+ yypcb->pcb_idepth++;
+ else if (inp->dn_value == 2 && yypcb->pcb_idepth != 0)
+ yypcb->pcb_idepth--;
+ }
+
+ yylineno = dnp->dn_value;
+}
+
+/*
+ * D compiler pragma types range from control directives to common pragmas to
+ * D custom pragmas, in order of specificity. Similar to gcc, we use #pragma D
+ * as a special prefix for our pragmas so they can be used in mixed headers.
+ */
+#define DT_PRAGMA_DIR 0 /* pragma directive may be used after naked # */
+#define DT_PRAGMA_SUB 1 /* pragma directive may be used after #pragma */
+#define DT_PRAGMA_DCP 2 /* pragma may only be used after #pragma D */
+
+static const struct dt_pragmadesc {
+ const char *dpd_name;
+ void (*dpd_func)(const char *, dt_node_t *);
+ int dpd_kind;
+} dt_pragmas[] = {
+ { "attributes", dt_pragma_attributes, DT_PRAGMA_DCP },
+ { "binding", dt_pragma_binding, DT_PRAGMA_DCP },
+ { "depends_on", dt_pragma_depends, DT_PRAGMA_DCP },
+ { "error", dt_pragma_error, DT_PRAGMA_DIR },
+ { "ident", dt_pragma_ident, DT_PRAGMA_DIR },
+ { "line", dt_pragma_line, DT_PRAGMA_DIR },
+ { "option", dt_pragma_option, DT_PRAGMA_DCP },
+ { NULL, NULL }
+};
+
+/*
+ * Process a control line #directive by looking up the directive name in our
+ * lookup table and invoking the corresponding function with the token list.
+ * According to K&R[A12.9], we silently ignore null directive lines.
+ */
+void
+dt_pragma(dt_node_t *pnp)
+{
+ const struct dt_pragmadesc *dpd;
+ dt_node_t *dnp;
+ int kind = DT_PRAGMA_DIR;
+
+ for (dnp = pnp; dnp != NULL; dnp = dnp->dn_list) {
+ if (dnp->dn_kind == DT_NODE_INT) {
+ dt_pragma_line("line", dnp);
+ break;
+ }
+
+ if (dnp->dn_kind != DT_NODE_IDENT)
+ xyerror(D_PRAGCTL_INVAL, "invalid control directive\n");
+
+ if (kind == DT_PRAGMA_DIR &&
+ strcmp(dnp->dn_string, "pragma") == 0) {
+ kind = DT_PRAGMA_SUB;
+ continue;
+ }
+
+ if (kind == DT_PRAGMA_SUB &&
+ strcmp(dnp->dn_string, "D") == 0) {
+ kind = DT_PRAGMA_DCP;
+ continue;
+ }
+
+ for (dpd = dt_pragmas; dpd->dpd_name != NULL; dpd++) {
+ if (dpd->dpd_kind <= kind &&
+ strcmp(dpd->dpd_name, dnp->dn_string) == 0)
+ break;
+ }
+
+ yylineno--; /* since we've already seen \n */
+
+ if (dpd->dpd_name != NULL) {
+ dpd->dpd_func(dpd->dpd_name, dnp->dn_list);
+ yylineno++;
+ break;
+ }
+
+ switch (kind) {
+ case DT_PRAGMA_DIR:
+ xyerror(D_PRAGCTL_INVAL, "invalid control directive: "
+ "#%s\n", dnp->dn_string);
+ /*NOTREACHED*/
+ case DT_PRAGMA_SUB:
+ break; /* K&R[A12.8] says to ignore unknown pragmas */
+ case DT_PRAGMA_DCP:
+ default:
+ xyerror(D_PRAGMA_INVAL, "invalid D pragma: %s\n",
+ dnp->dn_string);
+ }
+
+ yylineno++;
+ break;
+ }
+
+ dt_node_list_free(&pnp);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
new file mode 100644
index 000000000000..0a3a10a76954
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
@@ -0,0 +1,706 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * DTrace print() action
+ *
+ * This file contains the post-processing logic for the print() action. The
+ * print action behaves identically to trace() in that it generates a
+ * DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type
+ * string stored in the DOF string table (similar to printf formats). We
+ * take the result of the trace action and post-process it in the fashion of
+ * MDB's ::print dcmd.
+ *
+ * This implementation differs from MDB's in the following ways:
+ *
+ * - We do not expose any options or flags. The behavior of print() is
+ * equivalent to "::print -tn".
+ *
+ * - MDB will display "holes" in structures (unused padding between
+ * members).
+ *
+ * - When printing arrays of structures, MDB will leave a trailing ','
+ * after the last element.
+ *
+ * - MDB will print time_t types as date and time.
+ *
+ * - MDB will detect when an enum is actually the OR of several flags,
+ * and print it out with the constituent flags separated.
+ *
+ * - For large arrays, MDB will print the first few members and then
+ * print a "..." continuation line.
+ *
+ * - MDB will break and wrap arrays at 80 columns.
+ *
+ * - MDB prints out floats and doubles by hand, as it must run in kmdb
+ * context. We're able to leverage the printf() format strings,
+ * but the result is a slightly different format.
+ */
+
+#include <sys/sysmacros.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <dt_module.h>
+#include <dt_printf.h>
+#include <dt_string.h>
+#include <dt_impl.h>
+
+/* determines whether the given integer CTF encoding is a character */
+#define CTF_IS_CHAR(e) \
+ (((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
+ (CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
+/* determines whether the given CTF kind is a struct or union */
+#define CTF_IS_STRUCTLIKE(k) \
+ ((k) == CTF_K_STRUCT || (k) == CTF_K_UNION)
+
+/*
+ * Print structure passed down recursively through printing algorithm.
+ */
+typedef struct dt_printarg {
+ dtrace_hdl_t *pa_dtp; /* libdtrace handle */
+ caddr_t pa_addr; /* base address of trace data */
+ ctf_file_t *pa_ctfp; /* CTF container */
+ int pa_depth; /* member depth */
+ int pa_nest; /* nested array depth */
+ FILE *pa_file; /* output file */
+} dt_printarg_t;
+
+static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *);
+
+/*
+ * Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it
+ * can't resolve the type.
+ */
+static void
+dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen)
+{
+ if (ctf_type_name(ctfp, id, buf, buflen) == NULL)
+ (void) snprintf(buf, buflen, "<%ld>", id);
+}
+
+/*
+ * Print any necessary trailing braces for structures or unions. We don't get
+ * invoked when a struct or union ends, so we infer the need to print braces
+ * based on the depth the last time we printed something and the new depth.
+ */
+static void
+dt_print_trailing_braces(dt_printarg_t *pap, int depth)
+{
+ int d;
+
+ for (d = pap->pa_depth; d > depth; d--) {
+ (void) fprintf(pap->pa_file, "%*s}%s",
+ (d + pap->pa_nest - 1) * 4, "",
+ d == depth + 1 ? "" : "\n");
+ }
+}
+
+/*
+ * Print the appropriate amount of indentation given the current depth and
+ * array nesting.
+ */
+static void
+dt_print_indent(dt_printarg_t *pap)
+{
+ (void) fprintf(pap->pa_file, "%*s",
+ (pap->pa_depth + pap->pa_nest) * 4, "");
+}
+
+/*
+ * Print a bitfield. It's worth noting that the D compiler support for
+ * bitfields is currently broken; printing "D`user_desc_t" (pulled in by the
+ * various D provider files) will produce incorrect results compared to
+ * "genunix`user_desc_t".
+ */
+static void
+print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)
+{
+ FILE *fp = pap->pa_file;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+ uint64_t mask = (1ULL << ep->cte_bits) - 1;
+ uint64_t value = 0;
+ size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
+ uint8_t *buf = (uint8_t *)&value;
+ uint8_t shift;
+
+ /*
+ * On big-endian machines, we need to adjust the buf pointer to refer
+ * to the lowest 'size' bytes in 'value', and we need to shift based on
+ * the offset from the end of the data, not the offset of the start.
+ */
+#if BYTE_ORDER == _BIG_ENDIAN
+ buf += sizeof (value) - size;
+ off += ep->cte_bits;
+#endif
+ bcopy(addr, buf, size);
+ shift = off % NBBY;
+
+ /*
+ * Offsets are counted from opposite ends on little- and
+ * big-endian machines.
+ */
+#if BYTE_ORDER == _BIG_ENDIAN
+ shift = NBBY - shift;
+#endif
+
+ /*
+ * If the bits we want do not begin on a byte boundary, shift the data
+ * right so that the value is in the lowest 'cte_bits' of 'value'.
+ */
+ if (off % NBBY != 0)
+ value >>= shift;
+ value &= mask;
+
+ (void) fprintf(fp, "%#llx", (u_longlong_t)value);
+}
+
+/*
+ * Dump the contents of memory as a fixed-size integer in hex.
+ */
+static void
+dt_print_hex(FILE *fp, caddr_t addr, size_t size)
+{
+ switch (size) {
+ case sizeof (uint8_t):
+ (void) fprintf(fp, "%#x", *(uint8_t *)addr);
+ break;
+ case sizeof (uint16_t):
+ /* LINTED - alignment */
+ (void) fprintf(fp, "%#x", *(uint16_t *)addr);
+ break;
+ case sizeof (uint32_t):
+ /* LINTED - alignment */
+ (void) fprintf(fp, "%#x", *(uint32_t *)addr);
+ break;
+ case sizeof (uint64_t):
+ (void) fprintf(fp, "%#llx",
+ /* LINTED - alignment */
+ (unsigned long long)*(uint64_t *)addr);
+ break;
+ default:
+ (void) fprintf(fp, "<invalid size %u>", (uint_t)size);
+ }
+}
+
+/*
+ * Print an integer type. Before dumping the contents via dt_print_hex(), we
+ * first check the encoding to see if it's part of a bitfield or a character.
+ */
+static void
+dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ ctf_encoding_t e;
+ size_t size;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+
+ if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) {
+ (void) fprintf(fp, "<unknown encoding>");
+ return;
+ }
+
+ /*
+ * This comes from MDB - it's not clear under what circumstances this
+ * would be found.
+ */
+ if (e.cte_format & CTF_INT_VARARGS) {
+ (void) fprintf(fp, "...");
+ return;
+ }
+
+ /*
+ * We print this as a bitfield if the bit encoding indicates it's not
+ * an even power of two byte size, or is larger than 8 bytes.
+ */
+ size = e.cte_bits / NBBY;
+ if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) {
+ print_bitfield(pap, off, &e);
+ return;
+ }
+
+ /*
+ * If this is a character, print it out as such.
+ */
+ if (CTF_IS_CHAR(e)) {
+ char c = *(char *)addr;
+ if (isprint(c))
+ (void) fprintf(fp, "'%c'", c);
+ else if (c == 0)
+ (void) fprintf(fp, "'\\0'");
+ else
+ (void) fprintf(fp, "'\\%03o'", c);
+ return;
+ }
+
+ dt_print_hex(fp, addr, size);
+}
+
+/*
+ * Print a floating point (float, double, long double) value.
+ */
+/* ARGSUSED */
+static void
+dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ ctf_encoding_t e;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+
+ if (ctf_type_encoding(ctfp, base, &e) == 0) {
+ if (e.cte_format == CTF_FP_SINGLE &&
+ e.cte_bits == sizeof (float) * NBBY) {
+ /* LINTED - alignment */
+ (void) fprintf(fp, "%+.7e", *((float *)addr));
+ } else if (e.cte_format == CTF_FP_DOUBLE &&
+ e.cte_bits == sizeof (double) * NBBY) {
+ /* LINTED - alignment */
+ (void) fprintf(fp, "%+.7e", *((double *)addr));
+ } else if (e.cte_format == CTF_FP_LDOUBLE &&
+ e.cte_bits == sizeof (long double) * NBBY) {
+ /* LINTED - alignment */
+ (void) fprintf(fp, "%+.16LE", *((long double *)addr));
+ } else {
+ (void) fprintf(fp, "<unknown encoding>");
+ }
+ }
+}
+
+/*
+ * A pointer is generally printed as a fixed-size integer. If we have a
+ * function pointer, we try to look up its name.
+ */
+static void
+dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+ size_t size = ctf_type_size(ctfp, base);
+ ctf_id_t bid = ctf_type_reference(ctfp, base);
+ uint64_t pc;
+ dtrace_syminfo_t dts;
+ GElf_Sym sym;
+
+ if (bid == CTF_ERR || ctf_type_kind(ctfp, bid) != CTF_K_FUNCTION) {
+ dt_print_hex(fp, addr, size);
+ } else {
+ /* LINTED - alignment */
+ pc = *((uint64_t *)addr);
+ if (dtrace_lookup_by_addr(pap->pa_dtp, pc, &sym, &dts) != 0) {
+ dt_print_hex(fp, addr, size);
+ } else {
+ (void) fprintf(fp, "%s`%s", dts.dts_object,
+ dts.dts_name);
+ }
+ }
+}
+
+/*
+ * Print out an array. This is somewhat complex, as we must manually visit
+ * each member, and recursively invoke ctf_type_visit() for each member. If
+ * the members are non-structs, then we print them out directly:
+ *
+ * [ 0x14, 0x2e, 0 ]
+ *
+ * If they are structs, then we print out the necessary leading and trailing
+ * braces, to end up with:
+ *
+ * [
+ * type {
+ * ...
+ * },
+ * type {
+ * ...
+ * }
+ * ]
+ *
+ * We also use a heuristic to detect whether the array looks like a character
+ * array. If the encoding indicates it's a character, and we have all
+ * printable characters followed by a null byte, then we display it as a
+ * string:
+ *
+ * [ "string" ]
+ */
+static void
+dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+ ctf_arinfo_t car;
+ ssize_t eltsize;
+ ctf_encoding_t e;
+ int i;
+ boolean_t isstring;
+ int kind;
+ ctf_id_t rtype;
+
+ if (ctf_array_info(ctfp, base, &car) == CTF_ERR) {
+ (void) fprintf(fp, "%p", (void *)addr);
+ return;
+ }
+
+ if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 ||
+ (rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR ||
+ (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) {
+ (void) fprintf(fp, "<invalid type %lu>", car.ctr_contents);
+ return;
+ }
+
+ /* see if this looks like a string */
+ isstring = B_FALSE;
+ if (kind == CTF_K_INTEGER &&
+ ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) {
+ char c;
+ for (i = 0; i < car.ctr_nelems; i++) {
+ c = *((char *)addr + eltsize * i);
+ if (!isprint(c) || c == '\0')
+ break;
+ }
+
+ if (i != car.ctr_nelems && c == '\0')
+ isstring = B_TRUE;
+ }
+
+ /*
+ * As a slight aesthetic optimization, if we are a top-level type, then
+ * don't bother printing out the brackets. This lets print("foo") look
+ * like:
+ *
+ * string "foo"
+ *
+ * As D will internally represent this as a char[256] array.
+ */
+ if (!isstring || pap->pa_depth != 0)
+ (void) fprintf(fp, "[ ");
+
+ if (isstring)
+ (void) fprintf(fp, "\"");
+
+ for (i = 0; i < car.ctr_nelems; i++) {
+ if (isstring) {
+ char c = *((char *)addr + eltsize * i);
+ if (c == '\0')
+ break;
+ (void) fprintf(fp, "%c", c);
+ } else {
+ /*
+ * Recursively invoke ctf_type_visit() on each member.
+ * We setup a new printarg struct with 'pa_nest' set to
+ * indicate that we are within a nested array.
+ */
+ dt_printarg_t pa = *pap;
+ pa.pa_nest += pap->pa_depth + 1;
+ pa.pa_depth = 0;
+ pa.pa_addr = addr + eltsize * i;
+ (void) ctf_type_visit(ctfp, car.ctr_contents,
+ dt_print_member, &pa);
+
+ dt_print_trailing_braces(&pa, 0);
+ if (i != car.ctr_nelems - 1)
+ (void) fprintf(fp, ", ");
+ else if (CTF_IS_STRUCTLIKE(kind))
+ (void) fprintf(fp, "\n");
+ }
+ }
+
+ if (isstring)
+ (void) fprintf(fp, "\"");
+
+ if (!isstring || pap->pa_depth != 0) {
+ if (CTF_IS_STRUCTLIKE(kind))
+ dt_print_indent(pap);
+ else
+ (void) fprintf(fp, " ");
+ (void) fprintf(fp, "]");
+ }
+}
+
+/*
+ * This isued by both structs and unions to print the leading brace.
+ */
+/* ARGSUSED */
+static void
+dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap)
+{
+ (void) fprintf(pap->pa_file, "{");
+}
+
+/*
+ * For enums, we try to print the enum name, and fall back to the value if it
+ * can't be determined. We do not do any fancy flag processing like mdb.
+ */
+/* ARGSUSED */
+static void
+dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ const char *ename;
+ ssize_t size;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+ int value = 0;
+
+ /*
+ * The C standard says that an enum will be at most the sizeof (int).
+ * But if all the values are less than that, the compiler can use a
+ * smaller size. Thanks standards.
+ */
+ size = ctf_type_size(ctfp, base);
+ switch (size) {
+ case sizeof (uint8_t):
+ value = *(uint8_t *)addr;
+ break;
+ case sizeof (uint16_t):
+ value = *(uint16_t *)addr;
+ break;
+ case sizeof (int32_t):
+ value = *(int32_t *)addr;
+ break;
+ default:
+ (void) fprintf(fp, "<invalid enum size %u>", (uint_t)size);
+ return;
+ }
+
+ if ((ename = ctf_enum_name(ctfp, base, value)) != NULL)
+ (void) fprintf(fp, "%s", ename);
+ else
+ (void) fprintf(fp, "%d", value);
+}
+
+/*
+ * Forward declaration. There's not much to do here without the complete
+ * type information, so just print out this fact and drive on.
+ */
+/* ARGSUSED */
+static void
+dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ (void) fprintf(pap->pa_file, "<forward decl>");
+}
+
+typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *);
+
+static dt_printarg_f *const dt_printfuncs[] = {
+ dt_print_int, /* CTF_K_INTEGER */
+ dt_print_float, /* CTF_K_FLOAT */
+ dt_print_ptr, /* CTF_K_POINTER */
+ dt_print_array, /* CTF_K_ARRAY */
+ dt_print_ptr, /* CTF_K_FUNCTION */
+ dt_print_structlike, /* CTF_K_STRUCT */
+ dt_print_structlike, /* CTF_K_UNION */
+ dt_print_enum, /* CTF_K_ENUM */
+ dt_print_tag /* CTF_K_FORWARD */
+};
+
+/*
+ * Print one member of a structure. This callback is invoked from
+ * ctf_type_visit() recursively.
+ */
+static int
+dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth,
+ void *data)
+{
+ char type[DT_TYPE_NAMELEN];
+ int kind;
+ dt_printarg_t *pap = data;
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ boolean_t arraymember;
+ boolean_t brief;
+ ctf_encoding_t e;
+ ctf_id_t rtype;
+
+ dt_print_trailing_braces(pap, depth);
+ /*
+ * dt_print_trailing_braces() doesn't include the trailing newline; add
+ * it here if necessary.
+ */
+ if (depth < pap->pa_depth)
+ (void) fprintf(fp, "\n");
+ pap->pa_depth = depth;
+
+ if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||
+ (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||
+ kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {
+ dt_print_indent(pap);
+ (void) fprintf(fp, "%s = <invalid type %lu>", name, id);
+ return (0);
+ }
+
+ dt_print_type_name(ctfp, id, type, sizeof (type));
+
+ arraymember = (pap->pa_nest != 0 && depth == 0);
+ brief = (arraymember && !CTF_IS_STRUCTLIKE(kind));
+
+ if (!brief) {
+ /*
+ * If this is a direct array member and a struct (otherwise
+ * brief would be true), then print a trailing newline, as the
+ * array printing code doesn't include it because it might be a
+ * simple type.
+ */
+ if (arraymember)
+ (void) fprintf(fp, "\n");
+ dt_print_indent(pap);
+
+ /* always print the type */
+ (void) fprintf(fp, "%s", type);
+ if (name[0] != '\0') {
+ /*
+ * For aesthetics, we don't include a space between the
+ * type name and member name if the type is a pointer.
+ * This will give us "void *foo =" instead of "void *
+ * foo =". Unions also have the odd behavior that the
+ * type name is returned as "union ", with a trailing
+ * space, so we also avoid printing a space if the type
+ * name already ends with a space.
+ */
+ if (type[strlen(type) - 1] != '*' &&
+ type[strlen(type) -1] != ' ') {
+ (void) fprintf(fp, " ");
+ }
+ (void) fprintf(fp, "%s", name);
+
+ /*
+ * If this looks like a bitfield, or is an integer not
+ * aligned on a byte boundary, print the number of
+ * bits after the name.
+ */
+ if (kind == CTF_K_INTEGER &&
+ ctf_type_encoding(ctfp, id, &e) == 0) {
+ ulong_t bits = e.cte_bits;
+ ulong_t size = bits / NBBY;
+
+ if (bits % NBBY != 0 ||
+ off % NBBY != 0 ||
+ size > 8 ||
+ size != ctf_type_size(ctfp, id)) {
+ (void) fprintf(fp, " :%lu", bits);
+ }
+ }
+
+ (void) fprintf(fp, " =");
+ }
+ (void) fprintf(fp, " ");
+ }
+
+ dt_printfuncs[kind - 1](rtype, off, pap);
+
+ /* direct simple array members are not separated by newlines */
+ if (!brief)
+ (void) fprintf(fp, "\n");
+
+ return (0);
+}
+
+/*
+ * Main print function invoked by dt_consume_cpu().
+ */
+int
+dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
+ caddr_t addr, size_t len)
+{
+ const char *s;
+ char *object;
+ dt_printarg_t pa;
+ ctf_id_t id;
+ dt_module_t *dmp;
+ ctf_file_t *ctfp;
+ int libid;
+
+ /*
+ * Split the fully-qualified type ID (module`id). This should
+ * always be the format, but if for some reason we don't find the
+ * expected value, return 0 to fall back to the generic trace()
+ * behavior. In the case of userland CTF modules this will actually be
+ * of the format (module`lib`id). This is due to the fact that those
+ * modules have multiple CTF containers which `lib` identifies.
+ */
+ for (s = typename; *s != '\0' && *s != '`'; s++)
+ ;
+
+ if (*s != '`')
+ return (0);
+
+ object = alloca(s - typename + 1);
+ bcopy(typename, object, s - typename);
+ object[s - typename] = '\0';
+ dmp = dt_module_lookup_by_name(dtp, object);
+ if (dmp == NULL)
+ return (0);
+
+ if (dmp->dm_pid != 0) {
+ libid = atoi(s + 1);
+ s = strchr(s + 1, '`');
+ if (s == NULL || libid > dmp->dm_nctflibs)
+ return (0);
+ ctfp = dmp->dm_libctfp[libid];
+ } else {
+ ctfp = dt_module_getctf(dtp, dmp);
+ }
+
+ id = atoi(s + 1);
+
+ /*
+ * Try to get the CTF kind for this id. If something has gone horribly
+ * wrong and we can't resolve the ID, bail out and let trace() do the
+ * work.
+ */
+ if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR)
+ return (0);
+
+ /* setup the print structure and kick off the main print routine */
+ pa.pa_dtp = dtp;
+ pa.pa_addr = addr;
+ pa.pa_ctfp = ctfp;
+ pa.pa_nest = 0;
+ pa.pa_depth = 0;
+ pa.pa_file = fp;
+ (void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);
+
+ dt_print_trailing_braces(&pa, 0);
+
+ return (len);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
new file mode 100644
index 000000000000..f7b4684b01d0
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
@@ -0,0 +1,2083 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifdef illumos
+#include <sys/sysmacros.h>
+#else
+#define ABS(a) ((a) < 0 ? -(a) : (a))
+#endif
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <dt_printf.h>
+#include <dt_string.h>
+#include <dt_impl.h>
+
+/*ARGSUSED*/
+static int
+pfcheck_addr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_kaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp) ||
+ dt_node_is_symaddr(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_uaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ dtrace_hdl_t *dtp = pfv->pfv_dtp;
+ dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
+
+ if (dt_node_is_usymaddr(dnp))
+ return (1);
+
+ if (idp == NULL || idp->di_id == 0)
+ return (0);
+
+ return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_stack(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (dt_node_is_stack(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_time(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (dt_node_is_integer(dnp) &&
+ dt_node_type_size(dnp) == sizeof (uint64_t));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_str(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ ctf_file_t *ctfp;
+ ctf_encoding_t e;
+ ctf_arinfo_t r;
+ ctf_id_t base;
+ uint_t kind;
+
+ if (dt_node_is_string(dnp))
+ return (1);
+
+ ctfp = dnp->dn_ctfp;
+ base = ctf_type_resolve(ctfp, dnp->dn_type);
+ kind = ctf_type_kind(ctfp, base);
+
+ return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 &&
+ (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR &&
+ ctf_type_encoding(ctfp, base, &e) == 0 && IS_CHAR(e));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_wstr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ ctf_file_t *ctfp = dnp->dn_ctfp;
+ ctf_id_t base = ctf_type_resolve(ctfp, dnp->dn_type);
+ uint_t kind = ctf_type_kind(ctfp, base);
+
+ ctf_encoding_t e;
+ ctf_arinfo_t r;
+
+ return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 &&
+ (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR &&
+ ctf_type_kind(ctfp, base) == CTF_K_INTEGER &&
+ ctf_type_encoding(ctfp, base, &e) == 0 && e.cte_bits == 32);
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_csi(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (dt_node_is_integer(dnp) &&
+ dt_node_type_size(dnp) <= sizeof (int));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_fp(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (dt_node_is_float(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_xint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (dt_node_is_integer(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_dint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ if (dnp->dn_flags & DT_NF_SIGNED)
+ pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'i';
+ else
+ pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'u';
+
+ return (dt_node_is_integer(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_xshort(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ ctf_file_t *ctfp = dnp->dn_ctfp;
+ ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type);
+ char n[DT_TYPE_NAMELEN];
+
+ return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && (
+ strcmp(n, "short") == 0 || strcmp(n, "signed short") == 0 ||
+ strcmp(n, "unsigned short") == 0));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_xlong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ ctf_file_t *ctfp = dnp->dn_ctfp;
+ ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type);
+ char n[DT_TYPE_NAMELEN];
+
+ return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && (
+ strcmp(n, "long") == 0 || strcmp(n, "signed long") == 0 ||
+ strcmp(n, "unsigned long") == 0));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_xlonglong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ ctf_file_t *ctfp = dnp->dn_ctfp;
+ ctf_id_t type = dnp->dn_type;
+ char n[DT_TYPE_NAMELEN];
+
+ if (ctf_type_name(ctfp, ctf_type_resolve(ctfp, type), n,
+ sizeof (n)) != NULL && (strcmp(n, "long long") == 0 ||
+ strcmp(n, "signed long long") == 0 ||
+ strcmp(n, "unsigned long long") == 0))
+ return (1);
+
+ /*
+ * If the type used for %llx or %llX is not an [unsigned] long long, we
+ * also permit it to be a [u]int64_t or any typedef thereof. We know
+ * that these typedefs are guaranteed to work with %ll[xX] in either
+ * compilation environment even though they alias to "long" in LP64.
+ */
+ while (ctf_type_kind(ctfp, type) == CTF_K_TYPEDEF) {
+ if (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL &&
+ (strcmp(n, "int64_t") == 0 || strcmp(n, "uint64_t") == 0))
+ return (1);
+
+ type = ctf_type_reference(ctfp, type);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_type(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (ctf_type_compat(dnp->dn_ctfp, ctf_type_resolve(dnp->dn_ctfp,
+ dnp->dn_type), pfd->pfd_conv->pfc_dctfp, pfd->pfd_conv->pfc_dtype));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_sint(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t unormal)
+{
+ int64_t normal = (int64_t)unormal;
+ int32_t n = (int32_t)normal;
+
+ switch (size) {
+ case sizeof (int8_t):
+ return (dt_printf(dtp, fp, format,
+ (int32_t)*((int8_t *)addr) / n));
+ case sizeof (int16_t):
+ return (dt_printf(dtp, fp, format,
+ (int32_t)*((int16_t *)addr) / n));
+ case sizeof (int32_t):
+ return (dt_printf(dtp, fp, format,
+ *((int32_t *)addr) / n));
+ case sizeof (int64_t):
+ return (dt_printf(dtp, fp, format,
+ *((int64_t *)addr) / normal));
+ default:
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+ }
+}
+
+/*ARGSUSED*/
+static int
+pfprint_uint(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ uint32_t n = (uint32_t)normal;
+
+ switch (size) {
+ case sizeof (uint8_t):
+ return (dt_printf(dtp, fp, format,
+ (uint32_t)*((uint8_t *)addr) / n));
+ case sizeof (uint16_t):
+ return (dt_printf(dtp, fp, format,
+ (uint32_t)*((uint16_t *)addr) / n));
+ case sizeof (uint32_t):
+ return (dt_printf(dtp, fp, format,
+ *((uint32_t *)addr) / n));
+ case sizeof (uint64_t):
+ return (dt_printf(dtp, fp, format,
+ *((uint64_t *)addr) / normal));
+ default:
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+ }
+}
+
+static int
+pfprint_dint(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ if (pfd->pfd_flags & DT_PFCONV_SIGNED)
+ return (pfprint_sint(dtp, fp, format, pfd, addr, size, normal));
+ else
+ return (pfprint_uint(dtp, fp, format, pfd, addr, size, normal));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_fp(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ double n = (double)normal;
+ long double ldn = (long double)normal;
+
+ switch (size) {
+ case sizeof (float):
+ return (dt_printf(dtp, fp, format,
+ (double)*((float *)addr) / n));
+ case sizeof (double):
+ return (dt_printf(dtp, fp, format,
+ *((double *)addr) / n));
+#if !defined(__arm__) && !defined(__powerpc__) && \
+ !defined(__mips__) && !defined(__riscv)
+ case sizeof (long double):
+ return (dt_printf(dtp, fp, format,
+ *((long double *)addr) / ldn));
+#endif
+ default:
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+ }
+}
+
+/*ARGSUSED*/
+static int
+pfprint_addr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ char *s;
+ int n, len = 256;
+ uint64_t val;
+
+ switch (size) {
+ case sizeof (uint32_t):
+ val = *((uint32_t *)addr);
+ break;
+ case sizeof (uint64_t):
+ val = *((uint64_t *)addr);
+ break;
+ default:
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+ }
+
+ do {
+ n = len;
+ s = alloca(n);
+ } while ((len = dtrace_addr2str(dtp, val, s, n)) > n);
+
+ return (dt_printf(dtp, fp, format, s));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ return (dt_print_mod(dtp, fp, format, (caddr_t)addr));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ return (dt_print_umod(dtp, fp, format, (caddr_t)addr));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_uaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ char *s;
+ int n, len = 256;
+ uint64_t val, pid = 0;
+
+ dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
+
+ switch (size) {
+ case sizeof (uint32_t):
+ val = (u_longlong_t)*((uint32_t *)addr);
+ break;
+ case sizeof (uint64_t):
+ val = (u_longlong_t)*((uint64_t *)addr);
+ break;
+ case sizeof (uint64_t) * 2:
+ pid = ((uint64_t *)(uintptr_t)addr)[0];
+ val = ((uint64_t *)(uintptr_t)addr)[1];
+ break;
+ default:
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+ }
+
+ if (pid == 0 && dtp->dt_vector == NULL && idp != NULL)
+ pid = idp->di_id;
+
+ do {
+ n = len;
+ s = alloca(n);
+ } while ((len = dtrace_uaddr2str(dtp, pid, val, s, n)) > n);
+
+ return (dt_printf(dtp, fp, format, s));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *vaddr, size_t size, uint64_t normal)
+{
+ int width;
+ dtrace_optval_t saved = dtp->dt_options[DTRACEOPT_STACKINDENT];
+ const dtrace_recdesc_t *rec = pfd->pfd_rec;
+ caddr_t addr = (caddr_t)vaddr;
+ int err = 0;
+
+ /*
+ * We have stashed the value of the STACKINDENT option, and we will
+ * now override it for the purposes of formatting the stack. If the
+ * field has been specified as left-aligned (i.e. (%-#), we set the
+ * indentation to be the width. This is a slightly odd semantic, but
+ * it's useful functionality -- and it's slightly odd to begin with to
+ * be using a single format specifier to be formatting multiple lines
+ * of text...
+ */
+ if (pfd->pfd_dynwidth < 0) {
+ assert(pfd->pfd_flags & DT_PFCONV_DYNWIDTH);
+ width = -pfd->pfd_dynwidth;
+ } else if (pfd->pfd_flags & DT_PFCONV_LEFT) {
+ width = pfd->pfd_dynwidth ? pfd->pfd_dynwidth : pfd->pfd_width;
+ } else {
+ width = 0;
+ }
+
+ dtp->dt_options[DTRACEOPT_STACKINDENT] = width;
+
+ switch (rec->dtrd_action) {
+ case DTRACEACT_USTACK:
+ case DTRACEACT_JSTACK:
+ err = dt_print_ustack(dtp, fp, format, addr, rec->dtrd_arg);
+ break;
+
+ case DTRACEACT_STACK:
+ err = dt_print_stack(dtp, fp, format, addr, rec->dtrd_arg,
+ rec->dtrd_size / rec->dtrd_arg);
+ break;
+
+ default:
+ assert(0);
+ }
+
+ dtp->dt_options[DTRACEOPT_STACKINDENT] = saved;
+
+ return (err);
+}
+
+/*ARGSUSED*/
+static int
+pfprint_time(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ char src[32], buf[32], *dst = buf;
+ hrtime_t time = *((uint64_t *)addr);
+ time_t sec = (time_t)(time / NANOSEC);
+ int i;
+
+ /*
+ * ctime(3C) returns a string of the form "Dec 3 17:20:00 1973\n\0".
+ * Below, we turn this into the canonical adb/mdb /[yY] format,
+ * "1973 Dec 3 17:20:00".
+ */
+#ifdef illumos
+ (void) ctime_r(&sec, src, sizeof (src));
+#else
+ (void) ctime_r(&sec, src);
+#endif
+
+ /*
+ * Place the 4-digit year at the head of the string...
+ */
+ for (i = 20; i < 24; i++)
+ *dst++ = src[i];
+
+ /*
+ * ...and follow it with the remainder (month, day, hh:mm:ss).
+ */
+ for (i = 3; i < 19; i++)
+ *dst++ = src[i];
+
+ *dst = '\0';
+ return (dt_printf(dtp, fp, format, buf));
+}
+
+/*
+ * This prints the time in RFC 822 standard form. This is useful for emitting
+ * notions of time that are consumed by standard tools (e.g., as part of an
+ * RSS feed).
+ */
+/*ARGSUSED*/
+static int
+pfprint_time822(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ hrtime_t time = *((uint64_t *)addr);
+ time_t sec = (time_t)(time / NANOSEC);
+ struct tm tm;
+ char buf[64];
+
+ (void) localtime_r(&sec, &tm);
+ (void) strftime(buf, sizeof (buf), "%a, %d %b %G %T %Z", &tm);
+ return (dt_printf(dtp, fp, format, buf));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_port(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ uint16_t port = htons(*((uint16_t *)addr));
+ char buf[256];
+ struct servent *sv, res;
+
+#ifdef illumos
+ if ((sv = getservbyport_r(port, NULL, &res, buf, sizeof (buf))) != NULL)
+#else
+ if (getservbyport_r(port, NULL, &res, buf, sizeof (buf), &sv) > 0)
+#endif
+ return (dt_printf(dtp, fp, format, sv->s_name));
+
+ (void) snprintf(buf, sizeof (buf), "%d", *((uint16_t *)addr));
+ return (dt_printf(dtp, fp, format, buf));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_inetaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ char *s = alloca(size + 1);
+ struct hostent *host, res;
+ char inetaddr[NS_IN6ADDRSZ];
+ char buf[1024];
+ int e;
+
+ bcopy(addr, s, size);
+ s[size] = '\0';
+
+ if (strchr(s, ':') == NULL && inet_pton(AF_INET, s, inetaddr) != -1) {
+#ifdef illumos
+ if ((host = gethostbyaddr_r(inetaddr, NS_INADDRSZ,
+ AF_INET, &res, buf, sizeof (buf), &e)) != NULL)
+#else
+ if (gethostbyaddr_r(inetaddr, NS_INADDRSZ,
+ AF_INET, &res, buf, sizeof (buf), &host, &e) > 0)
+#endif
+ return (dt_printf(dtp, fp, format, host->h_name));
+ } else if (inet_pton(AF_INET6, s, inetaddr) != -1) {
+ if ((host = getipnodebyaddr(inetaddr, NS_IN6ADDRSZ,
+ AF_INET6, &e)) != NULL)
+ return (dt_printf(dtp, fp, format, host->h_name));
+ }
+
+ return (dt_printf(dtp, fp, format, s));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_cstr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ char *s = alloca(size + 1);
+
+ bcopy(addr, s, size);
+ s[size] = '\0';
+ return (dt_printf(dtp, fp, format, s));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_wstr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ wchar_t *ws = alloca(size + sizeof (wchar_t));
+
+ bcopy(addr, ws, size);
+ ws[size / sizeof (wchar_t)] = L'\0';
+ return (dt_printf(dtp, fp, format, ws));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_estr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ char *s;
+ int n;
+
+ if ((s = strchr2esc(addr, size)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ n = dt_printf(dtp, fp, format, s);
+ free(s);
+ return (n);
+}
+
+static int
+pfprint_echr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ char c;
+
+ switch (size) {
+ case sizeof (int8_t):
+ c = *(int8_t *)addr;
+ break;
+ case sizeof (int16_t):
+ c = *(int16_t *)addr;
+ break;
+ case sizeof (int32_t):
+ c = *(int32_t *)addr;
+ break;
+ default:
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+ }
+
+ return (pfprint_estr(dtp, fp, format, pfd, &c, 1, normal));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_pct(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ return (dt_printf(dtp, fp, "%%"));
+}
+
+static const char pfproto_xint[] = "char, short, int, long, or long long";
+static const char pfproto_csi[] = "char, short, or int";
+static const char pfproto_fp[] = "float, double, or long double";
+static const char pfproto_addr[] = "pointer or integer";
+static const char pfproto_uaddr[] =
+ "pointer or integer (with -p/-c) or _usymaddr (without -p/-c)";
+static const char pfproto_cstr[] = "char [] or string (or use stringof)";
+static const char pfproto_wstr[] = "wchar_t []";
+
+/*
+ * Printf format conversion dictionary. This table should match the set of
+ * conversions offered by printf(3C), as well as some additional extensions.
+ * The second parameter is an ASCII string which is either an actual type
+ * name we should look up (if pfcheck_type is specified), or just a descriptive
+ * string of the types expected for use in error messages.
+ */
+static const dt_pfconv_t _dtrace_conversions[] = {
+{ "a", "s", pfproto_addr, pfcheck_kaddr, pfprint_addr },
+{ "A", "s", pfproto_uaddr, pfcheck_uaddr, pfprint_uaddr },
+{ "c", "c", pfproto_csi, pfcheck_csi, pfprint_sint },
+{ "C", "s", pfproto_csi, pfcheck_csi, pfprint_echr },
+{ "d", "d", pfproto_xint, pfcheck_dint, pfprint_dint },
+{ "e", "e", pfproto_fp, pfcheck_fp, pfprint_fp },
+{ "E", "E", pfproto_fp, pfcheck_fp, pfprint_fp },
+{ "f", "f", pfproto_fp, pfcheck_fp, pfprint_fp },
+{ "g", "g", pfproto_fp, pfcheck_fp, pfprint_fp },
+{ "G", "G", pfproto_fp, pfcheck_fp, pfprint_fp },
+{ "hd", "d", "short", pfcheck_type, pfprint_sint },
+{ "hi", "i", "short", pfcheck_type, pfprint_sint },
+{ "ho", "o", "unsigned short", pfcheck_type, pfprint_uint },
+{ "hu", "u", "unsigned short", pfcheck_type, pfprint_uint },
+{ "hx", "x", "short", pfcheck_xshort, pfprint_uint },
+{ "hX", "X", "short", pfcheck_xshort, pfprint_uint },
+{ "i", "i", pfproto_xint, pfcheck_xint, pfprint_sint },
+{ "I", "s", pfproto_cstr, pfcheck_str, pfprint_inetaddr },
+{ "k", "s", "stack", pfcheck_stack, pfprint_stack },
+{ "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */
+{ "ld", "d", "long", pfcheck_type, pfprint_sint },
+{ "li", "i", "long", pfcheck_type, pfprint_sint },
+{ "lo", "o", "unsigned long", pfcheck_type, pfprint_uint },
+{ "lu", "u", "unsigned long", pfcheck_type, pfprint_uint },
+{ "ls", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
+{ "lx", "x", "long", pfcheck_xlong, pfprint_uint },
+{ "lX", "X", "long", pfcheck_xlong, pfprint_uint },
+{ "lld", "d", "long long", pfcheck_type, pfprint_sint },
+{ "lli", "i", "long long", pfcheck_type, pfprint_sint },
+{ "llo", "o", "unsigned long long", pfcheck_type, pfprint_uint },
+{ "llu", "u", "unsigned long long", pfcheck_type, pfprint_uint },
+{ "llx", "x", "long long", pfcheck_xlonglong, pfprint_uint },
+{ "llX", "X", "long long", pfcheck_xlonglong, pfprint_uint },
+{ "Le", "e", "long double", pfcheck_type, pfprint_fp },
+{ "LE", "E", "long double", pfcheck_type, pfprint_fp },
+{ "Lf", "f", "long double", pfcheck_type, pfprint_fp },
+{ "Lg", "g", "long double", pfcheck_type, pfprint_fp },
+{ "LG", "G", "long double", pfcheck_type, pfprint_fp },
+{ "o", "o", pfproto_xint, pfcheck_xint, pfprint_uint },
+{ "p", "x", pfproto_addr, pfcheck_addr, pfprint_uint },
+{ "P", "s", "uint16_t", pfcheck_type, pfprint_port },
+{ "s", "s", "char [] or string (or use stringof)", pfcheck_str, pfprint_cstr },
+{ "S", "s", pfproto_cstr, pfcheck_str, pfprint_estr },
+{ "T", "s", "int64_t", pfcheck_time, pfprint_time822 },
+{ "u", "u", pfproto_xint, pfcheck_xint, pfprint_uint },
+#ifdef illumos
+{ "wc", "wc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
+{ "ws", "ws", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
+#else
+{ "wc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
+{ "ws", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
+#endif
+{ "x", "x", pfproto_xint, pfcheck_xint, pfprint_uint },
+{ "X", "X", pfproto_xint, pfcheck_xint, pfprint_uint },
+{ "Y", "s", "int64_t", pfcheck_time, pfprint_time },
+{ "%", "%", "void", pfcheck_type, pfprint_pct },
+{ NULL, NULL, NULL, NULL, NULL }
+};
+
+int
+dt_pfdict_create(dtrace_hdl_t *dtp)
+{
+ uint_t n = _dtrace_strbuckets;
+ const dt_pfconv_t *pfd;
+ dt_pfdict_t *pdi;
+
+ if ((pdi = malloc(sizeof (dt_pfdict_t))) == NULL ||
+ (pdi->pdi_buckets = malloc(sizeof (dt_pfconv_t *) * n)) == NULL) {
+ free(pdi);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ dtp->dt_pfdict = pdi;
+ bzero(pdi->pdi_buckets, sizeof (dt_pfconv_t *) * n);
+ pdi->pdi_nbuckets = n;
+
+ for (pfd = _dtrace_conversions; pfd->pfc_name != NULL; pfd++) {
+ dtrace_typeinfo_t dtt;
+ dt_pfconv_t *pfc;
+ uint_t h;
+
+ if ((pfc = malloc(sizeof (dt_pfconv_t))) == NULL) {
+ dt_pfdict_destroy(dtp);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ bcopy(pfd, pfc, sizeof (dt_pfconv_t));
+ h = dt_strtab_hash(pfc->pfc_name, NULL) % n;
+ pfc->pfc_next = pdi->pdi_buckets[h];
+ pdi->pdi_buckets[h] = pfc;
+
+ dtt.dtt_ctfp = NULL;
+ dtt.dtt_type = CTF_ERR;
+
+ /*
+ * The "D" container or its parent must contain a definition of
+ * any type referenced by a printf conversion. If none can be
+ * found, we fail to initialize the printf dictionary.
+ */
+ if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type(
+ dtp, DTRACE_OBJ_DDEFS, pfc->pfc_tstr, &dtt) != 0) {
+ dt_pfdict_destroy(dtp);
+ return (dt_set_errno(dtp, EDT_NOCONV));
+ }
+
+ pfc->pfc_dctfp = dtt.dtt_ctfp;
+ pfc->pfc_dtype = dtt.dtt_type;
+
+ /*
+ * The "C" container may contain an alternate definition of an
+ * explicit conversion type. If it does, use it; otherwise
+ * just set pfc_ctype to pfc_dtype so it is always valid.
+ */
+ if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type(
+ dtp, DTRACE_OBJ_CDEFS, pfc->pfc_tstr, &dtt) == 0) {
+ pfc->pfc_cctfp = dtt.dtt_ctfp;
+ pfc->pfc_ctype = dtt.dtt_type;
+ } else {
+ pfc->pfc_cctfp = pfc->pfc_dctfp;
+ pfc->pfc_ctype = pfc->pfc_dtype;
+ }
+
+ if (pfc->pfc_check == NULL || pfc->pfc_print == NULL ||
+ pfc->pfc_ofmt == NULL || pfc->pfc_tstr == NULL) {
+ dt_pfdict_destroy(dtp);
+ return (dt_set_errno(dtp, EDT_BADCONV));
+ }
+
+ dt_dprintf("loaded printf conversion %%%s\n", pfc->pfc_name);
+ }
+
+ return (0);
+}
+
+void
+dt_pfdict_destroy(dtrace_hdl_t *dtp)
+{
+ dt_pfdict_t *pdi = dtp->dt_pfdict;
+ dt_pfconv_t *pfc, *nfc;
+ uint_t i;
+
+ if (pdi == NULL)
+ return;
+
+ for (i = 0; i < pdi->pdi_nbuckets; i++) {
+ for (pfc = pdi->pdi_buckets[i]; pfc != NULL; pfc = nfc) {
+ nfc = pfc->pfc_next;
+ free(pfc);
+ }
+ }
+
+ free(pdi->pdi_buckets);
+ free(pdi);
+ dtp->dt_pfdict = NULL;
+}
+
+static const dt_pfconv_t *
+dt_pfdict_lookup(dtrace_hdl_t *dtp, const char *name)
+{
+ dt_pfdict_t *pdi = dtp->dt_pfdict;
+ uint_t h = dt_strtab_hash(name, NULL) % pdi->pdi_nbuckets;
+ const dt_pfconv_t *pfc;
+
+ for (pfc = pdi->pdi_buckets[h]; pfc != NULL; pfc = pfc->pfc_next) {
+ if (strcmp(pfc->pfc_name, name) == 0)
+ break;
+ }
+
+ return (pfc);
+}
+
+static dt_pfargv_t *
+dt_printf_error(dtrace_hdl_t *dtp, int err)
+{
+ if (yypcb != NULL)
+ longjmp(yypcb->pcb_jmpbuf, err);
+
+ (void) dt_set_errno(dtp, err);
+ return (NULL);
+}
+
+dt_pfargv_t *
+dt_printf_create(dtrace_hdl_t *dtp, const char *s)
+{
+ dt_pfargd_t *pfd, *nfd = NULL;
+ dt_pfargv_t *pfv;
+ const char *p, *q;
+ char *format;
+
+ if ((pfv = malloc(sizeof (dt_pfargv_t))) == NULL ||
+ (format = strdup(s)) == NULL) {
+ free(pfv);
+ return (dt_printf_error(dtp, EDT_NOMEM));
+ }
+
+ pfv->pfv_format = format;
+ pfv->pfv_argv = NULL;
+ pfv->pfv_argc = 0;
+ pfv->pfv_flags = 0;
+ pfv->pfv_dtp = dtp;
+
+ for (q = format; (p = strchr(q, '%')) != NULL; q = *p ? p + 1 : p) {
+ uint_t namelen = 0;
+ int digits = 0;
+ int dot = 0;
+
+ char name[8];
+ char c;
+ int n;
+
+ if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) {
+ dt_printf_destroy(pfv);
+ return (dt_printf_error(dtp, EDT_NOMEM));
+ }
+
+ if (pfv->pfv_argv != NULL)
+ nfd->pfd_next = pfd;
+ else
+ pfv->pfv_argv = pfd;
+
+ bzero(pfd, sizeof (dt_pfargd_t));
+ pfv->pfv_argc++;
+ nfd = pfd;
+
+ if (p > q) {
+ pfd->pfd_preflen = (size_t)(p - q);
+ pfd->pfd_prefix = q;
+ }
+
+ fmt_switch:
+ switch (c = *++p) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (dot == 0 && digits == 0 && c == '0') {
+ pfd->pfd_flags |= DT_PFCONV_ZPAD;
+ pfd->pfd_flags &= ~DT_PFCONV_LEFT;
+ goto fmt_switch;
+ }
+
+ for (n = 0; isdigit(c); c = *++p)
+ n = n * 10 + c - '0';
+
+ if (dot)
+ pfd->pfd_prec = n;
+ else
+ pfd->pfd_width = n;
+
+ p--;
+ digits++;
+ goto fmt_switch;
+
+ case '#':
+ pfd->pfd_flags |= DT_PFCONV_ALT;
+ goto fmt_switch;
+
+ case '*':
+ n = dot ? DT_PFCONV_DYNPREC : DT_PFCONV_DYNWIDTH;
+
+ if (pfd->pfd_flags & n) {
+ yywarn("format conversion #%u has more than "
+ "one '*' specified for the output %s\n",
+ pfv->pfv_argc, n ? "precision" : "width");
+
+ dt_printf_destroy(pfv);
+ return (dt_printf_error(dtp, EDT_COMPILER));
+ }
+
+ pfd->pfd_flags |= n;
+ goto fmt_switch;
+
+ case '+':
+ pfd->pfd_flags |= DT_PFCONV_SPOS;
+ goto fmt_switch;
+
+ case '-':
+ pfd->pfd_flags |= DT_PFCONV_LEFT;
+ pfd->pfd_flags &= ~DT_PFCONV_ZPAD;
+ goto fmt_switch;
+
+ case '.':
+ if (dot++ != 0) {
+ yywarn("format conversion #%u has more than "
+ "one '.' specified\n", pfv->pfv_argc);
+
+ dt_printf_destroy(pfv);
+ return (dt_printf_error(dtp, EDT_COMPILER));
+ }
+ digits = 0;
+ goto fmt_switch;
+
+ case '?':
+ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
+ pfd->pfd_width = 16;
+ else
+ pfd->pfd_width = 8;
+ goto fmt_switch;
+
+ case '@':
+ pfd->pfd_flags |= DT_PFCONV_AGG;
+ goto fmt_switch;
+
+ case '\'':
+ pfd->pfd_flags |= DT_PFCONV_GROUP;
+ goto fmt_switch;
+
+ case ' ':
+ pfd->pfd_flags |= DT_PFCONV_SPACE;
+ goto fmt_switch;
+
+ case '$':
+ yywarn("format conversion #%u uses unsupported "
+ "positional format (%%n$)\n", pfv->pfv_argc);
+
+ dt_printf_destroy(pfv);
+ return (dt_printf_error(dtp, EDT_COMPILER));
+
+ case '%':
+ if (p[-1] == '%')
+ goto default_lbl; /* if %% then use "%" conv */
+
+ yywarn("format conversion #%u cannot be combined "
+ "with other format flags: %%%%\n", pfv->pfv_argc);
+
+ dt_printf_destroy(pfv);
+ return (dt_printf_error(dtp, EDT_COMPILER));
+
+ case '\0':
+ yywarn("format conversion #%u name expected before "
+ "end of format string\n", pfv->pfv_argc);
+
+ dt_printf_destroy(pfv);
+ return (dt_printf_error(dtp, EDT_COMPILER));
+
+ case 'h':
+ case 'l':
+ case 'L':
+ case 'w':
+ if (namelen < sizeof (name) - 2)
+ name[namelen++] = c;
+ goto fmt_switch;
+
+ default_lbl:
+ default:
+ name[namelen++] = c;
+ name[namelen] = '\0';
+ }
+
+ pfd->pfd_conv = dt_pfdict_lookup(dtp, name);
+
+ if (pfd->pfd_conv == NULL) {
+ yywarn("format conversion #%u is undefined: %%%s\n",
+ pfv->pfv_argc, name);
+ dt_printf_destroy(pfv);
+ return (dt_printf_error(dtp, EDT_COMPILER));
+ }
+ }
+
+ if (*q != '\0' || *format == '\0') {
+ if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) {
+ dt_printf_destroy(pfv);
+ return (dt_printf_error(dtp, EDT_NOMEM));
+ }
+
+ if (pfv->pfv_argv != NULL)
+ nfd->pfd_next = pfd;
+ else
+ pfv->pfv_argv = pfd;
+
+ bzero(pfd, sizeof (dt_pfargd_t));
+ pfv->pfv_argc++;
+
+ pfd->pfd_prefix = q;
+ pfd->pfd_preflen = strlen(q);
+ }
+
+ return (pfv);
+}
+
+void
+dt_printf_destroy(dt_pfargv_t *pfv)
+{
+ dt_pfargd_t *pfd, *nfd;
+
+ for (pfd = pfv->pfv_argv; pfd != NULL; pfd = nfd) {
+ nfd = pfd->pfd_next;
+ free(pfd);
+ }
+
+ free(pfv->pfv_format);
+ free(pfv);
+}
+
+void
+dt_printf_validate(dt_pfargv_t *pfv, uint_t flags,
+ dt_ident_t *idp, int foff, dtrace_actkind_t kind, dt_node_t *dnp)
+{
+ dt_pfargd_t *pfd = pfv->pfv_argv;
+ const char *func = idp->di_name;
+
+ char n[DT_TYPE_NAMELEN];
+ dtrace_typeinfo_t dtt;
+ const char *aggtype;
+ dt_node_t aggnode;
+ int i, j;
+
+ if (pfv->pfv_format[0] == '\0') {
+ xyerror(D_PRINTF_FMT_EMPTY,
+ "%s( ) format string is empty\n", func);
+ }
+
+ pfv->pfv_flags = flags;
+
+ /*
+ * We fake up a parse node representing the type that can be used with
+ * an aggregation result conversion, which -- for all but count() --
+ * is a signed quantity.
+ */
+ if (kind != DTRACEAGG_COUNT)
+ aggtype = "int64_t";
+ else
+ aggtype = "uint64_t";
+
+ if (dt_type_lookup(aggtype, &dtt) != 0)
+ xyerror(D_TYPE_ERR, "failed to lookup agg type %s\n", aggtype);
+
+ bzero(&aggnode, sizeof (aggnode));
+ dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
+
+ for (i = 0, j = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
+ const dt_pfconv_t *pfc = pfd->pfd_conv;
+ const char *dyns[2];
+ int dync = 0;
+
+ char vname[64];
+ dt_node_t *vnp;
+
+ if (pfc == NULL)
+ continue; /* no checking if argd is just a prefix */
+
+ if (pfc->pfc_print == &pfprint_pct) {
+ (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt);
+ continue;
+ }
+
+ if (pfd->pfd_flags & DT_PFCONV_DYNPREC)
+ dyns[dync++] = ".*";
+ if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH)
+ dyns[dync++] = "*";
+
+ for (; dync != 0; dync--) {
+ if (dnp == NULL) {
+ xyerror(D_PRINTF_DYN_PROTO,
+ "%s( ) prototype mismatch: conversion "
+ "#%d (%%%s) is missing a corresponding "
+ "\"%s\" argument\n", func, i + 1,
+ pfc->pfc_name, dyns[dync - 1]);
+ }
+
+ if (dt_node_is_integer(dnp) == 0) {
+ xyerror(D_PRINTF_DYN_TYPE,
+ "%s( ) argument #%d is incompatible "
+ "with conversion #%d prototype:\n"
+ "\tconversion: %% %s %s\n"
+ "\t prototype: int\n\t argument: %s\n",
+ func, j + foff + 1, i + 1,
+ dyns[dync - 1], pfc->pfc_name,
+ dt_node_type_name(dnp, n, sizeof (n)));
+ }
+
+ dnp = dnp->dn_list;
+ j++;
+ }
+
+ /*
+ * If this conversion is consuming the aggregation data, set
+ * the value node pointer (vnp) to a fake node based on the
+ * aggregating function result type. Otherwise assign vnp to
+ * the next parse node in the argument list, if there is one.
+ */
+ if (pfd->pfd_flags & DT_PFCONV_AGG) {
+ if (!(flags & DT_PRINTF_AGGREGATION)) {
+ xyerror(D_PRINTF_AGG_CONV,
+ "%%@ conversion requires an aggregation"
+ " and is not for use with %s( )\n", func);
+ }
+ (void) strlcpy(vname, "aggregating action",
+ sizeof (vname));
+ vnp = &aggnode;
+ } else if (dnp == NULL) {
+ xyerror(D_PRINTF_ARG_PROTO,
+ "%s( ) prototype mismatch: conversion #%d (%%"
+ "%s) is missing a corresponding value argument\n",
+ func, i + 1, pfc->pfc_name);
+ } else {
+ (void) snprintf(vname, sizeof (vname),
+ "argument #%d", j + foff + 1);
+ vnp = dnp;
+ dnp = dnp->dn_list;
+ j++;
+ }
+
+ /*
+ * Fill in the proposed final format string by prepending any
+ * size-related prefixes to the pfconv's format string. The
+ * pfc_check() function below may optionally modify the format
+ * as part of validating the type of the input argument.
+ */
+ if (pfc->pfc_print == &pfprint_sint ||
+ pfc->pfc_print == &pfprint_uint ||
+ pfc->pfc_print == &pfprint_dint) {
+ if (dt_node_type_size(vnp) == sizeof (uint64_t))
+ (void) strcpy(pfd->pfd_fmt, "ll");
+ } else if (pfc->pfc_print == &pfprint_fp) {
+ if (dt_node_type_size(vnp) == sizeof (long double))
+ (void) strcpy(pfd->pfd_fmt, "L");
+ }
+
+ (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt);
+
+ /*
+ * Validate the format conversion against the value node type.
+ * If the conversion is good, create the descriptor format
+ * string by concatenating together any required printf(3C)
+ * size prefixes with the conversion's native format string.
+ */
+ if (pfc->pfc_check(pfv, pfd, vnp) == 0) {
+ xyerror(D_PRINTF_ARG_TYPE,
+ "%s( ) %s is incompatible with "
+ "conversion #%d prototype:\n\tconversion: %%%s\n"
+ "\t prototype: %s\n\t argument: %s\n", func,
+ vname, i + 1, pfc->pfc_name, pfc->pfc_tstr,
+ dt_node_type_name(vnp, n, sizeof (n)));
+ }
+ }
+
+ if ((flags & DT_PRINTF_EXACTLEN) && dnp != NULL) {
+ xyerror(D_PRINTF_ARG_EXTRA,
+ "%s( ) prototype mismatch: only %d arguments "
+ "required by this format string\n", func, j);
+ }
+}
+
+void
+dt_printa_validate(dt_node_t *lhs, dt_node_t *rhs)
+{
+ dt_ident_t *lid, *rid;
+ dt_node_t *lproto, *rproto;
+ int largc, rargc, argn;
+ char n1[DT_TYPE_NAMELEN];
+ char n2[DT_TYPE_NAMELEN];
+
+ assert(lhs->dn_kind == DT_NODE_AGG);
+ assert(rhs->dn_kind == DT_NODE_AGG);
+
+ lid = lhs->dn_ident;
+ rid = rhs->dn_ident;
+
+ lproto = ((dt_idsig_t *)lid->di_data)->dis_args;
+ rproto = ((dt_idsig_t *)rid->di_data)->dis_args;
+
+ /*
+ * First, get an argument count on each side. These must match.
+ */
+ for (largc = 0; lproto != NULL; lproto = lproto->dn_list)
+ largc++;
+
+ for (rargc = 0; rproto != NULL; rproto = rproto->dn_list)
+ rargc++;
+
+ if (largc != rargc) {
+ xyerror(D_PRINTA_AGGKEY, "printa( ): @%s and @%s do not have "
+ "matching key signatures: @%s has %d key%s, @%s has %d "
+ "key%s", lid->di_name, rid->di_name,
+ lid->di_name, largc, largc == 1 ? "" : "s",
+ rid->di_name, rargc, rargc == 1 ? "" : "s");
+ }
+
+ /*
+ * Now iterate over the keys to verify that each type matches.
+ */
+ lproto = ((dt_idsig_t *)lid->di_data)->dis_args;
+ rproto = ((dt_idsig_t *)rid->di_data)->dis_args;
+
+ for (argn = 1; lproto != NULL; argn++, lproto = lproto->dn_list,
+ rproto = rproto->dn_list) {
+ assert(rproto != NULL);
+
+ if (dt_node_is_argcompat(lproto, rproto))
+ continue;
+
+ xyerror(D_PRINTA_AGGPROTO, "printa( ): @%s[ ] key #%d is "
+ "incompatible with @%s:\n%9s key #%d: %s\n"
+ "%9s key #%d: %s\n",
+ rid->di_name, argn, lid->di_name, lid->di_name, argn,
+ dt_node_type_name(lproto, n1, sizeof (n1)), rid->di_name,
+ argn, dt_node_type_name(rproto, n2, sizeof (n2)));
+ }
+}
+
+static int
+dt_printf_getint(dtrace_hdl_t *dtp, const dtrace_recdesc_t *recp,
+ uint_t nrecs, const void *buf, size_t len, int *ip)
+{
+ uintptr_t addr;
+
+ if (nrecs == 0)
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ addr = (uintptr_t)buf + recp->dtrd_offset;
+
+ if (addr + sizeof (int) > (uintptr_t)buf + len)
+ return (dt_set_errno(dtp, EDT_DOFFSET));
+
+ if (addr & (recp->dtrd_alignment - 1))
+ return (dt_set_errno(dtp, EDT_DALIGN));
+
+ switch (recp->dtrd_size) {
+ case sizeof (int8_t):
+ *ip = (int)*((int8_t *)addr);
+ break;
+ case sizeof (int16_t):
+ *ip = (int)*((int16_t *)addr);
+ break;
+ case sizeof (int32_t):
+ *ip = (int)*((int32_t *)addr);
+ break;
+ case sizeof (int64_t):
+ *ip = (int)*((int64_t *)addr);
+ break;
+ default:
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+pfprint_average(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ const uint64_t *data = addr;
+
+ if (size != sizeof (uint64_t) * 2)
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ return (dt_printf(dtp, fp, format,
+ data[0] ? data[1] / normal / data[0] : 0));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_stddev(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ const uint64_t *data = addr;
+
+ if (size != sizeof (uint64_t) * 4)
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ return (dt_printf(dtp, fp, format,
+ dt_stddev((uint64_t *)data, normal)));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_quantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ return (dt_print_quantize(dtp, fp, addr, size, normal));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_lquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ return (dt_print_lquantize(dtp, fp, addr, size, normal));
+}
+
+/*ARGSUSED*/
+static int
+pfprint_llquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ return (dt_print_llquantize(dtp, fp, addr, size, normal));
+}
+
+static int
+dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
+ const dtrace_recdesc_t *recs, uint_t nrecs, const void *buf,
+ size_t len, const dtrace_aggdata_t **aggsdata, int naggvars)
+{
+ dt_pfargd_t *pfd = pfv->pfv_argv;
+ const dtrace_recdesc_t *recp = recs;
+ const dtrace_aggdata_t *aggdata;
+ dtrace_aggdesc_t *agg;
+ caddr_t lim = (caddr_t)buf + len, limit;
+ char format[64] = "%";
+ size_t ret;
+ int i, aggrec, curagg = -1;
+ uint64_t normal;
+
+ /*
+ * If we are formatting an aggregation, set 'aggrec' to the index of
+ * the final record description (the aggregation result) so we can use
+ * this record index with any conversion where DT_PFCONV_AGG is set.
+ * (The actual aggregation used will vary as we increment through the
+ * aggregation variables that we have been passed.) Finally, we
+ * decrement nrecs to prevent this record from being used with any
+ * other conversion.
+ */
+ if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
+ assert(aggsdata != NULL);
+ assert(naggvars > 0);
+
+ if (nrecs == 0)
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ curagg = naggvars > 1 ? 1 : 0;
+ aggdata = aggsdata[0];
+ aggrec = aggdata->dtada_desc->dtagd_nrecs - 1;
+ nrecs--;
+ }
+
+ for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
+ const dt_pfconv_t *pfc = pfd->pfd_conv;
+ int width = pfd->pfd_width;
+ int prec = pfd->pfd_prec;
+ int rval;
+
+ const char *start;
+ char *f = format + 1; /* skip initial '%' */
+ size_t fmtsz = sizeof(format) - 1;
+ const dtrace_recdesc_t *rec;
+ dt_pfprint_f *func;
+ caddr_t addr;
+ size_t size;
+ uint32_t flags;
+
+ if (pfd->pfd_preflen != 0) {
+ char *tmp = alloca(pfd->pfd_preflen + 1);
+
+ bcopy(pfd->pfd_prefix, tmp, pfd->pfd_preflen);
+ tmp[pfd->pfd_preflen] = '\0';
+
+ if ((rval = dt_printf(dtp, fp, tmp)) < 0)
+ return (rval);
+
+ if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
+ /*
+ * For printa(), we flush the buffer after each
+ * prefix, setting the flags to indicate that
+ * this is part of the printa() format string.
+ */
+ flags = DTRACE_BUFDATA_AGGFORMAT;
+
+ if (pfc == NULL && i == pfv->pfv_argc - 1)
+ flags |= DTRACE_BUFDATA_AGGLAST;
+
+ if (dt_buffered_flush(dtp, NULL, NULL,
+ aggdata, flags) < 0)
+ return (-1);
+ }
+ }
+
+ if (pfc == NULL) {
+ if (pfv->pfv_argc == 1)
+ return (nrecs != 0);
+ continue;
+ }
+
+ /*
+ * If the conversion is %%, just invoke the print callback
+ * with no data record and continue; it consumes no record.
+ */
+ if (pfc->pfc_print == &pfprint_pct) {
+ if (pfc->pfc_print(dtp, fp, NULL, pfd, NULL, 0, 1) >= 0)
+ continue;
+ return (-1); /* errno is set for us */
+ }
+
+ if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) {
+ if (dt_printf_getint(dtp, recp++, nrecs--, buf,
+ len, &width) == -1)
+ return (-1); /* errno is set for us */
+ pfd->pfd_dynwidth = width;
+ } else {
+ pfd->pfd_dynwidth = 0;
+ }
+
+ if ((pfd->pfd_flags & DT_PFCONV_DYNPREC) && dt_printf_getint(
+ dtp, recp++, nrecs--, buf, len, &prec) == -1)
+ return (-1); /* errno is set for us */
+
+ if (pfd->pfd_flags & DT_PFCONV_AGG) {
+ /*
+ * This should be impossible -- the compiler shouldn't
+ * create a DT_PFCONV_AGG conversion without an
+ * aggregation present. Still, we'd rather fail
+ * gracefully than blow up...
+ */
+ if (aggsdata == NULL)
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ aggdata = aggsdata[curagg];
+ agg = aggdata->dtada_desc;
+
+ /*
+ * We increment the current aggregation variable, but
+ * not beyond the number of aggregation variables that
+ * we're printing. This has the (desired) effect that
+ * DT_PFCONV_AGG conversions beyond the number of
+ * aggregation variables (re-)convert the aggregation
+ * value of the last aggregation variable.
+ */
+ if (curagg < naggvars - 1)
+ curagg++;
+
+ rec = &agg->dtagd_rec[aggrec];
+ addr = aggdata->dtada_data + rec->dtrd_offset;
+ limit = addr + aggdata->dtada_size;
+ normal = aggdata->dtada_normal;
+ flags = DTRACE_BUFDATA_AGGVAL;
+ } else {
+ if (nrecs == 0)
+ return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+ if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
+ /*
+ * When printing aggregation keys, we always
+ * set the aggdata to be the representative
+ * (zeroth) aggregation. The aggdata isn't
+ * actually used here in this case, but it is
+ * passed to the buffer handler and must
+ * therefore still be correct.
+ */
+ aggdata = aggsdata[0];
+ flags = DTRACE_BUFDATA_AGGKEY;
+ }
+
+ rec = recp++;
+ nrecs--;
+ addr = (caddr_t)buf + rec->dtrd_offset;
+ limit = lim;
+ normal = 1;
+ }
+
+ size = rec->dtrd_size;
+
+ if (addr + size > limit) {
+ dt_dprintf("bad size: addr=%p size=0x%x lim=%p\n",
+ (void *)addr, rec->dtrd_size, (void *)lim);
+ return (dt_set_errno(dtp, EDT_DOFFSET));
+ }
+
+ if (rec->dtrd_alignment != 0 &&
+ ((uintptr_t)addr & (rec->dtrd_alignment - 1)) != 0) {
+ dt_dprintf("bad align: addr=%p size=0x%x align=0x%x\n",
+ (void *)addr, rec->dtrd_size, rec->dtrd_alignment);
+ return (dt_set_errno(dtp, EDT_DALIGN));
+ }
+
+ switch (rec->dtrd_action) {
+ case DTRACEAGG_AVG:
+ func = pfprint_average;
+ break;
+ case DTRACEAGG_STDDEV:
+ func = pfprint_stddev;
+ break;
+ case DTRACEAGG_QUANTIZE:
+ func = pfprint_quantize;
+ break;
+ case DTRACEAGG_LQUANTIZE:
+ func = pfprint_lquantize;
+ break;
+ case DTRACEAGG_LLQUANTIZE:
+ func = pfprint_llquantize;
+ break;
+ case DTRACEACT_MOD:
+ func = pfprint_mod;
+ break;
+ case DTRACEACT_UMOD:
+ func = pfprint_umod;
+ break;
+ default:
+ func = pfc->pfc_print;
+ break;
+ }
+
+ start = f;
+ if (pfd->pfd_flags & DT_PFCONV_ALT)
+ *f++ = '#';
+ if (pfd->pfd_flags & DT_PFCONV_ZPAD)
+ *f++ = '0';
+ if (width < 0 || (pfd->pfd_flags & DT_PFCONV_LEFT))
+ *f++ = '-';
+ if (pfd->pfd_flags & DT_PFCONV_SPOS)
+ *f++ = '+';
+ if (pfd->pfd_flags & DT_PFCONV_GROUP)
+ *f++ = '\'';
+ if (pfd->pfd_flags & DT_PFCONV_SPACE)
+ *f++ = ' ';
+ fmtsz -= f - start;
+
+ /*
+ * If we're printing a stack and DT_PFCONV_LEFT is set, we
+ * don't add the width to the format string. See the block
+ * comment in pfprint_stack() for a description of the
+ * behavior in this case.
+ */
+ if (func == pfprint_stack && (pfd->pfd_flags & DT_PFCONV_LEFT))
+ width = 0;
+
+ if (width != 0) {
+ ret = snprintf(f, fmtsz, "%d", ABS(width));
+ f += ret;
+ fmtsz = MAX(0, fmtsz - ret);
+ }
+
+ if (prec > 0) {
+ ret = snprintf(f, fmtsz, ".%d", prec);
+ f += ret;
+ fmtsz = MAX(0, fmtsz - ret);
+ }
+
+ if (strlcpy(f, pfd->pfd_fmt, fmtsz) >= fmtsz)
+ return (dt_set_errno(dtp, EDT_COMPILER));
+ pfd->pfd_rec = rec;
+
+ if (func(dtp, fp, format, pfd, addr, size, normal) < 0)
+ return (-1); /* errno is set for us */
+
+ if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
+ /*
+ * For printa(), we flush the buffer after each tuple
+ * element, inidicating that this is the last record
+ * as appropriate.
+ */
+ if (i == pfv->pfv_argc - 1)
+ flags |= DTRACE_BUFDATA_AGGLAST;
+
+ if (dt_buffered_flush(dtp, NULL,
+ rec, aggdata, flags) < 0)
+ return (-1);
+ }
+ }
+
+ return ((int)(recp - recs));
+}
+
+int
+dtrace_sprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
+ const dtrace_recdesc_t *recp, uint_t nrecs, const void *buf, size_t len)
+{
+ dtrace_optval_t size;
+ int rval;
+
+ rval = dtrace_getopt(dtp, "strsize", &size);
+ assert(rval == 0);
+ assert(dtp->dt_sprintf_buflen == 0);
+
+ if (dtp->dt_sprintf_buf != NULL)
+ free(dtp->dt_sprintf_buf);
+
+ if ((dtp->dt_sprintf_buf = malloc(size)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ bzero(dtp->dt_sprintf_buf, size);
+ dtp->dt_sprintf_buflen = size;
+ rval = dt_printf_format(dtp, fp, fmtdata, recp, nrecs, buf, len,
+ NULL, 0);
+ dtp->dt_sprintf_buflen = 0;
+
+ if (rval == -1)
+ free(dtp->dt_sprintf_buf);
+
+ return (rval);
+}
+
+/*ARGSUSED*/
+int
+dtrace_system(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
+ const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
+ uint_t nrecs, const void *buf, size_t len)
+{
+ int rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len);
+
+ if (rval == -1)
+ return (rval);
+
+ /*
+ * Before we execute the specified command, flush fp to assure that
+ * any prior dt_printf()'s appear before the output of the command
+ * not after it.
+ */
+ (void) fflush(fp);
+
+ if (system(dtp->dt_sprintf_buf) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ return (rval);
+}
+
+int
+dtrace_freopen(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
+ const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
+ uint_t nrecs, const void *buf, size_t len)
+{
+ char selfbuf[40], restorebuf[40], *filename;
+ FILE *nfp;
+ int rval, errval;
+ dt_pfargv_t *pfv = fmtdata;
+ dt_pfargd_t *pfd = pfv->pfv_argv;
+
+ rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len);
+
+ if (rval == -1 || fp == NULL)
+ return (rval);
+
+#ifdef illumos
+ if (pfd->pfd_preflen != 0 &&
+ strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) {
+ /*
+ * The only way to have the format string set to the value
+ * DT_FREOPEN_RESTORE is via the empty freopen() string --
+ * denoting that we should restore the old stdout.
+ */
+ assert(strcmp(dtp->dt_sprintf_buf, DT_FREOPEN_RESTORE) == 0);
+
+ if (dtp->dt_stdout_fd == -1) {
+ /*
+ * We could complain here by generating an error,
+ * but it seems like overkill: it seems that calling
+ * freopen() to restore stdout when freopen() has
+ * never before been called should just be a no-op,
+ * so we just return in this case.
+ */
+ return (rval);
+ }
+
+ (void) snprintf(restorebuf, sizeof (restorebuf),
+ "/dev/fd/%d", dtp->dt_stdout_fd);
+ filename = restorebuf;
+ } else {
+ filename = dtp->dt_sprintf_buf;
+ }
+
+ /*
+ * freopen(3C) will always close the specified stream and underlying
+ * file descriptor -- even if the specified file can't be opened.
+ * Even for the semantic cesspool that is standard I/O, this is
+ * surprisingly brain-dead behavior: it means that any failure to
+ * open the specified file destroys the specified stream in the
+ * process -- which is particularly relevant when the specified stream
+ * happens (or rather, happened) to be stdout. This could be resolved
+ * were there an "fdreopen()" equivalent of freopen() that allowed one
+ * to pass a file descriptor instead of the name of a file, but there
+ * is no such thing. However, we can effect this ourselves by first
+ * fopen()'ing the desired file, and then (assuming that that works),
+ * freopen()'ing "/dev/fd/[fileno]", where [fileno] is the underlying
+ * file descriptor for the fopen()'d file. This way, if the fopen()
+ * fails, we can fail the operation without destroying stdout.
+ */
+ if ((nfp = fopen(filename, "aF")) == NULL) {
+ char *msg = strerror(errno);
+ char *faultstr;
+ int len = 80;
+
+ len += strlen(msg) + strlen(filename);
+ faultstr = alloca(len);
+
+ (void) snprintf(faultstr, len, "couldn't freopen() \"%s\": %s",
+ filename, strerror(errno));
+
+ if ((errval = dt_handle_liberr(dtp, data, faultstr)) == 0)
+ return (rval);
+
+ return (errval);
+ }
+
+ (void) snprintf(selfbuf, sizeof (selfbuf), "/dev/fd/%d", fileno(nfp));
+
+ if (dtp->dt_stdout_fd == -1) {
+ /*
+ * If this is the first time that we're calling freopen(),
+ * we're going to stash away the file descriptor for stdout.
+ * We don't expect the dup(2) to fail, so if it does we must
+ * return failure.
+ */
+ if ((dtp->dt_stdout_fd = dup(fileno(fp))) == -1) {
+ (void) fclose(nfp);
+ return (dt_set_errno(dtp, errno));
+ }
+ }
+
+ if (freopen(selfbuf, "aF", fp) == NULL) {
+ (void) fclose(nfp);
+ return (dt_set_errno(dtp, errno));
+ }
+
+ (void) fclose(nfp);
+#else /* !illumos */
+ /*
+ * The 'standard output' (which is not necessarily stdout)
+ * treatment on FreeBSD is implemented differently than on
+ * Solaris because FreeBSD's freopen() will attempt to re-use
+ * the current file descriptor, causing the previous file to
+ * be closed and thereby preventing it from be re-activated
+ * later.
+ *
+ * For FreeBSD we use the concept of setting an output file
+ * pointer in the DTrace handle if a dtrace_freopen() has
+ * enabled another output file and we leave the caller's
+ * file pointer untouched. If it was actually stdout, then
+ * stdout remains open. If it was another file, then that
+ * file remains open. While a dtrace_freopen() has activated
+ * another file, we keep a pointer to that which we use in
+ * the output functions by preference and only use the caller's
+ * file pointer if no dtrace_freopen() call has been made.
+ *
+ * The check to see if we're re-activating the caller's
+ * output file is much the same as on Solaris.
+ */
+ if (pfd->pfd_preflen != 0 &&
+ strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) {
+ /*
+ * The only way to have the format string set to the value
+ * DT_FREOPEN_RESTORE is via the empty freopen() string --
+ * denoting that we should restore the old stdout.
+ */
+ assert(strcmp(dtp->dt_sprintf_buf, DT_FREOPEN_RESTORE) == 0);
+
+ if (dtp->dt_freopen_fp == NULL) {
+ /*
+ * We could complain here by generating an error,
+ * but it seems like overkill: it seems that calling
+ * freopen() to restore stdout when freopen() has
+ * never before been called should just be a no-op,
+ * so we just return in this case.
+ */
+ return (rval);
+ }
+
+ /*
+ * At this point, to re-active the original output file,
+ * on FreeBSD we only code the current file that this
+ * function opened previously.
+ */
+ (void) fclose(dtp->dt_freopen_fp);
+ dtp->dt_freopen_fp = NULL;
+
+ return (rval);
+ }
+
+ if ((nfp = fopen(dtp->dt_sprintf_buf, "a")) == NULL) {
+ char *msg = strerror(errno);
+ char *faultstr;
+ int len = 80;
+
+ len += strlen(msg) + strlen(dtp->dt_sprintf_buf);
+ faultstr = alloca(len);
+
+ (void) snprintf(faultstr, len, "couldn't freopen() \"%s\": %s",
+ dtp->dt_sprintf_buf, strerror(errno));
+
+ if ((errval = dt_handle_liberr(dtp, data, faultstr)) == 0)
+ return (rval);
+
+ return (errval);
+ }
+
+ if (dtp->dt_freopen_fp != NULL)
+ (void) fclose(dtp->dt_freopen_fp);
+
+ /* Remember that the output has been redirected to the new file. */
+ dtp->dt_freopen_fp = nfp;
+#endif /* illumos */
+
+ return (rval);
+}
+
+/*ARGSUSED*/
+int
+dtrace_fprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
+ const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
+ uint_t nrecs, const void *buf, size_t len)
+{
+ return (dt_printf_format(dtp, fp, fmtdata,
+ recp, nrecs, buf, len, NULL, 0));
+}
+
+void *
+dtrace_printf_create(dtrace_hdl_t *dtp, const char *s)
+{
+ dt_pfargv_t *pfv = dt_printf_create(dtp, s);
+ dt_pfargd_t *pfd;
+ int i;
+
+ if (pfv == NULL)
+ return (NULL); /* errno has been set for us */
+
+ pfd = pfv->pfv_argv;
+
+ for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
+ const dt_pfconv_t *pfc = pfd->pfd_conv;
+
+ if (pfc == NULL)
+ continue;
+
+ /*
+ * If the output format is not %s then we assume that we have
+ * been given a correctly-sized format string, so we copy the
+ * true format name including the size modifier. If the output
+ * format is %s, then either the input format is %s as well or
+ * it is one of our custom formats (e.g. pfprint_addr), so we
+ * must set pfd_fmt to be the output format conversion "s".
+ */
+ if (strcmp(pfc->pfc_ofmt, "s") != 0)
+ (void) strcat(pfd->pfd_fmt, pfc->pfc_name);
+ else
+ (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt);
+ }
+
+ return (pfv);
+}
+
+void *
+dtrace_printa_create(dtrace_hdl_t *dtp, const char *s)
+{
+ dt_pfargv_t *pfv = dtrace_printf_create(dtp, s);
+
+ if (pfv == NULL)
+ return (NULL); /* errno has been set for us */
+
+ pfv->pfv_flags |= DT_PRINTF_AGGREGATION;
+
+ return (pfv);
+}
+
+/*ARGSUSED*/
+size_t
+dtrace_printf_format(dtrace_hdl_t *dtp, void *fmtdata, char *s, size_t len)
+{
+ dt_pfargv_t *pfv = fmtdata;
+ dt_pfargd_t *pfd = pfv->pfv_argv;
+
+ /*
+ * An upper bound on the string length is the length of the original
+ * format string, plus three times the number of conversions (each
+ * conversion could add up an additional "ll" and/or pfd_width digit
+ * in the case of converting %? to %16) plus one for a terminating \0.
+ */
+ size_t formatlen = strlen(pfv->pfv_format) + 3 * pfv->pfv_argc + 1;
+ char *format = alloca(formatlen);
+ char *f = format;
+ int i, j;
+
+ for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
+ const dt_pfconv_t *pfc = pfd->pfd_conv;
+ const char *str;
+ int width = pfd->pfd_width;
+ int prec = pfd->pfd_prec;
+
+ if (pfd->pfd_preflen != 0) {
+ for (j = 0; j < pfd->pfd_preflen; j++)
+ *f++ = pfd->pfd_prefix[j];
+ }
+
+ if (pfc == NULL)
+ continue;
+
+ *f++ = '%';
+
+ if (pfd->pfd_flags & DT_PFCONV_ALT)
+ *f++ = '#';
+ if (pfd->pfd_flags & DT_PFCONV_ZPAD)
+ *f++ = '0';
+ if (pfd->pfd_flags & DT_PFCONV_LEFT)
+ *f++ = '-';
+ if (pfd->pfd_flags & DT_PFCONV_SPOS)
+ *f++ = '+';
+ if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH)
+ *f++ = '*';
+ if (pfd->pfd_flags & DT_PFCONV_DYNPREC) {
+ *f++ = '.';
+ *f++ = '*';
+ }
+ if (pfd->pfd_flags & DT_PFCONV_GROUP)
+ *f++ = '\'';
+ if (pfd->pfd_flags & DT_PFCONV_SPACE)
+ *f++ = ' ';
+ if (pfd->pfd_flags & DT_PFCONV_AGG)
+ *f++ = '@';
+
+ if (width != 0)
+ f += snprintf(f, sizeof (format), "%d", width);
+
+ if (prec != 0)
+ f += snprintf(f, sizeof (format), ".%d", prec);
+
+ /*
+ * If the output format is %s, then either %s is the underlying
+ * conversion or the conversion is one of our customized ones,
+ * e.g. pfprint_addr. In these cases, put the original string
+ * name of the conversion (pfc_name) into the pickled format
+ * string rather than the derived conversion (pfd_fmt).
+ */
+ if (strcmp(pfc->pfc_ofmt, "s") == 0)
+ str = pfc->pfc_name;
+ else
+ str = pfd->pfd_fmt;
+
+ for (j = 0; str[j] != '\0'; j++)
+ *f++ = str[j];
+ }
+
+ *f = '\0'; /* insert nul byte; do not count in return value */
+
+ assert(f < format + formatlen);
+ (void) strncpy(s, format, len);
+
+ return ((size_t)(f - format));
+}
+
+static int
+dt_fprinta(const dtrace_aggdata_t *adp, void *arg)
+{
+ const dtrace_aggdesc_t *agg = adp->dtada_desc;
+ const dtrace_recdesc_t *recp = &agg->dtagd_rec[0];
+ uint_t nrecs = agg->dtagd_nrecs;
+ dt_pfwalk_t *pfw = arg;
+ dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp;
+ int id;
+
+ if (dt_printf_getint(dtp, recp++, nrecs--,
+ adp->dtada_data, adp->dtada_size, &id) != 0 || pfw->pfw_aid != id)
+ return (0); /* no aggregation id or id does not match */
+
+ if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv,
+ recp, nrecs, adp->dtada_data, adp->dtada_size, &adp, 1) == -1)
+ return (pfw->pfw_err = dtp->dt_errno);
+
+ /*
+ * Cast away the const to set the bit indicating that this aggregation
+ * has been printed.
+ */
+ ((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED;
+
+ return (0);
+}
+
+static int
+dt_fprintas(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
+{
+ const dtrace_aggdata_t *aggdata = aggsdata[0];
+ const dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ const dtrace_recdesc_t *rec = &agg->dtagd_rec[1];
+ uint_t nrecs = agg->dtagd_nrecs - 1;
+ dt_pfwalk_t *pfw = arg;
+ dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp;
+ int i;
+
+ if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv,
+ rec, nrecs, aggdata->dtada_data, aggdata->dtada_size,
+ aggsdata, naggvars) == -1)
+ return (pfw->pfw_err = dtp->dt_errno);
+
+ /*
+ * For each aggregation, indicate that it has been printed, casting
+ * away the const as necessary.
+ */
+ for (i = 1; i < naggvars; i++) {
+ agg = aggsdata[i]->dtada_desc;
+ ((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED;
+ }
+
+ return (0);
+}
+/*ARGSUSED*/
+int
+dtrace_fprinta(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
+ const dtrace_probedata_t *data, const dtrace_recdesc_t *recs,
+ uint_t nrecs, const void *buf, size_t len)
+{
+ dt_pfwalk_t pfw;
+ int i, naggvars = 0;
+ dtrace_aggvarid_t *aggvars;
+
+ aggvars = alloca(nrecs * sizeof (dtrace_aggvarid_t));
+
+ /*
+ * This might be a printa() with multiple aggregation variables. We
+ * need to scan forward through the records until we find a record from
+ * a different statement.
+ */
+ for (i = 0; i < nrecs; i++) {
+ const dtrace_recdesc_t *nrec = &recs[i];
+
+ if (nrec->dtrd_uarg != recs->dtrd_uarg)
+ break;
+
+ if (nrec->dtrd_action != recs->dtrd_action)
+ return (dt_set_errno(dtp, EDT_BADAGG));
+
+ aggvars[naggvars++] =
+ /* LINTED - alignment */
+ *((dtrace_aggvarid_t *)((caddr_t)buf + nrec->dtrd_offset));
+ }
+
+ if (naggvars == 0)
+ return (dt_set_errno(dtp, EDT_BADAGG));
+
+ pfw.pfw_argv = fmtdata;
+ pfw.pfw_fp = fp;
+ pfw.pfw_err = 0;
+
+ if (naggvars == 1) {
+ pfw.pfw_aid = aggvars[0];
+
+ if (dtrace_aggregate_walk_sorted(dtp,
+ dt_fprinta, &pfw) == -1 || pfw.pfw_err != 0)
+ return (-1); /* errno is set for us */
+ } else {
+ if (dtrace_aggregate_walk_joined(dtp, aggvars, naggvars,
+ dt_fprintas, &pfw) == -1 || pfw.pfw_err != 0)
+ return (-1); /* errno is set for us */
+ }
+
+ return (i);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h
new file mode 100644
index 000000000000..b3b5b8b94bf6
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_PRINTF_H
+#define _DT_PRINTF_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <libctf.h>
+#include <dtrace.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dt_node;
+struct dt_ident;
+
+struct dt_pfconv;
+struct dt_pfargv;
+struct dt_pfargd;
+
+typedef int dt_pfcheck_f(struct dt_pfargv *,
+ struct dt_pfargd *, struct dt_node *);
+typedef int dt_pfprint_f(dtrace_hdl_t *, FILE *, const char *,
+ const struct dt_pfargd *, const void *, size_t, uint64_t);
+
+typedef struct dt_pfconv {
+ const char *pfc_name; /* string name of input conversion */
+ const char *pfc_ofmt; /* string name of output conversion */
+ const char *pfc_tstr; /* string name for conversion type */
+ dt_pfcheck_f *pfc_check; /* function to use for type checking */
+ dt_pfprint_f *pfc_print; /* function to use for formatting */
+ ctf_file_t *pfc_cctfp; /* CTF container for "C" defn of type */
+ ctf_id_t pfc_ctype; /* CTF type ID for "C" defn of type */
+ ctf_file_t *pfc_dctfp; /* CTF container for "D" defn of type */
+ ctf_id_t pfc_dtype; /* CTF type ID for "D" defn of type */
+ struct dt_pfconv *pfc_next; /* next conversion in hash chain */
+} dt_pfconv_t;
+
+typedef struct dt_pfdict {
+ dt_pfconv_t **pdi_buckets; /* hash bucket array */
+ uint_t pdi_nbuckets; /* size of hash bucket array */
+} dt_pfdict_t;
+
+typedef struct dt_pfargd {
+ const char *pfd_prefix; /* prefix string pointer (or NULL) */
+ size_t pfd_preflen; /* length of prefix in bytes */
+ char pfd_fmt[8]; /* output format name to use */
+ uint_t pfd_flags; /* format flags (see below) */
+ int pfd_width; /* field width (or 0) */
+ int pfd_dynwidth; /* dynamic field width (or 0) */
+ int pfd_prec; /* field precision (or 0) */
+ const dt_pfconv_t *pfd_conv; /* conversion specification */
+ const dtrace_recdesc_t *pfd_rec; /* pointer to current record */
+ struct dt_pfargd *pfd_next; /* pointer to next arg descriptor */
+} dt_pfargd_t;
+
+#define DT_PFCONV_ALT 0x0001 /* alternate print format (%#) */
+#define DT_PFCONV_ZPAD 0x0002 /* zero-pad integer field (%0) */
+#define DT_PFCONV_LEFT 0x0004 /* left-align field (%-) */
+#define DT_PFCONV_SPOS 0x0008 /* sign positive values (%+) */
+#define DT_PFCONV_DYNWIDTH 0x0010 /* dynamic width (%*.) */
+#define DT_PFCONV_DYNPREC 0x0020 /* dynamic precision (%.*) */
+#define DT_PFCONV_GROUP 0x0040 /* group thousands (%') */
+#define DT_PFCONV_SPACE 0x0080 /* insert leading space (% ) */
+#define DT_PFCONV_AGG 0x0100 /* use aggregation result (%@) */
+#define DT_PFCONV_SIGNED 0x0200 /* arg is a signed integer */
+
+typedef struct dt_pfargv {
+ dtrace_hdl_t *pfv_dtp; /* libdtrace client handle */
+ char *pfv_format; /* format string pointer */
+ dt_pfargd_t *pfv_argv; /* list of argument descriptors */
+ uint_t pfv_argc; /* number of argument descriptors */
+ uint_t pfv_flags; /* flags used for validation */
+} dt_pfargv_t;
+
+typedef struct dt_pfwalk {
+ const dt_pfargv_t *pfw_argv; /* argument description list */
+ uint_t pfw_aid; /* aggregation variable identifier */
+ FILE *pfw_fp; /* file pointer to use for output */
+ int pfw_err; /* error status code */
+} dt_pfwalk_t;
+
+extern int dt_pfdict_create(dtrace_hdl_t *);
+extern void dt_pfdict_destroy(dtrace_hdl_t *);
+
+extern dt_pfargv_t *dt_printf_create(dtrace_hdl_t *, const char *);
+extern void dt_printf_destroy(dt_pfargv_t *);
+
+#define DT_PRINTF_EXACTLEN 0x1 /* do not permit extra arguments */
+#define DT_PRINTF_AGGREGATION 0x2 /* enable aggregation conversion */
+
+extern void dt_printf_validate(dt_pfargv_t *, uint_t,
+ struct dt_ident *, int, dtrace_actkind_t, struct dt_node *);
+
+extern void dt_printa_validate(struct dt_node *, struct dt_node *);
+
+extern int dt_print_stack(dtrace_hdl_t *, FILE *,
+ const char *, caddr_t, int, int);
+extern int dt_print_ustack(dtrace_hdl_t *, FILE *,
+ const char *, caddr_t, uint64_t);
+extern int dt_print_mod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
+extern int dt_print_umod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_PRINTF_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c
new file mode 100644
index 000000000000..34bcc15b9ac7
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c
@@ -0,0 +1,1262 @@
+/*
+ * 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 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * DTrace Process Control
+ *
+ * This file provides a set of routines that permit libdtrace and its clients
+ * to create and grab process handles using libproc, and to share these handles
+ * between library mechanisms that need libproc access, such as ustack(), and
+ * client mechanisms that need libproc access, such as dtrace(1M) -c and -p.
+ * The library provides several mechanisms in the libproc control layer:
+ *
+ * Reference Counting: The library code and client code can independently grab
+ * the same process handles without interfering with one another. Only when
+ * the reference count drops to zero and the handle is not being cached (see
+ * below for more information on caching) will Prelease() be called on it.
+ *
+ * Handle Caching: If a handle is grabbed PGRAB_RDONLY (e.g. by ustack()) and
+ * the reference count drops to zero, the handle is not immediately released.
+ * Instead, libproc handles are maintained on dph_lrulist in order from most-
+ * recently accessed to least-recently accessed. Idle handles are maintained
+ * until a pre-defined LRU cache limit is exceeded, permitting repeated calls
+ * to ustack() to avoid the overhead of releasing and re-grabbing processes.
+ *
+ * Process Control: For processes that are grabbed for control (~PGRAB_RDONLY)
+ * or created by dt_proc_create(), a control thread is created to provide
+ * callbacks on process exit and symbol table caching on dlopen()s.
+ *
+ * MT-Safety: Libproc is not MT-Safe, so dt_proc_lock() and dt_proc_unlock()
+ * are provided to synchronize access to the libproc handle between libdtrace
+ * code and client code and the control thread's use of the ps_prochandle.
+ *
+ * NOTE: MT-Safety is NOT provided for libdtrace itself, or for use of the
+ * dtrace_proc_grab/dtrace_proc_create mechanisms. Like all exported libdtrace
+ * calls, these are assumed to be MT-Unsafe. MT-Safety is ONLY provided for
+ * synchronization between libdtrace control threads and the client thread.
+ *
+ * The ps_prochandles themselves are maintained along with a dt_proc_t struct
+ * in a hash table indexed by PID. This provides basic locking and reference
+ * counting. The dt_proc_t is also maintained in LRU order on dph_lrulist.
+ * The dph_lrucnt and dph_lrulim count the number of cacheable processes and
+ * the current limit on the number of actively cached entries.
+ *
+ * The control thread for a process establishes breakpoints at the rtld_db
+ * locations of interest, updates mappings and symbol tables at these points,
+ * and handles exec and fork (by always following the parent). The control
+ * thread automatically exits when the process dies or control is lost.
+ *
+ * A simple notification mechanism is provided for libdtrace clients using
+ * dtrace_handle_proc() for notification of PS_UNDEAD or PS_LOST events. If
+ * such an event occurs, the dt_proc_t itself is enqueued on a notification
+ * list and the control thread broadcasts to dph_cv. dtrace_sleep() will wake
+ * up using this condition and will then call the client handler as necessary.
+ */
+
+#include <sys/wait.h>
+#ifdef illumos
+#include <sys/lwp.h>
+#endif
+#include <strings.h>
+#include <signal.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <dt_proc.h>
+#include <dt_pid.h>
+#include <dt_impl.h>
+
+#ifndef illumos
+#include <sys/syscall.h>
+#include <libproc_compat.h>
+#define SYS_forksys SYS_fork
+#endif
+
+#define IS_SYS_EXEC(w) (w == SYS_execve)
+#define IS_SYS_FORK(w) (w == SYS_vfork || w == SYS_forksys)
+
+static dt_bkpt_t *
+dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
+{
+ struct ps_prochandle *P = dpr->dpr_proc;
+ dt_bkpt_t *dbp;
+
+ assert(DT_MUTEX_HELD(&dpr->dpr_lock));
+
+ if ((dbp = dt_zalloc(dpr->dpr_hdl, sizeof (dt_bkpt_t))) != NULL) {
+ dbp->dbp_func = func;
+ dbp->dbp_data = data;
+ dbp->dbp_addr = addr;
+
+ if (Psetbkpt(P, dbp->dbp_addr, &dbp->dbp_instr) == 0)
+ dbp->dbp_active = B_TRUE;
+
+ dt_list_append(&dpr->dpr_bps, dbp);
+ }
+
+ return (dbp);
+}
+
+static void
+dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts)
+{
+ int state = Pstate(dpr->dpr_proc);
+ dt_bkpt_t *dbp, *nbp;
+
+ assert(DT_MUTEX_HELD(&dpr->dpr_lock));
+
+ for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) {
+ if (delbkpts && dbp->dbp_active &&
+ state != PS_LOST && state != PS_UNDEAD) {
+ (void) Pdelbkpt(dpr->dpr_proc,
+ dbp->dbp_addr, dbp->dbp_instr);
+ }
+ nbp = dt_list_next(dbp);
+ dt_list_delete(&dpr->dpr_bps, dbp);
+ dt_free(dpr->dpr_hdl, dbp);
+ }
+}
+
+static void
+dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
+{
+#ifdef illumos
+ const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
+#else
+ unsigned long pc;
+#endif
+ dt_bkpt_t *dbp;
+
+ assert(DT_MUTEX_HELD(&dpr->dpr_lock));
+
+#ifndef illumos
+ proc_regget(dpr->dpr_proc, REG_PC, &pc);
+ proc_bkptregadj(&pc);
+#endif
+
+ for (dbp = dt_list_next(&dpr->dpr_bps);
+ dbp != NULL; dbp = dt_list_next(dbp)) {
+#ifdef illumos
+ if (psp->pr_reg[R_PC] == dbp->dbp_addr)
+ break;
+#else
+ if (pc == dbp->dbp_addr)
+ break;
+#endif
+ }
+
+ if (dbp == NULL) {
+ dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
+#ifdef illumos
+ (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]);
+#else
+ (int)dpr->dpr_pid, pc);
+#endif
+ return;
+ }
+
+ dt_dprintf("pid %d: hit breakpoint at %lx (%lu)\n",
+ (int)dpr->dpr_pid, (ulong_t)dbp->dbp_addr, ++dbp->dbp_hits);
+
+ dbp->dbp_func(dtp, dpr, dbp->dbp_data);
+ (void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr);
+}
+
+static void
+dt_proc_bpenable(dt_proc_t *dpr)
+{
+ dt_bkpt_t *dbp;
+
+ assert(DT_MUTEX_HELD(&dpr->dpr_lock));
+
+ for (dbp = dt_list_next(&dpr->dpr_bps);
+ dbp != NULL; dbp = dt_list_next(dbp)) {
+ if (!dbp->dbp_active && Psetbkpt(dpr->dpr_proc,
+ dbp->dbp_addr, &dbp->dbp_instr) == 0)
+ dbp->dbp_active = B_TRUE;
+ }
+
+ dt_dprintf("breakpoints enabled\n");
+}
+
+static void
+dt_proc_bpdisable(dt_proc_t *dpr)
+{
+ dt_bkpt_t *dbp;
+
+ assert(DT_MUTEX_HELD(&dpr->dpr_lock));
+
+ for (dbp = dt_list_next(&dpr->dpr_bps);
+ dbp != NULL; dbp = dt_list_next(dbp)) {
+ if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc,
+ dbp->dbp_addr, dbp->dbp_instr) == 0)
+ dbp->dbp_active = B_FALSE;
+ }
+
+ dt_dprintf("breakpoints disabled\n");
+}
+
+static void
+dt_proc_notify(dtrace_hdl_t *dtp, dt_proc_hash_t *dph, dt_proc_t *dpr,
+ const char *msg)
+{
+ dt_proc_notify_t *dprn = dt_alloc(dtp, sizeof (dt_proc_notify_t));
+
+ if (dprn == NULL) {
+ dt_dprintf("failed to allocate notification for %d %s\n",
+ (int)dpr->dpr_pid, msg);
+ } else {
+ dprn->dprn_dpr = dpr;
+ if (msg == NULL)
+ dprn->dprn_errmsg[0] = '\0';
+ else
+ (void) strlcpy(dprn->dprn_errmsg, msg,
+ sizeof (dprn->dprn_errmsg));
+
+ (void) pthread_mutex_lock(&dph->dph_lock);
+
+ dprn->dprn_next = dph->dph_notify;
+ dph->dph_notify = dprn;
+
+ (void) pthread_cond_broadcast(&dph->dph_cv);
+ (void) pthread_mutex_unlock(&dph->dph_lock);
+ }
+}
+
+/*
+ * Check to see if the control thread was requested to stop when the victim
+ * process reached a particular event (why) rather than continuing the victim.
+ * If 'why' is set in the stop mask, we wait on dpr_cv for dt_proc_continue().
+ * If 'why' is not set, this function returns immediately and does nothing.
+ */
+static void
+dt_proc_stop(dt_proc_t *dpr, uint8_t why)
+{
+ assert(DT_MUTEX_HELD(&dpr->dpr_lock));
+ assert(why != DT_PROC_STOP_IDLE);
+
+ if (dpr->dpr_stop & why) {
+ dpr->dpr_stop |= DT_PROC_STOP_IDLE;
+ dpr->dpr_stop &= ~why;
+
+ (void) pthread_cond_broadcast(&dpr->dpr_cv);
+
+ /*
+ * We disable breakpoints while stopped to preserve the
+ * integrity of the program text for both our own disassembly
+ * and that of the kernel.
+ */
+ dt_proc_bpdisable(dpr);
+
+ while (dpr->dpr_stop & DT_PROC_STOP_IDLE)
+ (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
+
+ dt_proc_bpenable(dpr);
+ }
+}
+
+/*ARGSUSED*/
+static void
+dt_proc_bpmain(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *fname)
+{
+ dt_dprintf("pid %d: breakpoint at %s()\n", (int)dpr->dpr_pid, fname);
+ dt_proc_stop(dpr, DT_PROC_STOP_MAIN);
+}
+
+static void
+dt_proc_rdevent(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *evname)
+{
+ rd_event_msg_t rdm;
+ rd_err_e err;
+
+ if ((err = rd_event_getmsg(dpr->dpr_rtld, &rdm)) != RD_OK) {
+ dt_dprintf("pid %d: failed to get %s event message: %s\n",
+ (int)dpr->dpr_pid, evname, rd_errstr(err));
+ return;
+ }
+
+ dt_dprintf("pid %d: rtld event %s type=%d state %d\n",
+ (int)dpr->dpr_pid, evname, rdm.type, rdm.u.state);
+
+ switch (rdm.type) {
+ case RD_DLACTIVITY:
+ if (rdm.u.state != RD_CONSISTENT)
+ break;
+
+ Pupdate_syms(dpr->dpr_proc);
+ if (dt_pid_create_probes_module(dtp, dpr) != 0)
+ dt_proc_notify(dtp, dtp->dt_procs, dpr,
+ dpr->dpr_errmsg);
+
+ break;
+ case RD_PREINIT:
+ Pupdate_syms(dpr->dpr_proc);
+ dt_proc_stop(dpr, DT_PROC_STOP_PREINIT);
+ break;
+ case RD_POSTINIT:
+ Pupdate_syms(dpr->dpr_proc);
+ dt_proc_stop(dpr, DT_PROC_STOP_POSTINIT);
+ break;
+ }
+}
+
+static void
+dt_proc_rdwatch(dt_proc_t *dpr, rd_event_e event, const char *evname)
+{
+ rd_notify_t rdn;
+ rd_err_e err;
+
+ if ((err = rd_event_addr(dpr->dpr_rtld, event, &rdn)) != RD_OK) {
+ dt_dprintf("pid %d: failed to get event address for %s: %s\n",
+ (int)dpr->dpr_pid, evname, rd_errstr(err));
+ return;
+ }
+
+ if (rdn.type != RD_NOTIFY_BPT) {
+ dt_dprintf("pid %d: event %s has unexpected type %d\n",
+ (int)dpr->dpr_pid, evname, rdn.type);
+ return;
+ }
+
+ (void) dt_proc_bpcreate(dpr, rdn.u.bptaddr,
+#ifdef illumos
+ (dt_bkpt_f *)dt_proc_rdevent, (void *)evname);
+#else
+ /* XXX ugly */
+ (dt_bkpt_f *)dt_proc_rdevent, __DECONST(void *, evname));
+#endif
+}
+
+/*
+ * Common code for enabling events associated with the run-time linker after
+ * attaching to a process or after a victim process completes an exec(2).
+ */
+static void
+dt_proc_attach(dt_proc_t *dpr, int exec)
+{
+#ifdef illumos
+ const pstatus_t *psp = Pstatus(dpr->dpr_proc);
+#endif
+ rd_err_e err;
+ GElf_Sym sym;
+
+ assert(DT_MUTEX_HELD(&dpr->dpr_lock));
+
+ if (exec) {
+#ifdef illumos
+ if (psp->pr_lwp.pr_errno != 0)
+ return; /* exec failed: nothing needs to be done */
+#endif
+
+ dt_proc_bpdestroy(dpr, B_FALSE);
+#ifdef illumos
+ Preset_maps(dpr->dpr_proc);
+#endif
+ }
+ if ((dpr->dpr_rtld = Prd_agent(dpr->dpr_proc)) != NULL &&
+ (err = rd_event_enable(dpr->dpr_rtld, B_TRUE)) == RD_OK) {
+#ifdef illumos
+ dt_proc_rdwatch(dpr, RD_PREINIT, "RD_PREINIT");
+#endif
+ dt_proc_rdwatch(dpr, RD_POSTINIT, "RD_POSTINIT");
+#ifdef illumos
+ dt_proc_rdwatch(dpr, RD_DLACTIVITY, "RD_DLACTIVITY");
+#endif
+ } else {
+ dt_dprintf("pid %d: failed to enable rtld events: %s\n",
+ (int)dpr->dpr_pid, dpr->dpr_rtld ? rd_errstr(err) :
+ "rtld_db agent initialization failed");
+ }
+
+ Pupdate_maps(dpr->dpr_proc);
+
+ if (Pxlookup_by_name(dpr->dpr_proc, LM_ID_BASE,
+ "a.out", "main", &sym, NULL) == 0) {
+ (void) dt_proc_bpcreate(dpr, (uintptr_t)sym.st_value,
+ (dt_bkpt_f *)dt_proc_bpmain, "a.out`main");
+ } else {
+ dt_dprintf("pid %d: failed to find a.out`main: %s\n",
+ (int)dpr->dpr_pid, strerror(errno));
+ }
+}
+
+/*
+ * Wait for a stopped process to be set running again by some other debugger.
+ * This is typically not required by /proc-based debuggers, since the usual
+ * model is that one debugger controls one victim. But DTrace, as usual, has
+ * its own needs: the stop() action assumes that prun(1) or some other tool
+ * will be applied to resume the victim process. This could be solved by
+ * adding a PCWRUN directive to /proc, but that seems like overkill unless
+ * other debuggers end up needing this functionality, so we implement a cheap
+ * equivalent to PCWRUN using the set of existing kernel mechanisms.
+ *
+ * Our intent is really not just to wait for the victim to run, but rather to
+ * wait for it to run and then stop again for a reason other than the current
+ * PR_REQUESTED stop. Since PCWSTOP/Pstopstatus() can be applied repeatedly
+ * to a stopped process and will return the same result without affecting the
+ * victim, we can just perform these operations repeatedly until Pstate()
+ * changes, the representative LWP ID changes, or the stop timestamp advances.
+ * dt_proc_control() will then rediscover the new state and continue as usual.
+ * When the process is still stopped in the same exact state, we sleep for a
+ * brief interval before waiting again so as not to spin consuming CPU cycles.
+ */
+static void
+dt_proc_waitrun(dt_proc_t *dpr)
+{
+ printf("%s:%s(%d): not implemented\n", __FUNCTION__, __FILE__,
+ __LINE__);
+#ifdef DOODAD
+ struct ps_prochandle *P = dpr->dpr_proc;
+ const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;
+
+ int krflag = psp->pr_flags & (PR_KLC | PR_RLC);
+ timestruc_t tstamp = psp->pr_tstamp;
+ lwpid_t lwpid = psp->pr_lwpid;
+
+ const long wstop = PCWSTOP;
+ int pfd = Pctlfd(P);
+
+ assert(DT_MUTEX_HELD(&dpr->dpr_lock));
+ assert(psp->pr_flags & PR_STOPPED);
+ assert(Pstate(P) == PS_STOP);
+
+ /*
+ * While we are waiting for the victim to run, clear PR_KLC and PR_RLC
+ * so that if the libdtrace client is killed, the victim stays stopped.
+ * dt_proc_destroy() will also observe this and perform PRELEASE_HANG.
+ */
+ (void) Punsetflags(P, krflag);
+ Psync(P);
+
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+
+ while (!dpr->dpr_quit) {
+ if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
+ continue; /* check dpr_quit and continue waiting */
+
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+ (void) Pstopstatus(P, PCNULL, 0);
+ psp = &Pstatus(P)->pr_lwp;
+
+ /*
+ * If we've reached a new state, found a new representative, or
+ * the stop timestamp has changed, restore PR_KLC/PR_RLC to its
+ * original setting and then return with dpr_lock held.
+ */
+ if (Pstate(P) != PS_STOP || psp->pr_lwpid != lwpid ||
+ bcmp(&psp->pr_tstamp, &tstamp, sizeof (tstamp)) != 0) {
+ (void) Psetflags(P, krflag);
+ Psync(P);
+ return;
+ }
+
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+ (void) poll(NULL, 0, MILLISEC / 2);
+ }
+
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+#endif
+}
+
+typedef struct dt_proc_control_data {
+ dtrace_hdl_t *dpcd_hdl; /* DTrace handle */
+ dt_proc_t *dpcd_proc; /* proccess to control */
+} dt_proc_control_data_t;
+
+/*
+ * Main loop for all victim process control threads. We initialize all the
+ * appropriate /proc control mechanisms, and then enter a loop waiting for
+ * the process to stop on an event or die. We process any events by calling
+ * appropriate subroutines, and exit when the victim dies or we lose control.
+ *
+ * The control thread synchronizes the use of dpr_proc with other libdtrace
+ * threads using dpr_lock. We hold the lock for all of our operations except
+ * waiting while the process is running: this is accomplished by writing a
+ * PCWSTOP directive directly to the underlying /proc/<pid>/ctl file. If the
+ * libdtrace client wishes to exit or abort our wait, SIGCANCEL can be used.
+ */
+static void *
+dt_proc_control(void *arg)
+{
+ dt_proc_control_data_t *datap = arg;
+ dtrace_hdl_t *dtp = datap->dpcd_hdl;
+ dt_proc_t *dpr = datap->dpcd_proc;
+ dt_proc_hash_t *dph = dtp->dt_procs;
+ struct ps_prochandle *P = dpr->dpr_proc;
+ int pid = dpr->dpr_pid;
+
+#ifdef illumos
+ int pfd = Pctlfd(P);
+
+ const long wstop = PCWSTOP;
+#endif
+ int notify = B_FALSE;
+
+ /*
+ * We disable the POSIX thread cancellation mechanism so that the
+ * client program using libdtrace can't accidentally cancel our thread.
+ * dt_proc_destroy() uses SIGCANCEL explicitly to simply poke us out
+ * of PCWSTOP with EINTR, at which point we will see dpr_quit and exit.
+ */
+ (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ /*
+ * Set up the corresponding process for tracing by libdtrace. We want
+ * to be able to catch breakpoints and efficiently single-step over
+ * them, and we need to enable librtld_db to watch libdl activity.
+ */
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+
+#ifdef illumos
+ (void) Punsetflags(P, PR_ASYNC); /* require synchronous mode */
+ (void) Psetflags(P, PR_BPTADJ); /* always adjust eip on x86 */
+ (void) Punsetflags(P, PR_FORK); /* do not inherit on fork */
+
+ (void) Pfault(P, FLTBPT, B_TRUE); /* always trace breakpoints */
+ (void) Pfault(P, FLTTRACE, B_TRUE); /* always trace single-step */
+
+ /*
+ * We must trace exit from exec() system calls so that if the exec is
+ * successful, we can reset our breakpoints and re-initialize libproc.
+ */
+ (void) Psysexit(P, SYS_execve, B_TRUE);
+
+ /*
+ * We must trace entry and exit for fork() system calls in order to
+ * disable our breakpoints temporarily during the fork. We do not set
+ * the PR_FORK flag, so if fork succeeds the child begins executing and
+ * does not inherit any other tracing behaviors or a control thread.
+ */
+ (void) Psysentry(P, SYS_vfork, B_TRUE);
+ (void) Psysexit(P, SYS_vfork, B_TRUE);
+ (void) Psysentry(P, SYS_forksys, B_TRUE);
+ (void) Psysexit(P, SYS_forksys, B_TRUE);
+
+ Psync(P); /* enable all /proc changes */
+#endif
+ dt_proc_attach(dpr, B_FALSE); /* enable rtld breakpoints */
+
+ /*
+ * If PR_KLC is set, we created the process; otherwise we grabbed it.
+ * Check for an appropriate stop request and wait for dt_proc_continue.
+ */
+#ifdef illumos
+ if (Pstatus(P)->pr_flags & PR_KLC)
+#else
+ if (proc_getflags(P) & PR_KLC)
+#endif
+ dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
+ else
+ dt_proc_stop(dpr, DT_PROC_STOP_GRAB);
+
+ if (Psetrun(P, 0, 0) == -1) {
+ dt_dprintf("pid %d: failed to set running: %s\n",
+ (int)dpr->dpr_pid, strerror(errno));
+ }
+
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+
+ /*
+ * Wait for the process corresponding to this control thread to stop,
+ * process the event, and then set it running again. We want to sleep
+ * with dpr_lock *unheld* so that other parts of libdtrace can use the
+ * ps_prochandle in the meantime (e.g. ustack()). To do this, we write
+ * a PCWSTOP directive directly to the underlying /proc/<pid>/ctl file.
+ * Once the process stops, we wake up, grab dpr_lock, and then call
+ * Pwait() (which will return immediately) and do our processing.
+ */
+ while (!dpr->dpr_quit) {
+ const lwpstatus_t *psp;
+
+#ifdef illumos
+ if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
+ continue; /* check dpr_quit and continue waiting */
+#else
+ /* Wait for the process to report status. */
+ proc_wstatus(P);
+ if (errno == EINTR)
+ continue; /* check dpr_quit and continue waiting */
+#endif
+
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+
+#ifdef illumos
+pwait_locked:
+ if (Pstopstatus(P, PCNULL, 0) == -1 && errno == EINTR) {
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+ continue; /* check dpr_quit and continue waiting */
+ }
+#endif
+
+ switch (Pstate(P)) {
+ case PS_STOP:
+#ifdef illumos
+ psp = &Pstatus(P)->pr_lwp;
+#else
+ psp = proc_getlwpstatus(P);
+#endif
+
+ dt_dprintf("pid %d: proc stopped showing %d/%d\n",
+ pid, psp->pr_why, psp->pr_what);
+
+ /*
+ * If the process stops showing PR_REQUESTED, then the
+ * DTrace stop() action was applied to it or another
+ * debugging utility (e.g. pstop(1)) asked it to stop.
+ * In either case, the user's intention is for the
+ * process to remain stopped until another external
+ * mechanism (e.g. prun(1)) is applied. So instead of
+ * setting the process running ourself, we wait for
+ * someone else to do so. Once that happens, we return
+ * to our normal loop waiting for an event of interest.
+ */
+ if (psp->pr_why == PR_REQUESTED) {
+ dt_proc_waitrun(dpr);
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+ continue;
+ }
+
+ /*
+ * If the process stops showing one of the events that
+ * we are tracing, perform the appropriate response.
+ * Note that we ignore PR_SUSPENDED, PR_CHECKPOINT, and
+ * PR_JOBCONTROL by design: if one of these conditions
+ * occurs, we will fall through to Psetrun() but the
+ * process will remain stopped in the kernel by the
+ * corresponding mechanism (e.g. job control stop).
+ */
+ if (psp->pr_why == PR_FAULTED && psp->pr_what == FLTBPT)
+ dt_proc_bpmatch(dtp, dpr);
+ else if (psp->pr_why == PR_SYSENTRY &&
+ IS_SYS_FORK(psp->pr_what))
+ dt_proc_bpdisable(dpr);
+ else if (psp->pr_why == PR_SYSEXIT &&
+ IS_SYS_FORK(psp->pr_what))
+ dt_proc_bpenable(dpr);
+ else if (psp->pr_why == PR_SYSEXIT &&
+ IS_SYS_EXEC(psp->pr_what))
+ dt_proc_attach(dpr, B_TRUE);
+ break;
+
+ case PS_LOST:
+#ifdef illumos
+ if (Preopen(P) == 0)
+ goto pwait_locked;
+#endif
+
+ dt_dprintf("pid %d: proc lost: %s\n",
+ pid, strerror(errno));
+
+ dpr->dpr_quit = B_TRUE;
+ notify = B_TRUE;
+ break;
+
+ case PS_UNDEAD:
+ dt_dprintf("pid %d: proc died\n", pid);
+ dpr->dpr_quit = B_TRUE;
+ notify = B_TRUE;
+ break;
+ }
+
+ if (Pstate(P) != PS_UNDEAD && Psetrun(P, 0, 0) == -1) {
+ dt_dprintf("pid %d: failed to set running: %s\n",
+ (int)dpr->dpr_pid, strerror(errno));
+ }
+
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+ }
+
+ /*
+ * If the control thread detected PS_UNDEAD or PS_LOST, then enqueue
+ * the dt_proc_t structure on the dt_proc_hash_t notification list.
+ */
+ if (notify)
+ dt_proc_notify(dtp, dph, dpr, NULL);
+
+ /*
+ * Destroy and remove any remaining breakpoints, set dpr_done and clear
+ * dpr_tid to indicate the control thread has exited, and notify any
+ * waiting thread in dt_proc_destroy() that we have succesfully exited.
+ */
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+
+ dt_proc_bpdestroy(dpr, B_TRUE);
+ dpr->dpr_done = B_TRUE;
+ dpr->dpr_tid = 0;
+
+ (void) pthread_cond_broadcast(&dpr->dpr_cv);
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+
+ return (NULL);
+}
+
+/*PRINTFLIKE3*/
+static struct ps_prochandle *
+dt_proc_error(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap);
+ va_end(ap);
+
+ if (dpr->dpr_proc != NULL)
+ Prelease(dpr->dpr_proc, 0);
+
+ dt_free(dtp, dpr);
+ (void) dt_set_errno(dtp, EDT_COMPILER);
+ return (NULL);
+}
+
+dt_proc_t *
+dt_proc_lookup(dtrace_hdl_t *dtp, struct ps_prochandle *P, int remove)
+{
+ dt_proc_hash_t *dph = dtp->dt_procs;
+#ifdef illumos
+ pid_t pid = Pstatus(P)->pr_pid;
+#else
+ pid_t pid = proc_getpid(P);
+#endif
+ dt_proc_t *dpr, **dpp = &dph->dph_hash[pid & (dph->dph_hashlen - 1)];
+
+ for (dpr = *dpp; dpr != NULL; dpr = dpr->dpr_hash) {
+ if (dpr->dpr_pid == pid)
+ break;
+ else
+ dpp = &dpr->dpr_hash;
+ }
+
+ assert(dpr != NULL);
+ assert(dpr->dpr_proc == P);
+
+ if (remove)
+ *dpp = dpr->dpr_hash; /* remove from pid hash chain */
+
+ return (dpr);
+}
+
+static void
+dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
+{
+ dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
+ dt_proc_hash_t *dph = dtp->dt_procs;
+ dt_proc_notify_t *npr, **npp;
+ int rflag;
+
+ assert(dpr != NULL);
+
+ /*
+ * If neither PR_KLC nor PR_RLC is set, then the process is stopped by
+ * an external debugger and we were waiting in dt_proc_waitrun().
+ * Leave the process in this condition using PRELEASE_HANG.
+ */
+#ifdef illumos
+ if (!(Pstatus(dpr->dpr_proc)->pr_flags & (PR_KLC | PR_RLC))) {
+#else
+ if (!(proc_getflags(dpr->dpr_proc) & (PR_KLC | PR_RLC))) {
+#endif
+ dt_dprintf("abandoning pid %d\n", (int)dpr->dpr_pid);
+ rflag = PRELEASE_HANG;
+#ifdef illumos
+ } else if (Pstatus(dpr->dpr_proc)->pr_flags & PR_KLC) {
+#else
+ } else if (proc_getflags(dpr->dpr_proc) & PR_KLC) {
+#endif
+ dt_dprintf("killing pid %d\n", (int)dpr->dpr_pid);
+ rflag = PRELEASE_KILL; /* apply kill-on-last-close */
+ } else {
+ dt_dprintf("releasing pid %d\n", (int)dpr->dpr_pid);
+ rflag = 0; /* apply run-on-last-close */
+ }
+
+ if (dpr->dpr_tid) {
+ /*
+ * Set the dpr_quit flag to tell the daemon thread to exit. We
+ * send it a SIGCANCEL to poke it out of PCWSTOP or any other
+ * long-term /proc system call. Our daemon threads have POSIX
+ * cancellation disabled, so EINTR will be the only effect. We
+ * then wait for dpr_done to indicate the thread has exited.
+ *
+ * We can't use pthread_kill() to send SIGCANCEL because the
+ * interface forbids it and we can't use pthread_cancel()
+ * because with cancellation disabled it won't actually
+ * send SIGCANCEL to the target thread, so we use _lwp_kill()
+ * to do the job. This is all built on evil knowledge of
+ * the details of the cancellation mechanism in libc.
+ */
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+ dpr->dpr_quit = B_TRUE;
+#ifdef illumos
+ (void) _lwp_kill(dpr->dpr_tid, SIGCANCEL);
+#else
+ pthread_kill(dpr->dpr_tid, SIGTHR);
+#endif
+
+ /*
+ * If the process is currently idling in dt_proc_stop(), re-
+ * enable breakpoints and poke it into running again.
+ */
+ if (dpr->dpr_stop & DT_PROC_STOP_IDLE) {
+ dt_proc_bpenable(dpr);
+ dpr->dpr_stop &= ~DT_PROC_STOP_IDLE;
+ (void) pthread_cond_broadcast(&dpr->dpr_cv);
+ }
+
+ while (!dpr->dpr_done)
+ (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
+
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+ }
+
+ /*
+ * Before we free the process structure, remove this dt_proc_t from the
+ * lookup hash, and then walk the dt_proc_hash_t's notification list
+ * and remove this dt_proc_t if it is enqueued.
+ */
+ (void) pthread_mutex_lock(&dph->dph_lock);
+ (void) dt_proc_lookup(dtp, P, B_TRUE);
+ npp = &dph->dph_notify;
+
+ while ((npr = *npp) != NULL) {
+ if (npr->dprn_dpr == dpr) {
+ *npp = npr->dprn_next;
+ dt_free(dtp, npr);
+ } else {
+ npp = &npr->dprn_next;
+ }
+ }
+
+ (void) pthread_mutex_unlock(&dph->dph_lock);
+
+ /*
+ * Remove the dt_proc_list from the LRU list, release the underlying
+ * libproc handle, and free our dt_proc_t data structure.
+ */
+ if (dpr->dpr_cacheable) {
+ assert(dph->dph_lrucnt != 0);
+ dph->dph_lrucnt--;
+ }
+
+ dt_list_delete(&dph->dph_lrulist, dpr);
+ Prelease(dpr->dpr_proc, rflag);
+ dt_free(dtp, dpr);
+}
+
+static int
+dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
+{
+ dt_proc_control_data_t data;
+ sigset_t nset, oset;
+ pthread_attr_t a;
+ int err;
+
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+ dpr->dpr_stop |= stop; /* set bit for initial rendezvous */
+
+ (void) pthread_attr_init(&a);
+ (void) pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
+
+ (void) sigfillset(&nset);
+ (void) sigdelset(&nset, SIGABRT); /* unblocked for assert() */
+#ifdef illumos
+ (void) sigdelset(&nset, SIGCANCEL); /* see dt_proc_destroy() */
+#else
+ (void) sigdelset(&nset, SIGUSR1); /* see dt_proc_destroy() */
+#endif
+
+ data.dpcd_hdl = dtp;
+ data.dpcd_proc = dpr;
+
+ (void) pthread_sigmask(SIG_SETMASK, &nset, &oset);
+ err = pthread_create(&dpr->dpr_tid, &a, dt_proc_control, &data);
+ (void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
+
+ /*
+ * If the control thread was created, then wait on dpr_cv for either
+ * dpr_done to be set (the victim died or the control thread failed)
+ * or DT_PROC_STOP_IDLE to be set, indicating that the victim is now
+ * stopped by /proc and the control thread is at the rendezvous event.
+ * On success, we return with the process and control thread stopped:
+ * the caller can then apply dt_proc_continue() to resume both.
+ */
+ if (err == 0) {
+ while (!dpr->dpr_done && !(dpr->dpr_stop & DT_PROC_STOP_IDLE))
+ (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
+
+ /*
+ * If dpr_done is set, the control thread aborted before it
+ * reached the rendezvous event. This is either due to PS_LOST
+ * or PS_UNDEAD (i.e. the process died). We try to provide a
+ * small amount of useful information to help figure it out.
+ */
+ if (dpr->dpr_done) {
+#ifdef illumos
+ const psinfo_t *prp = Ppsinfo(dpr->dpr_proc);
+ int stat = prp ? prp->pr_wstat : 0;
+ int pid = dpr->dpr_pid;
+#else
+ int stat = proc_getwstat(dpr->dpr_proc);
+ int pid = proc_getpid(dpr->dpr_proc);
+#endif
+ if (proc_state(dpr->dpr_proc) == PS_LOST) {
+ (void) dt_proc_error(dpr->dpr_hdl, dpr,
+ "failed to control pid %d: process exec'd "
+ "set-id or unobservable program\n", pid);
+ } else if (WIFSIGNALED(stat)) {
+ (void) dt_proc_error(dpr->dpr_hdl, dpr,
+ "failed to control pid %d: process died "
+ "from signal %d\n", pid, WTERMSIG(stat));
+ } else {
+ (void) dt_proc_error(dpr->dpr_hdl, dpr,
+ "failed to control pid %d: process exited "
+ "with status %d\n", pid, WEXITSTATUS(stat));
+ }
+
+ err = ESRCH; /* cause grab() or create() to fail */
+ }
+ } else {
+ (void) dt_proc_error(dpr->dpr_hdl, dpr,
+ "failed to create control thread for process-id %d: %s\n",
+ (int)dpr->dpr_pid, strerror(err));
+ }
+
+ if (err == 0)
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+ (void) pthread_attr_destroy(&a);
+
+ return (err);
+}
+
+struct ps_prochandle *
+dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv,
+ proc_child_func *pcf, void *child_arg)
+{
+ dt_proc_hash_t *dph = dtp->dt_procs;
+ dt_proc_t *dpr;
+ int err;
+
+ if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL)
+ return (NULL); /* errno is set for us */
+
+ (void) pthread_mutex_init(&dpr->dpr_lock, NULL);
+ (void) pthread_cond_init(&dpr->dpr_cv, NULL);
+
+#ifdef illumos
+ dpr->dpr_proc = Pxcreate(file, argv, dtp->dt_proc_env, &err, NULL, 0);
+ if (dpr->dpr_proc == NULL) {
+ return (dt_proc_error(dtp, dpr,
+ "failed to execute %s: %s\n", file, Pcreate_error(err)));
+ }
+#else
+ if ((err = proc_create(file, argv, dtp->dt_proc_env, pcf, child_arg,
+ &dpr->dpr_proc)) != 0) {
+ return (dt_proc_error(dtp, dpr,
+ "failed to execute %s: %s\n", file, Pcreate_error(err)));
+ }
+#endif
+
+ dpr->dpr_hdl = dtp;
+#ifdef illumos
+ dpr->dpr_pid = Pstatus(dpr->dpr_proc)->pr_pid;
+#else
+ dpr->dpr_pid = proc_getpid(dpr->dpr_proc);
+#endif
+
+ (void) Punsetflags(dpr->dpr_proc, PR_RLC);
+ (void) Psetflags(dpr->dpr_proc, PR_KLC);
+
+ if (dt_proc_create_thread(dtp, dpr, dtp->dt_prcmode) != 0)
+ return (NULL); /* dt_proc_error() has been called for us */
+
+ dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)];
+ dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)] = dpr;
+ dt_list_prepend(&dph->dph_lrulist, dpr);
+
+ dt_dprintf("created pid %d\n", (int)dpr->dpr_pid);
+ dpr->dpr_refs++;
+
+ return (dpr->dpr_proc);
+}
+
+struct ps_prochandle *
+dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor)
+{
+ dt_proc_hash_t *dph = dtp->dt_procs;
+ uint_t h = pid & (dph->dph_hashlen - 1);
+ dt_proc_t *dpr, *opr;
+ int err;
+
+ /*
+ * Search the hash table for the pid. If it is already grabbed or
+ * created, move the handle to the front of the lrulist, increment
+ * the reference count, and return the existing ps_prochandle.
+ */
+ for (dpr = dph->dph_hash[h]; dpr != NULL; dpr = dpr->dpr_hash) {
+ if (dpr->dpr_pid == pid && !dpr->dpr_stale) {
+ /*
+ * If the cached handle was opened read-only and
+ * this request is for a writeable handle, mark
+ * the cached handle as stale and open a new handle.
+ * Since it's stale, unmark it as cacheable.
+ */
+ if (dpr->dpr_rdonly && !(flags & PGRAB_RDONLY)) {
+ dt_dprintf("upgrading pid %d\n", (int)pid);
+ dpr->dpr_stale = B_TRUE;
+ dpr->dpr_cacheable = B_FALSE;
+ dph->dph_lrucnt--;
+ break;
+ }
+
+ dt_dprintf("grabbed pid %d (cached)\n", (int)pid);
+ dt_list_delete(&dph->dph_lrulist, dpr);
+ dt_list_prepend(&dph->dph_lrulist, dpr);
+ dpr->dpr_refs++;
+ return (dpr->dpr_proc);
+ }
+ }
+
+ if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL)
+ return (NULL); /* errno is set for us */
+
+ (void) pthread_mutex_init(&dpr->dpr_lock, NULL);
+ (void) pthread_cond_init(&dpr->dpr_cv, NULL);
+
+#ifdef illumos
+ if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) {
+#else
+ if ((err = proc_attach(pid, flags, &dpr->dpr_proc)) != 0) {
+#endif
+ return (dt_proc_error(dtp, dpr,
+ "failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err)));
+ }
+
+ dpr->dpr_hdl = dtp;
+ dpr->dpr_pid = pid;
+
+ (void) Punsetflags(dpr->dpr_proc, PR_KLC);
+ (void) Psetflags(dpr->dpr_proc, PR_RLC);
+
+ /*
+ * If we are attempting to grab the process without a monitor
+ * thread, then mark the process cacheable only if it's being
+ * grabbed read-only. If we're currently caching more process
+ * handles than dph_lrulim permits, attempt to find the
+ * least-recently-used handle that is currently unreferenced and
+ * release it from the cache. Otherwise we are grabbing the process
+ * for control: create a control thread for this process and store
+ * its ID in dpr->dpr_tid.
+ */
+ if (nomonitor || (flags & PGRAB_RDONLY)) {
+ if (dph->dph_lrucnt >= dph->dph_lrulim) {
+ for (opr = dt_list_prev(&dph->dph_lrulist);
+ opr != NULL; opr = dt_list_prev(opr)) {
+ if (opr->dpr_cacheable && opr->dpr_refs == 0) {
+ dt_proc_destroy(dtp, opr->dpr_proc);
+ break;
+ }
+ }
+ }
+
+ if (flags & PGRAB_RDONLY) {
+ dpr->dpr_cacheable = B_TRUE;
+ dpr->dpr_rdonly = B_TRUE;
+ dph->dph_lrucnt++;
+ }
+
+ } else if (dt_proc_create_thread(dtp, dpr, DT_PROC_STOP_GRAB) != 0)
+ return (NULL); /* dt_proc_error() has been called for us */
+
+ dpr->dpr_hash = dph->dph_hash[h];
+ dph->dph_hash[h] = dpr;
+ dt_list_prepend(&dph->dph_lrulist, dpr);
+
+ dt_dprintf("grabbed pid %d\n", (int)pid);
+ dpr->dpr_refs++;
+
+ return (dpr->dpr_proc);
+}
+
+void
+dt_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P)
+{
+ dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
+ dt_proc_hash_t *dph = dtp->dt_procs;
+
+ assert(dpr != NULL);
+ assert(dpr->dpr_refs != 0);
+
+ if (--dpr->dpr_refs == 0 &&
+ (!dpr->dpr_cacheable || dph->dph_lrucnt > dph->dph_lrulim))
+ dt_proc_destroy(dtp, P);
+}
+
+void
+dt_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P)
+{
+ dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
+
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+
+ if (dpr->dpr_stop & DT_PROC_STOP_IDLE) {
+ dpr->dpr_stop &= ~DT_PROC_STOP_IDLE;
+ (void) pthread_cond_broadcast(&dpr->dpr_cv);
+ }
+
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+}
+
+void
+dt_proc_lock(dtrace_hdl_t *dtp, struct ps_prochandle *P)
+{
+ dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
+ int err = pthread_mutex_lock(&dpr->dpr_lock);
+ assert(err == 0); /* check for recursion */
+}
+
+void
+dt_proc_unlock(dtrace_hdl_t *dtp, struct ps_prochandle *P)
+{
+ dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
+ int err = pthread_mutex_unlock(&dpr->dpr_lock);
+ assert(err == 0); /* check for unheld lock */
+}
+
+void
+dt_proc_init(dtrace_hdl_t *dtp)
+{
+ extern char **environ;
+ static char *envdef[] = {
+ "LD_NOLAZYLOAD=1", /* linker lazy loading hides funcs */
+ NULL
+ };
+ char **p;
+ int i;
+
+ if ((dtp->dt_procs = dt_zalloc(dtp, sizeof (dt_proc_hash_t) +
+ sizeof (dt_proc_t *) * _dtrace_pidbuckets - 1)) == NULL)
+ return;
+
+ (void) pthread_mutex_init(&dtp->dt_procs->dph_lock, NULL);
+ (void) pthread_cond_init(&dtp->dt_procs->dph_cv, NULL);
+
+ dtp->dt_procs->dph_hashlen = _dtrace_pidbuckets;
+ dtp->dt_procs->dph_lrulim = _dtrace_pidlrulim;
+
+ /*
+ * Count how big our environment needs to be.
+ */
+ for (i = 1, p = environ; *p != NULL; i++, p++)
+ continue;
+ for (p = envdef; *p != NULL; i++, p++)
+ continue;
+
+ if ((dtp->dt_proc_env = dt_zalloc(dtp, sizeof (char *) * i)) == NULL)
+ return;
+
+ for (i = 0, p = environ; *p != NULL; i++, p++) {
+ if ((dtp->dt_proc_env[i] = strdup(*p)) == NULL)
+ goto err;
+ }
+ for (p = envdef; *p != NULL; i++, p++) {
+ if ((dtp->dt_proc_env[i] = strdup(*p)) == NULL)
+ goto err;
+ }
+
+ return;
+
+err:
+ while (--i != 0) {
+ dt_free(dtp, dtp->dt_proc_env[i]);
+ }
+ dt_free(dtp, dtp->dt_proc_env);
+ dtp->dt_proc_env = NULL;
+}
+
+void
+dt_proc_fini(dtrace_hdl_t *dtp)
+{
+ dt_proc_hash_t *dph = dtp->dt_procs;
+ dt_proc_t *dpr;
+ char **p;
+
+ while ((dpr = dt_list_next(&dph->dph_lrulist)) != NULL)
+ dt_proc_destroy(dtp, dpr->dpr_proc);
+
+ dtp->dt_procs = NULL;
+ dt_free(dtp, dph);
+
+ for (p = dtp->dt_proc_env; *p != NULL; p++)
+ dt_free(dtp, *p);
+
+ dt_free(dtp, dtp->dt_proc_env);
+ dtp->dt_proc_env = NULL;
+}
+
+struct ps_prochandle *
+dtrace_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv,
+ proc_child_func *pcf, void *child_arg)
+{
+ dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
+ struct ps_prochandle *P = dt_proc_create(dtp, file, argv, pcf, child_arg);
+
+ if (P != NULL && idp != NULL && idp->di_id == 0) {
+#ifdef illumos
+ idp->di_id = Pstatus(P)->pr_pid; /* $target = created pid */
+#else
+ idp->di_id = proc_getpid(P); /* $target = created pid */
+#endif
+ }
+
+ return (P);
+}
+
+struct ps_prochandle *
+dtrace_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags)
+{
+ dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
+ struct ps_prochandle *P = dt_proc_grab(dtp, pid, flags, 0);
+
+ if (P != NULL && idp != NULL && idp->di_id == 0)
+ idp->di_id = pid; /* $target = grabbed pid */
+
+ return (P);
+}
+
+void
+dtrace_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P)
+{
+ dt_proc_release(dtp, P);
+}
+
+void
+dtrace_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P)
+{
+ dt_proc_continue(dtp, P);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h
new file mode 100644
index 000000000000..beae6f6d5cda
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h
@@ -0,0 +1,118 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#ifndef _DT_PROC_H
+#define _DT_PROC_H
+
+#include <libproc.h>
+#include <dtrace.h>
+#include <pthread.h>
+#include <dt_list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct dt_proc {
+ dt_list_t dpr_list; /* prev/next pointers for lru chain */
+ struct dt_proc *dpr_hash; /* next pointer for pid hash chain */
+ dtrace_hdl_t *dpr_hdl; /* back pointer to libdtrace handle */
+ struct ps_prochandle *dpr_proc; /* proc handle for libproc calls */
+ char dpr_errmsg[BUFSIZ]; /* error message */
+ rd_agent_t *dpr_rtld; /* rtld handle for librtld_db calls */
+ pthread_mutex_t dpr_lock; /* lock for manipulating dpr_hdl */
+ pthread_cond_t dpr_cv; /* cond for dpr_stop/quit/done */
+ pid_t dpr_pid; /* pid of process */
+ uint_t dpr_refs; /* reference count */
+ uint8_t dpr_cacheable; /* cache handle using lru list */
+ uint8_t dpr_stop; /* stop mask: see flag bits below */
+ uint8_t dpr_quit; /* quit flag: ctl thread should quit */
+ uint8_t dpr_done; /* done flag: ctl thread has exited */
+ uint8_t dpr_usdt; /* usdt flag: usdt initialized */
+ uint8_t dpr_stale; /* proc flag: been deprecated */
+ uint8_t dpr_rdonly; /* proc flag: opened read-only */
+ pthread_t dpr_tid; /* control thread (or zero if none) */
+ dt_list_t dpr_bps; /* list of dt_bkpt_t structures */
+} dt_proc_t;
+
+typedef struct dt_proc_notify {
+ dt_proc_t *dprn_dpr; /* process associated with the event */
+ char dprn_errmsg[BUFSIZ]; /* error message */
+ struct dt_proc_notify *dprn_next; /* next pointer */
+} dt_proc_notify_t;
+
+#define DT_PROC_STOP_IDLE 0x01 /* idle on owner's stop request */
+#define DT_PROC_STOP_CREATE 0x02 /* wait on dpr_cv at process exec */
+#define DT_PROC_STOP_GRAB 0x04 /* wait on dpr_cv at process grab */
+#define DT_PROC_STOP_PREINIT 0x08 /* wait on dpr_cv at rtld preinit */
+#define DT_PROC_STOP_POSTINIT 0x10 /* wait on dpr_cv at rtld postinit */
+#define DT_PROC_STOP_MAIN 0x20 /* wait on dpr_cv at a.out`main() */
+
+typedef void dt_bkpt_f(dtrace_hdl_t *, dt_proc_t *, void *);
+
+typedef struct dt_bkpt {
+ dt_list_t dbp_list; /* prev/next pointers for bkpt list */
+ dt_bkpt_f *dbp_func; /* callback function to execute */
+ void *dbp_data; /* callback function private data */
+ uintptr_t dbp_addr; /* virtual address of breakpoint */
+ ulong_t dbp_instr; /* saved instruction from breakpoint */
+ ulong_t dbp_hits; /* count of breakpoint hits for debug */
+ int dbp_active; /* flag indicating breakpoint is on */
+} dt_bkpt_t;
+
+typedef struct dt_proc_hash {
+ pthread_mutex_t dph_lock; /* lock protecting dph_notify list */
+ pthread_cond_t dph_cv; /* cond for waiting for dph_notify */
+ dt_proc_notify_t *dph_notify; /* list of pending proc notifications */
+ dt_list_t dph_lrulist; /* list of dt_proc_t's in lru order */
+ uint_t dph_lrulim; /* limit on number of procs to hold */
+ uint_t dph_lrucnt; /* count of cached process handles */
+ uint_t dph_hashlen; /* size of hash chains array */
+ dt_proc_t *dph_hash[1]; /* hash chains array */
+} dt_proc_hash_t;
+
+extern struct ps_prochandle *dt_proc_create(dtrace_hdl_t *,
+ const char *, char *const *, proc_child_func *, void *);
+
+extern struct ps_prochandle *dt_proc_grab(dtrace_hdl_t *, pid_t, int, int);
+extern void dt_proc_release(dtrace_hdl_t *, struct ps_prochandle *);
+extern void dt_proc_continue(dtrace_hdl_t *, struct ps_prochandle *);
+extern void dt_proc_lock(dtrace_hdl_t *, struct ps_prochandle *);
+extern void dt_proc_unlock(dtrace_hdl_t *, struct ps_prochandle *);
+extern dt_proc_t *dt_proc_lookup(dtrace_hdl_t *, struct ps_prochandle *, int);
+
+extern void dt_proc_init(dtrace_hdl_t *);
+extern void dt_proc_fini(dtrace_hdl_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_PROC_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c
new file mode 100644
index 000000000000..232a3723b11d
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c
@@ -0,0 +1,626 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ */
+
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+
+#include <dt_impl.h>
+#include <dt_program.h>
+#include <dt_printf.h>
+#include <dt_provider.h>
+
+dtrace_prog_t *
+dt_program_create(dtrace_hdl_t *dtp)
+{
+ dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
+
+ if (pgp != NULL) {
+ dt_list_append(&dtp->dt_programs, pgp);
+ } else {
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+ return (NULL);
+ }
+
+ /*
+ * 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);
+}
+
+void
+dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
+{
+ dt_stmt_t *stp, *next;
+ uint_t i;
+
+ for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
+ next = dt_list_next(stp);
+ dtrace_stmt_destroy(dtp, stp->ds_desc);
+ dt_free(dtp, stp);
+ }
+
+ for (i = 0; i < pgp->dp_xrefslen; i++)
+ dt_free(dtp, pgp->dp_xrefs[i]);
+
+ dt_free(dtp, pgp->dp_xrefs);
+ dt_list_delete(&dtp->dt_programs, pgp);
+ dt_free(dtp, pgp);
+}
+
+/*ARGSUSED*/
+void
+dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
+ dtrace_proginfo_t *pip)
+{
+ dt_stmt_t *stp;
+ dtrace_actdesc_t *ap;
+ dtrace_ecbdesc_t *last = NULL;
+
+ if (pip == NULL)
+ return;
+
+ bzero(pip, sizeof (dtrace_proginfo_t));
+
+ if (dt_list_next(&pgp->dp_stmts) != NULL) {
+ pip->dpi_descattr = _dtrace_maxattr;
+ pip->dpi_stmtattr = _dtrace_maxattr;
+ } else {
+ pip->dpi_descattr = _dtrace_defattr;
+ pip->dpi_stmtattr = _dtrace_defattr;
+ }
+
+ for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
+ dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
+
+ if (edp == last)
+ continue;
+ last = edp;
+
+ pip->dpi_descattr =
+ dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
+
+ pip->dpi_stmtattr =
+ dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
+
+ /*
+ * If there aren't any actions, account for the fact that
+ * recording the epid will generate a record.
+ */
+ if (edp->dted_action == NULL)
+ pip->dpi_recgens++;
+
+ for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
+ if (ap->dtad_kind == DTRACEACT_SPECULATE) {
+ pip->dpi_speculations++;
+ continue;
+ }
+
+ if (DTRACEACT_ISAGG(ap->dtad_kind)) {
+ pip->dpi_recgens -= ap->dtad_arg;
+ pip->dpi_aggregates++;
+ continue;
+ }
+
+ if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
+ continue;
+
+ if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
+ ap->dtad_difo->dtdo_rtype.dtdt_kind ==
+ DIF_TYPE_CTF &&
+ ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
+ continue;
+
+ pip->dpi_recgens++;
+ }
+ }
+}
+
+int
+dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
+ dtrace_proginfo_t *pip)
+{
+ dtrace_enable_io_t args;
+ void *dof;
+ int n, err;
+
+ dtrace_program_info(dtp, pgp, pip);
+
+ if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
+ return (-1);
+
+ args.dof = dof;
+ args.n_matched = 0;
+ n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
+ dtrace_dof_destroy(dtp, dof);
+
+ if (n == -1) {
+ switch (errno) {
+ case EINVAL:
+ err = EDT_DIFINVAL;
+ break;
+ case EFAULT:
+ err = EDT_DIFFAULT;
+ break;
+ case E2BIG:
+ err = EDT_DIFSIZE;
+ break;
+ case EBUSY:
+ err = EDT_ENABLING_ERR;
+ break;
+ default:
+ err = errno;
+ }
+
+ return (dt_set_errno(dtp, err));
+ }
+
+ if (pip != NULL)
+ pip->dpi_matches += args.n_matched;
+
+ return (0);
+}
+
+static void
+dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
+{
+ edp->dted_refcnt++;
+}
+
+void
+dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
+{
+ if (--edp->dted_refcnt > 0)
+ return;
+
+ dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
+ assert(edp->dted_action == NULL);
+ dt_free(dtp, edp);
+}
+
+dtrace_ecbdesc_t *
+dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
+{
+ dtrace_ecbdesc_t *edp;
+
+ if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+ return (NULL);
+ }
+
+ edp->dted_probe = *pdp;
+ dt_ecbdesc_hold(edp);
+ return (edp);
+}
+
+dtrace_stmtdesc_t *
+dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
+{
+ dtrace_stmtdesc_t *sdp;
+
+ if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
+ return (NULL);
+
+ dt_ecbdesc_hold(edp);
+ sdp->dtsd_ecbdesc = edp;
+ sdp->dtsd_descattr = _dtrace_defattr;
+ sdp->dtsd_stmtattr = _dtrace_defattr;
+
+ return (sdp);
+}
+
+dtrace_actdesc_t *
+dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *new;
+ dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
+
+ if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
+ return (NULL);
+
+ if (sdp->dtsd_action_last != NULL) {
+ assert(sdp->dtsd_action != NULL);
+ assert(sdp->dtsd_action_last->dtad_next == NULL);
+ sdp->dtsd_action_last->dtad_next = new;
+ } else {
+ dtrace_actdesc_t *ap = edp->dted_action;
+
+ assert(sdp->dtsd_action == NULL);
+ sdp->dtsd_action = new;
+
+ while (ap != NULL && ap->dtad_next != NULL)
+ ap = ap->dtad_next;
+
+ if (ap == NULL)
+ edp->dted_action = new;
+ else
+ ap->dtad_next = new;
+ }
+
+ sdp->dtsd_action_last = new;
+ bzero(new, sizeof (dtrace_actdesc_t));
+ new->dtad_uarg = (uintptr_t)sdp;
+
+ return (new);
+}
+
+int
+dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
+{
+ dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ dt_list_append(&pgp->dp_stmts, stp);
+ stp->ds_desc = sdp;
+
+ return (0);
+}
+
+int
+dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
+ dtrace_stmt_f *func, void *data)
+{
+ dt_stmt_t *stp, *next;
+ int status = 0;
+
+ for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
+ next = dt_list_next(stp);
+ if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
+ break;
+ }
+
+ return (status);
+}
+
+void
+dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
+
+ /*
+ * We need to remove any actions that we have on this ECB, and
+ * remove our hold on the ECB itself.
+ */
+ if (sdp->dtsd_action != NULL) {
+ dtrace_actdesc_t *last = sdp->dtsd_action_last;
+ dtrace_actdesc_t *ap, *next;
+
+ assert(last != NULL);
+
+ for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
+ if (ap == sdp->dtsd_action)
+ break;
+
+ if (ap->dtad_next == sdp->dtsd_action)
+ break;
+ }
+
+ assert(ap != NULL);
+
+ if (ap == edp->dted_action)
+ edp->dted_action = last->dtad_next;
+ else
+ ap->dtad_next = last->dtad_next;
+
+ /*
+ * We have now removed our action list from its ECB; we can
+ * safely destroy the list.
+ */
+ last->dtad_next = NULL;
+
+ for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
+ assert(ap->dtad_uarg == (uintptr_t)sdp);
+ dt_difo_free(dtp, ap->dtad_difo);
+ next = ap->dtad_next;
+ dt_free(dtp, ap);
+ }
+ }
+
+ if (sdp->dtsd_fmtdata != NULL)
+ dt_printf_destroy(sdp->dtsd_fmtdata);
+ dt_free(dtp, sdp->dtsd_strdata);
+
+ dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
+ dt_free(dtp, sdp);
+}
+
+typedef struct dt_header_info {
+ dtrace_hdl_t *dthi_dtp; /* consumer handle */
+ FILE *dthi_out; /* output file */
+ char *dthi_pmname; /* provider macro name */
+ char *dthi_pfname; /* provider function name */
+ int dthi_empty; /* should we generate empty macros */
+} dt_header_info_t;
+
+static void
+dt_header_fmt_macro(char *buf, const char *str)
+{
+ for (;;) {
+ if (islower(*str)) {
+ *buf++ = *str++ + 'A' - 'a';
+ } else if (*str == '-') {
+ *buf++ = '_';
+ str++;
+ } else if (*str == '.') {
+ *buf++ = '_';
+ str++;
+ } else if ((*buf++ = *str++) == '\0') {
+ break;
+ }
+ }
+}
+
+static void
+dt_header_fmt_func(char *buf, const char *str)
+{
+ for (;;) {
+ if (*str == '-') {
+ *buf++ = '_';
+ *buf++ = '_';
+ str++;
+ } else if ((*buf++ = *str++) == '\0') {
+ break;
+ }
+ }
+}
+
+/*ARGSUSED*/
+static int
+dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
+{
+ dt_header_info_t *infop = data;
+ dtrace_hdl_t *dtp = infop->dthi_dtp;
+ dt_probe_t *prp = idp->di_data;
+ dt_node_t *dnp;
+ char buf[DT_TYPE_NAMELEN];
+ char *fname;
+ const char *p;
+ int i;
+
+ p = prp->pr_name;
+ for (i = 0; (p = strchr(p, '-')) != NULL; i++)
+ p++;
+
+ fname = alloca(strlen(prp->pr_name) + 1 + i);
+ dt_header_fmt_func(fname, prp->pr_name);
+
+ if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
+ infop->dthi_pfname, fname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
+ if (fprintf(infop->dthi_out, "%s",
+ ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
+ buf, sizeof (buf))) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (i + 1 != prp->pr_nargc &&
+ fprintf(infop->dthi_out, ", ") < 0)
+ return (dt_set_errno(dtp, errno));
+ }
+
+ if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (fprintf(infop->dthi_out, ");\n") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (fprintf(infop->dthi_out,
+ "#ifndef\t__sparc\n"
+ "extern int __dtraceenabled_%s___%s(void);\n"
+ "#else\n"
+ "extern int __dtraceenabled_%s___%s(long);\n"
+ "#endif\n",
+ infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
+{
+ dt_header_info_t *infop = data;
+ dtrace_hdl_t *dtp = infop->dthi_dtp;
+ dt_probe_t *prp = idp->di_data;
+ char *mname, *fname;
+ const char *p;
+ int i;
+
+ p = prp->pr_name;
+ for (i = 0; (p = strchr(p, '-')) != NULL; i++)
+ p++;
+
+ mname = alloca(strlen(prp->pr_name) + 1);
+ dt_header_fmt_macro(mname, prp->pr_name);
+
+ fname = alloca(strlen(prp->pr_name) + 1 + i);
+ dt_header_fmt_func(fname, prp->pr_name);
+
+ if (fprintf(infop->dthi_out, "#define\t%s_%s(",
+ infop->dthi_pmname, mname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ for (i = 0; i < prp->pr_nargc; i++) {
+ if (fprintf(infop->dthi_out, "arg%d", i) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (i + 1 != prp->pr_nargc &&
+ fprintf(infop->dthi_out, ", ") < 0)
+ return (dt_set_errno(dtp, errno));
+ }
+
+ if (!infop->dthi_empty) {
+ if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
+ infop->dthi_pfname, fname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ for (i = 0; i < prp->pr_nargc; i++) {
+ if (fprintf(infop->dthi_out, "arg%d", i) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (i + 1 != prp->pr_nargc &&
+ fprintf(infop->dthi_out, ", ") < 0)
+ return (dt_set_errno(dtp, errno));
+ }
+ }
+
+ if (fprintf(infop->dthi_out, ")\n") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (!infop->dthi_empty) {
+ if (fprintf(infop->dthi_out,
+ "#ifndef\t__sparc\n"
+ "#define\t%s_%s_ENABLED() \\\n"
+ "\t__dtraceenabled_%s___%s()\n"
+ "#else\n"
+ "#define\t%s_%s_ENABLED() \\\n"
+ "\t__dtraceenabled_%s___%s(0)\n"
+ "#endif\n",
+ infop->dthi_pmname, mname,
+ infop->dthi_pfname, fname,
+ infop->dthi_pmname, mname,
+ infop->dthi_pfname, fname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ } else {
+ if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
+ infop->dthi_pmname, mname) < 0)
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (0);
+}
+
+static int
+dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
+{
+ dt_header_info_t info;
+ const char *p;
+ int i;
+
+ if (pvp->pv_flags & DT_PROVIDER_IMPL)
+ return (0);
+
+ /*
+ * Count the instances of the '-' character since we'll need to double
+ * those up.
+ */
+ p = pvp->pv_desc.dtvd_name;
+ for (i = 0; (p = strchr(p, '-')) != NULL; i++)
+ p++;
+
+ info.dthi_dtp = dtp;
+ info.dthi_out = out;
+ info.dthi_empty = 0;
+
+ info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
+ dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
+
+ info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
+ dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
+
+#ifdef __FreeBSD__
+ if (fprintf(out, "#include <sys/sdt.h>\n\n") < 0)
+ return (dt_set_errno(dtp, errno));
+#endif
+ if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
+ return (-1); /* dt_errno is set for us */
+ if (fprintf(out, "\n\n") < 0)
+ return (dt_set_errno(dtp, errno));
+ if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
+ return (-1); /* dt_errno is set for us */
+
+ if (fprintf(out, "\n#else\n\n") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ info.dthi_empty = 1;
+
+ if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
+ return (-1); /* dt_errno is set for us */
+
+ if (fprintf(out, "\n#endif\n\n") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ return (0);
+}
+
+int
+dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
+{
+ dt_provider_t *pvp;
+ char *mfname, *p;
+
+ if (fname != NULL) {
+ if ((p = strrchr(fname, '/')) != NULL)
+ fname = p + 1;
+
+ mfname = alloca(strlen(fname) + 1);
+ dt_header_fmt_macro(mfname, fname);
+ if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
+ mfname, mfname) < 0)
+ return (dt_set_errno(dtp, errno));
+ }
+
+ if (fprintf(out, "#include <unistd.h>\n\n") < 0)
+ return (-1);
+
+ if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
+ return (-1);
+
+ for (pvp = dt_list_next(&dtp->dt_provlist);
+ pvp != NULL; pvp = dt_list_next(pvp)) {
+ if (dt_header_provider(dtp, pvp, out) != 0)
+ return (-1); /* dt_errno is set for us */
+ }
+
+ if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.h
new file mode 100644
index 000000000000..3fe1c39136fa
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.h
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_PROGRAM_H
+#define _DT_PROGRAM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dtrace.h>
+#include <dt_list.h>
+
+typedef struct dt_stmt {
+ dt_list_t ds_list; /* list forward/back pointers */
+ dtrace_stmtdesc_t *ds_desc; /* pointer to statement description */
+} dt_stmt_t;
+
+struct dtrace_prog {
+ dt_list_t dp_list; /* list forward/back pointers */
+ 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 *);
+extern void dt_program_destroy(dtrace_hdl_t *, dtrace_prog_t *);
+
+extern dtrace_ecbdesc_t *dt_ecbdesc_create(dtrace_hdl_t *,
+ const dtrace_probedesc_t *);
+extern void dt_ecbdesc_release(dtrace_hdl_t *, dtrace_ecbdesc_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_PROGRAM_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c
new file mode 100644
index 000000000000..7cf352d4d505
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c
@@ -0,0 +1,900 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#ifdef illumos
+#include <sys/sysmacros.h>
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <strings.h>
+#include <stdlib.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+
+#include <dt_provider.h>
+#include <dt_module.h>
+#include <dt_string.h>
+#include <dt_list.h>
+#include <dt_pid.h>
+#include <dtrace.h>
+
+static dt_provider_t *
+dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h)
+{
+ dt_list_append(&dtp->dt_provlist, pvp);
+
+ pvp->pv_next = dtp->dt_provs[h];
+ dtp->dt_provs[h] = pvp;
+ dtp->dt_nprovs++;
+
+ return (pvp);
+}
+
+dt_provider_t *
+dt_provider_lookup(dtrace_hdl_t *dtp, const char *name)
+{
+ uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_provbuckets;
+ dtrace_providerdesc_t desc;
+ dt_provider_t *pvp;
+
+ for (pvp = dtp->dt_provs[h]; pvp != NULL; pvp = pvp->pv_next) {
+ if (strcmp(pvp->pv_desc.dtvd_name, name) == 0)
+ return (pvp);
+ }
+
+ if (strisglob(name) || name[0] == '\0') {
+ (void) dt_set_errno(dtp, EDT_NOPROV);
+ return (NULL);
+ }
+
+ bzero(&desc, sizeof (desc));
+ (void) strlcpy(desc.dtvd_name, name, DTRACE_PROVNAMELEN);
+
+ if (dt_ioctl(dtp, DTRACEIOC_PROVIDER, &desc) == -1) {
+ (void) dt_set_errno(dtp, errno == ESRCH ? EDT_NOPROV : errno);
+ return (NULL);
+ }
+
+ if ((pvp = dt_provider_create(dtp, name)) == NULL)
+ return (NULL); /* dt_errno is set for us */
+
+ bcopy(&desc, &pvp->pv_desc, sizeof (desc));
+ pvp->pv_flags |= DT_PROVIDER_IMPL;
+ return (pvp);
+}
+
+dt_provider_t *
+dt_provider_create(dtrace_hdl_t *dtp, const char *name)
+{
+ dt_provider_t *pvp;
+
+ if ((pvp = dt_zalloc(dtp, sizeof (dt_provider_t))) == NULL)
+ return (NULL);
+
+ (void) strlcpy(pvp->pv_desc.dtvd_name, name, DTRACE_PROVNAMELEN);
+ pvp->pv_probes = dt_idhash_create(pvp->pv_desc.dtvd_name, NULL, 0, 0);
+ pvp->pv_gen = dtp->dt_gen;
+ pvp->pv_hdl = dtp;
+
+ if (pvp->pv_probes == NULL) {
+ dt_free(dtp, pvp);
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+ return (NULL);
+ }
+
+ pvp->pv_desc.dtvd_attr.dtpa_provider = _dtrace_prvattr;
+ pvp->pv_desc.dtvd_attr.dtpa_mod = _dtrace_prvattr;
+ pvp->pv_desc.dtvd_attr.dtpa_func = _dtrace_prvattr;
+ pvp->pv_desc.dtvd_attr.dtpa_name = _dtrace_prvattr;
+ pvp->pv_desc.dtvd_attr.dtpa_args = _dtrace_prvattr;
+
+ return (dt_provider_insert(dtp, pvp,
+ dt_strtab_hash(name, NULL) % dtp->dt_provbuckets));
+}
+
+void
+dt_provider_destroy(dtrace_hdl_t *dtp, dt_provider_t *pvp)
+{
+ dt_provider_t **pp;
+ uint_t h;
+
+ assert(pvp->pv_hdl == dtp);
+
+ h = dt_strtab_hash(pvp->pv_desc.dtvd_name, NULL) % dtp->dt_provbuckets;
+ pp = &dtp->dt_provs[h];
+
+ while (*pp != NULL && *pp != pvp)
+ pp = &(*pp)->pv_next;
+
+ assert(*pp != NULL && *pp == pvp);
+ *pp = pvp->pv_next;
+
+ dt_list_delete(&dtp->dt_provlist, pvp);
+ dtp->dt_nprovs--;
+
+ if (pvp->pv_probes != NULL)
+ dt_idhash_destroy(pvp->pv_probes);
+
+ dt_node_link_free(&pvp->pv_nodes);
+ dt_free(dtp, pvp->pv_xrefs);
+ dt_free(dtp, pvp);
+}
+
+int
+dt_provider_xref(dtrace_hdl_t *dtp, dt_provider_t *pvp, id_t id)
+{
+ size_t oldsize = BT_SIZEOFMAP(pvp->pv_xrmax);
+ size_t newsize = BT_SIZEOFMAP(dtp->dt_xlatorid);
+
+ assert(id >= 0 && id < dtp->dt_xlatorid);
+
+ if (newsize > oldsize) {
+ ulong_t *xrefs = dt_zalloc(dtp, newsize);
+
+ if (xrefs == NULL)
+ return (-1);
+
+ bcopy(pvp->pv_xrefs, xrefs, oldsize);
+ dt_free(dtp, pvp->pv_xrefs);
+
+ pvp->pv_xrefs = xrefs;
+ pvp->pv_xrmax = dtp->dt_xlatorid;
+ }
+
+ BT_SET(pvp->pv_xrefs, id);
+ return (0);
+}
+
+static uint8_t
+dt_probe_argmap(dt_node_t *xnp, dt_node_t *nnp)
+{
+ uint8_t i;
+
+ for (i = 0; nnp != NULL; i++) {
+ if (nnp->dn_string != NULL &&
+ strcmp(nnp->dn_string, xnp->dn_string) == 0)
+ break;
+ else
+ nnp = nnp->dn_list;
+ }
+
+ return (i);
+}
+
+static dt_node_t *
+dt_probe_alloc_args(dt_provider_t *pvp, int argc)
+{
+ dt_node_t *args = NULL, *pnp = NULL, *dnp;
+ int i;
+
+ for (i = 0; i < argc; i++, pnp = dnp) {
+ if ((dnp = dt_node_xalloc(pvp->pv_hdl, DT_NODE_TYPE)) == NULL)
+ return (NULL);
+
+ dnp->dn_link = pvp->pv_nodes;
+ pvp->pv_nodes = dnp;
+
+ if (args == NULL)
+ args = dnp;
+ else
+ pnp->dn_list = dnp;
+ }
+
+ return (args);
+}
+
+static size_t
+dt_probe_keylen(const dtrace_probedesc_t *pdp)
+{
+ return (strlen(pdp->dtpd_mod) + 1 +
+ strlen(pdp->dtpd_func) + 1 + strlen(pdp->dtpd_name) + 1);
+}
+
+static char *
+dt_probe_key(const dtrace_probedesc_t *pdp, char *s)
+{
+ (void) snprintf(s, INT_MAX, "%s:%s:%s",
+ pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
+ return (s);
+}
+
+/*
+ * If a probe was discovered from the kernel, ask dtrace(7D) for a description
+ * of each of its arguments, including native and translated types.
+ */
+static dt_probe_t *
+dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp)
+{
+ dtrace_hdl_t *dtp = pvp->pv_hdl;
+ char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp)));
+
+ dt_node_t *xargs, *nargs;
+ dt_ident_t *idp;
+ dt_probe_t *prp;
+
+ dtrace_typeinfo_t dtt;
+ int i, nc, xc;
+
+ int adc = _dtrace_argmax;
+ dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc);
+ dtrace_argdesc_t *adp = adv;
+
+ assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0);
+ assert(pdp->dtpd_id != DTRACE_IDNONE);
+
+ dt_dprintf("discovering probe %s:%s id=%d\n",
+ pvp->pv_desc.dtvd_name, name, pdp->dtpd_id);
+
+ for (nc = -1, i = 0; i < adc; i++, adp++) {
+ bzero(adp, sizeof (dtrace_argdesc_t));
+ adp->dtargd_ndx = i;
+ adp->dtargd_id = pdp->dtpd_id;
+
+ if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) {
+ (void) dt_set_errno(dtp, errno);
+ return (NULL);
+ }
+
+ if (adp->dtargd_ndx == DTRACE_ARGNONE)
+ break; /* all argument descs have been retrieved */
+
+ nc = MAX(nc, adp->dtargd_mapping);
+ }
+
+ xc = i;
+ nc++;
+
+ /*
+ * The pid provider believes in giving the kernel a break. No reason to
+ * give the kernel all the ctf containers that we're keeping ourselves
+ * just to get it back from it. So if we're coming from a pid provider
+ * probe and the kernel gave us no argument information we'll get some
+ * here. If for some crazy reason the kernel knows about our userland
+ * types then we just ignore this.
+ */
+ if (xc == 0 && nc == 0 &&
+ strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) {
+ nc = adc;
+ dt_pid_get_types(dtp, pdp, adv, &nc);
+ xc = nc;
+ }
+
+ /*
+ * Now that we have discovered the number of native and translated
+ * arguments from the argument descriptions, allocate a new probe ident
+ * and corresponding dt_probe_t and hash it into the provider.
+ */
+ xargs = dt_probe_alloc_args(pvp, xc);
+ nargs = dt_probe_alloc_args(pvp, nc);
+
+ if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL))
+ return (NULL); /* dt_errno is set for us */
+
+ idp = dt_ident_create(name, DT_IDENT_PROBE,
+ DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0,
+ &dt_idops_probe, NULL, dtp->dt_gen);
+
+ if (idp == NULL) {
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+ return (NULL);
+ }
+
+ if ((prp = dt_probe_create(dtp, idp, 2,
+ nargs, nc, xargs, xc)) == NULL) {
+ dt_ident_destroy(idp);
+ return (NULL);
+ }
+
+ dt_probe_declare(pvp, prp);
+
+ /*
+ * Once our new dt_probe_t is fully constructed, iterate over the
+ * cached argument descriptions and assign types to prp->pr_nargv[]
+ * and prp->pr_xargv[] and assign mappings to prp->pr_mapping[].
+ */
+ for (adp = adv, i = 0; i < xc; i++, adp++) {
+ if (dtrace_type_strcompile(dtp,
+ adp->dtargd_native, &dtt) != 0) {
+ dt_dprintf("failed to resolve input type %s "
+ "for %s:%s arg #%d: %s\n", adp->dtargd_native,
+ pvp->pv_desc.dtvd_name, name, i + 1,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+
+ dtt.dtt_object = NULL;
+ dtt.dtt_ctfp = NULL;
+ dtt.dtt_type = CTF_ERR;
+ } else {
+ dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping],
+ dtt.dtt_ctfp, dtt.dtt_type,
+ dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE);
+ }
+
+ if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' ||
+ strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) {
+ dt_node_type_propagate(prp->pr_nargv[
+ adp->dtargd_mapping], prp->pr_xargv[i]);
+ } else if (dtrace_type_strcompile(dtp,
+ adp->dtargd_xlate, &dtt) != 0) {
+ dt_dprintf("failed to resolve output type %s "
+ "for %s:%s arg #%d: %s\n", adp->dtargd_xlate,
+ pvp->pv_desc.dtvd_name, name, i + 1,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+
+ dtt.dtt_object = NULL;
+ dtt.dtt_ctfp = NULL;
+ dtt.dtt_type = CTF_ERR;
+ } else {
+ dt_node_type_assign(prp->pr_xargv[i],
+ dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
+ }
+
+ prp->pr_mapping[i] = adp->dtargd_mapping;
+ prp->pr_argv[i] = dtt;
+ }
+
+ return (prp);
+}
+
+/*
+ * Lookup a probe declaration based on a known provider and full or partially
+ * specified module, function, and name. If the probe is not known to us yet,
+ * ask dtrace(7D) to match the description and then cache any useful results.
+ */
+dt_probe_t *
+dt_probe_lookup(dt_provider_t *pvp, const char *s)
+{
+ dtrace_hdl_t *dtp = pvp->pv_hdl;
+ dtrace_probedesc_t pd;
+ dt_ident_t *idp;
+ size_t keylen;
+ char *key;
+
+ if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, s, &pd) != 0)
+ return (NULL); /* dt_errno is set for us */
+
+ keylen = dt_probe_keylen(&pd);
+ key = dt_probe_key(&pd, alloca(keylen));
+
+ /*
+ * If the probe is already declared, then return the dt_probe_t from
+ * the existing identifier. This could come from a static declaration
+ * or it could have been cached from an earlier call to this function.
+ */
+ if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
+ return (idp->di_data);
+
+ /*
+ * If the probe isn't known, use the probe description computed above
+ * to ask dtrace(7D) to find the first matching probe.
+ */
+ if (dt_ioctl(dtp, DTRACEIOC_PROBEMATCH, &pd) == 0)
+ return (dt_probe_discover(pvp, &pd));
+
+ if (errno == ESRCH || errno == EBADF)
+ (void) dt_set_errno(dtp, EDT_NOPROBE);
+ else
+ (void) dt_set_errno(dtp, errno);
+
+ return (NULL);
+}
+
+dt_probe_t *
+dt_probe_create(dtrace_hdl_t *dtp, dt_ident_t *idp, int protoc,
+ dt_node_t *nargs, uint_t nargc, dt_node_t *xargs, uint_t xargc)
+{
+ dt_module_t *dmp;
+ dt_probe_t *prp;
+ const char *p;
+ uint_t i;
+
+ assert(idp->di_kind == DT_IDENT_PROBE);
+ assert(idp->di_data == NULL);
+
+ /*
+ * If only a single prototype is given, set xargc/s to nargc/s to
+ * simplify subsequent use. Note that we can have one or both of nargs
+ * and xargs be specified but set to NULL, indicating a void prototype.
+ */
+ if (protoc < 2) {
+ assert(xargs == NULL);
+ assert(xargc == 0);
+ xargs = nargs;
+ xargc = nargc;
+ }
+
+ if ((prp = dt_alloc(dtp, sizeof (dt_probe_t))) == NULL)
+ return (NULL);
+
+ prp->pr_pvp = NULL;
+ prp->pr_ident = idp;
+
+ p = strrchr(idp->di_name, ':');
+ assert(p != NULL);
+ prp->pr_name = p + 1;
+
+ prp->pr_nargs = nargs;
+ prp->pr_nargv = dt_alloc(dtp, sizeof (dt_node_t *) * nargc);
+ prp->pr_nargc = nargc;
+ prp->pr_xargs = xargs;
+ prp->pr_xargv = dt_alloc(dtp, sizeof (dt_node_t *) * xargc);
+ prp->pr_xargc = xargc;
+ prp->pr_mapping = dt_alloc(dtp, sizeof (uint8_t) * xargc);
+ prp->pr_inst = NULL;
+ prp->pr_argv = dt_alloc(dtp, sizeof (dtrace_typeinfo_t) * xargc);
+ prp->pr_argc = xargc;
+
+ if ((prp->pr_nargc != 0 && prp->pr_nargv == NULL) ||
+ (prp->pr_xargc != 0 && prp->pr_xargv == NULL) ||
+ (prp->pr_xargc != 0 && prp->pr_mapping == NULL) ||
+ (prp->pr_argc != 0 && prp->pr_argv == NULL)) {
+ dt_probe_destroy(prp);
+ return (NULL);
+ }
+
+ for (i = 0; i < xargc; i++, xargs = xargs->dn_list) {
+ if (xargs->dn_string != NULL)
+ prp->pr_mapping[i] = dt_probe_argmap(xargs, nargs);
+ else
+ prp->pr_mapping[i] = i;
+
+ prp->pr_xargv[i] = xargs;
+
+ if ((dmp = dt_module_lookup_by_ctf(dtp,
+ xargs->dn_ctfp)) != NULL)
+ prp->pr_argv[i].dtt_object = dmp->dm_name;
+ else
+ prp->pr_argv[i].dtt_object = NULL;
+
+ prp->pr_argv[i].dtt_ctfp = xargs->dn_ctfp;
+ prp->pr_argv[i].dtt_type = xargs->dn_type;
+ }
+
+ for (i = 0; i < nargc; i++, nargs = nargs->dn_list)
+ prp->pr_nargv[i] = nargs;
+
+ idp->di_data = prp;
+ return (prp);
+}
+
+void
+dt_probe_declare(dt_provider_t *pvp, dt_probe_t *prp)
+{
+ assert(prp->pr_ident->di_kind == DT_IDENT_PROBE);
+ assert(prp->pr_ident->di_data == prp);
+ assert(prp->pr_pvp == NULL);
+
+ if (prp->pr_xargs != prp->pr_nargs)
+ pvp->pv_flags &= ~DT_PROVIDER_INTF;
+
+ prp->pr_pvp = pvp;
+ dt_idhash_xinsert(pvp->pv_probes, prp->pr_ident);
+}
+
+void
+dt_probe_destroy(dt_probe_t *prp)
+{
+ dt_probe_instance_t *pip, *pip_next;
+ dtrace_hdl_t *dtp;
+
+ if (prp->pr_pvp != NULL)
+ dtp = prp->pr_pvp->pv_hdl;
+ else
+ dtp = yypcb->pcb_hdl;
+
+ dt_node_list_free(&prp->pr_nargs);
+ dt_node_list_free(&prp->pr_xargs);
+
+ dt_free(dtp, prp->pr_nargv);
+ dt_free(dtp, prp->pr_xargv);
+
+ for (pip = prp->pr_inst; pip != NULL; pip = pip_next) {
+ pip_next = pip->pi_next;
+ dt_free(dtp, pip->pi_rname);
+ dt_free(dtp, pip->pi_fname);
+ dt_free(dtp, pip->pi_offs);
+ dt_free(dtp, pip->pi_enoffs);
+ dt_free(dtp, pip);
+ }
+
+ dt_free(dtp, prp->pr_mapping);
+ dt_free(dtp, prp->pr_argv);
+ dt_free(dtp, prp);
+}
+
+int
+dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
+ 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);
+
+ for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
+ if (strcmp(pip->pi_fname, fname) == 0 &&
+ strcmp(pip->pi_rname, rname) == 0)
+ break;
+ }
+
+ if (pip == NULL) {
+ if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL)
+ return (-1);
+
+ if ((pip->pi_offs = dt_zalloc(dtp, sizeof (uint32_t))) == NULL)
+ goto nomem;
+
+ if ((pip->pi_enoffs = dt_zalloc(dtp,
+ sizeof (uint32_t))) == NULL)
+ goto nomem;
+
+ if ((pip->pi_fname = strdup(fname)) == NULL)
+ goto nomem;
+
+ if ((pip->pi_rname = strdup(rname)) == NULL)
+ goto nomem;
+
+ 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 (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(*offs, new_offs, sizeof (uint32_t) * *maxoffs);
+
+ dt_free(dtp, *offs);
+ *maxoffs = new_max;
+ *offs = new_offs;
+ }
+
+ 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);
+
+ assert(*noffs < *maxoffs);
+ (*offs)[(*noffs)++] = offset;
+
+ return (0);
+
+nomem:
+ dt_free(dtp, pip->pi_fname);
+ dt_free(dtp, pip->pi_enoffs);
+ dt_free(dtp, pip->pi_offs);
+ dt_free(dtp, pip);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+}
+
+/*
+ * Lookup the dynamic translator type tag for the specified probe argument and
+ * assign the type to the specified node. If the type is not yet defined, add
+ * it to the "D" module's type container as a typedef for an unknown type.
+ */
+dt_node_t *
+dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp)
+{
+ dtrace_hdl_t *dtp = prp->pr_pvp->pv_hdl;
+ dtrace_typeinfo_t dtt;
+ size_t len;
+ char *tag;
+
+ len = snprintf(NULL, 0, "__dtrace_%s___%s_arg%u",
+ prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);
+
+ tag = alloca(len + 1);
+
+ (void) snprintf(tag, len + 1, "__dtrace_%s___%s_arg%u",
+ prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);
+
+ if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS, tag, &dtt) != 0) {
+ dtt.dtt_object = DTRACE_OBJ_DDEFS;
+ dtt.dtt_ctfp = DT_DYN_CTFP(dtp);
+ dtt.dtt_type = ctf_add_typedef(DT_DYN_CTFP(dtp),
+ CTF_ADD_ROOT, tag, DT_DYN_TYPE(dtp));
+
+ if (dtt.dtt_type == CTF_ERR ||
+ ctf_update(dtt.dtt_ctfp) == CTF_ERR) {
+ xyerror(D_UNKNOWN, "cannot define type %s: %s\n",
+ tag, ctf_errmsg(ctf_errno(dtt.dtt_ctfp)));
+ }
+ }
+
+ bzero(dnp, sizeof (dt_node_t));
+ dnp->dn_kind = DT_NODE_TYPE;
+
+ dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
+ dt_node_attr_assign(dnp, _dtrace_defattr);
+
+ return (dnp);
+}
+
+/*ARGSUSED*/
+static int
+dt_probe_desc(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg)
+{
+ if (((dtrace_probedesc_t *)arg)->dtpd_id == DTRACE_IDNONE) {
+ bcopy(pdp, arg, sizeof (dtrace_probedesc_t));
+ return (0);
+ }
+
+ return (1);
+}
+
+dt_probe_t *
+dt_probe_info(dtrace_hdl_t *dtp,
+ const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
+{
+ int m_is_glob = pdp->dtpd_mod[0] == '\0' || strisglob(pdp->dtpd_mod);
+ int f_is_glob = pdp->dtpd_func[0] == '\0' || strisglob(pdp->dtpd_func);
+ int n_is_glob = pdp->dtpd_name[0] == '\0' || strisglob(pdp->dtpd_name);
+
+ dt_probe_t *prp = NULL;
+ const dtrace_pattr_t *pap;
+ dt_provider_t *pvp;
+ dt_ident_t *idp;
+
+ /*
+ * Attempt to lookup the probe in our existing cache for this provider.
+ * If none is found and an explicit probe ID was specified, discover
+ * that specific probe and cache its description and arguments.
+ */
+ if ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) != NULL) {
+ size_t keylen = dt_probe_keylen(pdp);
+ char *key = dt_probe_key(pdp, alloca(keylen));
+
+ if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
+ prp = idp->di_data;
+ else if (pdp->dtpd_id != DTRACE_IDNONE)
+ prp = dt_probe_discover(pvp, pdp);
+ }
+
+ /*
+ * If no probe was found in our cache, convert the caller's partial
+ * probe description into a fully-formed matching probe description by
+ * iterating over up to at most two probes that match 'pdp'. We then
+ * call dt_probe_discover() on the resulting probe identifier.
+ */
+ if (prp == NULL) {
+ dtrace_probedesc_t pd;
+ int m;
+
+ bzero(&pd, sizeof (pd));
+ pd.dtpd_id = DTRACE_IDNONE;
+
+ /*
+ * Call dtrace_probe_iter() to find matching probes. Our
+ * dt_probe_desc() callback will produce the following results:
+ *
+ * m < 0 dtrace_probe_iter() found zero matches (or failed).
+ * m > 0 dtrace_probe_iter() found more than one match.
+ * m = 0 dtrace_probe_iter() found exactly one match.
+ */
+ if ((m = dtrace_probe_iter(dtp, pdp, dt_probe_desc, &pd)) < 0)
+ return (NULL); /* dt_errno is set for us */
+
+ if ((pvp = dt_provider_lookup(dtp, pd.dtpd_provider)) == NULL)
+ return (NULL); /* dt_errno is set for us */
+
+ /*
+ * If more than one probe was matched, then do not report probe
+ * information if either of the following conditions is true:
+ *
+ * (a) The Arguments Data stability of the matched provider is
+ * less than Evolving.
+ *
+ * (b) Any description component that is at least Evolving is
+ * empty or is specified using a globbing expression.
+ *
+ * These conditions imply that providers that provide Evolving
+ * or better Arguments Data stability must guarantee that all
+ * probes with identical field names in a field of Evolving or
+ * better Name stability have identical argument signatures.
+ */
+ if (m > 0) {
+ if (pvp->pv_desc.dtvd_attr.dtpa_args.dtat_data <
+ DTRACE_STABILITY_EVOLVING) {
+ (void) dt_set_errno(dtp, EDT_UNSTABLE);
+ return (NULL);
+ }
+
+
+ if (pvp->pv_desc.dtvd_attr.dtpa_mod.dtat_name >=
+ DTRACE_STABILITY_EVOLVING && m_is_glob) {
+ (void) dt_set_errno(dtp, EDT_UNSTABLE);
+ return (NULL);
+ }
+
+ if (pvp->pv_desc.dtvd_attr.dtpa_func.dtat_name >=
+ DTRACE_STABILITY_EVOLVING && f_is_glob) {
+ (void) dt_set_errno(dtp, EDT_UNSTABLE);
+ return (NULL);
+ }
+
+ if (pvp->pv_desc.dtvd_attr.dtpa_name.dtat_name >=
+ DTRACE_STABILITY_EVOLVING && n_is_glob) {
+ (void) dt_set_errno(dtp, EDT_UNSTABLE);
+ return (NULL);
+ }
+ }
+
+ /*
+ * If we matched a probe exported by dtrace(7D), then discover
+ * the real attributes. Otherwise grab the static declaration.
+ */
+ if (pd.dtpd_id != DTRACE_IDNONE)
+ prp = dt_probe_discover(pvp, &pd);
+ else
+ prp = dt_probe_lookup(pvp, pd.dtpd_name);
+
+ if (prp == NULL)
+ return (NULL); /* dt_errno is set for us */
+ }
+
+ assert(pvp != NULL && prp != NULL);
+
+ /*
+ * Compute the probe description attributes by taking the minimum of
+ * the attributes of the specified fields. If no provider is specified
+ * or a glob pattern is used for the provider, use Unstable attributes.
+ */
+ if (pdp->dtpd_provider[0] == '\0' || strisglob(pdp->dtpd_provider))
+ pap = &_dtrace_prvdesc;
+ else
+ pap = &pvp->pv_desc.dtvd_attr;
+
+ pip->dtp_attr = pap->dtpa_provider;
+
+ if (!m_is_glob)
+ pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_mod);
+ if (!f_is_glob)
+ pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_func);
+ if (!n_is_glob)
+ pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_name);
+
+ pip->dtp_arga = pap->dtpa_args;
+ pip->dtp_argv = prp->pr_argv;
+ pip->dtp_argc = prp->pr_argc;
+
+ return (prp);
+}
+
+int
+dtrace_probe_info(dtrace_hdl_t *dtp,
+ const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
+{
+ return (dt_probe_info(dtp, pdp, pip) != NULL ? 0 : -1);
+}
+
+/*ARGSUSED*/
+static int
+dt_probe_iter(dt_idhash_t *ihp, dt_ident_t *idp, dt_probe_iter_t *pit)
+{
+ const dt_probe_t *prp = idp->di_data;
+
+ if (!dt_gmatch(prp->pr_name, pit->pit_pat))
+ return (0); /* continue on and examine next probe in hash */
+
+ (void) strlcpy(pit->pit_desc.dtpd_name, prp->pr_name, DTRACE_NAMELEN);
+ pit->pit_desc.dtpd_id = idp->di_id;
+ pit->pit_matches++;
+
+ return (pit->pit_func(pit->pit_hdl, &pit->pit_desc, pit->pit_arg));
+}
+
+int
+dtrace_probe_iter(dtrace_hdl_t *dtp,
+ const dtrace_probedesc_t *pdp, dtrace_probe_f *func, void *arg)
+{
+ const char *provider = pdp ? pdp->dtpd_provider : NULL;
+ dtrace_id_t id = DTRACE_IDNONE;
+
+ dtrace_probedesc_t pd;
+ dt_probe_iter_t pit;
+ int cmd, rv;
+
+ bzero(&pit, sizeof (pit));
+ pit.pit_hdl = dtp;
+ pit.pit_func = func;
+ pit.pit_arg = arg;
+ pit.pit_pat = pdp ? pdp->dtpd_name : NULL;
+
+ for (pit.pit_pvp = dt_list_next(&dtp->dt_provlist);
+ pit.pit_pvp != NULL; pit.pit_pvp = dt_list_next(pit.pit_pvp)) {
+
+ if (pit.pit_pvp->pv_flags & DT_PROVIDER_IMPL)
+ continue; /* we'll get these later using dt_ioctl() */
+
+ if (!dt_gmatch(pit.pit_pvp->pv_desc.dtvd_name, provider))
+ continue;
+
+ (void) strlcpy(pit.pit_desc.dtpd_provider,
+ pit.pit_pvp->pv_desc.dtvd_name, DTRACE_PROVNAMELEN);
+
+ if ((rv = dt_idhash_iter(pit.pit_pvp->pv_probes,
+ (dt_idhash_f *)dt_probe_iter, &pit)) != 0)
+ return (rv);
+ }
+
+ if (pdp != NULL)
+ cmd = DTRACEIOC_PROBEMATCH;
+ else
+ cmd = DTRACEIOC_PROBES;
+
+ for (;;) {
+ if (pdp != NULL)
+ bcopy(pdp, &pd, sizeof (pd));
+
+ pd.dtpd_id = id;
+
+ if (dt_ioctl(dtp, cmd, &pd) != 0)
+ break;
+ else if ((rv = func(dtp, &pd, arg)) != 0)
+ return (rv);
+
+ pit.pit_matches++;
+ id = pd.dtpd_id + 1;
+ }
+
+ switch (errno) {
+ case ESRCH:
+ case EBADF:
+ return (pit.pit_matches ? 0 : dt_set_errno(dtp, EDT_NOPROBE));
+ case EINVAL:
+ return (dt_set_errno(dtp, EDT_BADPGLOB));
+ default:
+ return (dt_set_errno(dtp, errno));
+ }
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h
new file mode 100644
index 000000000000..2752baae32da
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h
@@ -0,0 +1,118 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_PROVIDER_H
+#define _DT_PROVIDER_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <dt_impl.h>
+#include <dt_ident.h>
+#include <dt_list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct dt_provider {
+ dt_list_t pv_list; /* list forward/back pointers */
+ struct dt_provider *pv_next; /* pointer to next provider in hash */
+ dtrace_providerdesc_t pv_desc; /* provider name and attributes */
+ dt_idhash_t *pv_probes; /* probe defs (if user-declared) */
+ dt_node_t *pv_nodes; /* parse node allocation list */
+ ulong_t *pv_xrefs; /* translator reference bitmap */
+ ulong_t pv_xrmax; /* number of valid bits in pv_xrefs */
+ ulong_t pv_gen; /* generation # that created me */
+ dtrace_hdl_t *pv_hdl; /* pointer to containing dtrace_hdl */
+ uint_t pv_flags; /* flags (see below) */
+} dt_provider_t;
+
+#define DT_PROVIDER_INTF 0x1 /* provider interface declaration */
+#define DT_PROVIDER_IMPL 0x2 /* provider implementation is loaded */
+
+typedef struct dt_probe_iter {
+ dtrace_probedesc_t pit_desc; /* description storage */
+ dtrace_hdl_t *pit_hdl; /* libdtrace handle */
+ dt_provider_t *pit_pvp; /* current provider */
+ const char *pit_pat; /* caller's name pattern (or NULL) */
+ dtrace_probe_f *pit_func; /* caller's function */
+ void *pit_arg; /* caller's argument */
+ uint_t pit_matches; /* number of matches */
+} dt_probe_iter_t;
+
+typedef struct dt_probe_instance {
+ char *pi_fname; /* function name */
+ char *pi_rname; /* 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;
+
+typedef struct dt_probe {
+ dt_provider_t *pr_pvp; /* pointer to containing provider */
+ dt_ident_t *pr_ident; /* pointer to probe identifier */
+ const char *pr_name; /* pointer to name component */
+ dt_node_t *pr_nargs; /* native argument list */
+ dt_node_t **pr_nargv; /* native argument vector */
+ uint_t pr_nargc; /* native argument count */
+ dt_node_t *pr_xargs; /* translated argument list */
+ dt_node_t **pr_xargv; /* translated argument vector */
+ uint_t pr_xargc; /* translated argument count */
+ uint8_t *pr_mapping; /* translated argument mapping */
+ dt_probe_instance_t *pr_inst; /* list of functions and offsets */
+ dtrace_typeinfo_t *pr_argv; /* output argument types */
+ int pr_argc; /* output argument count */
+} dt_probe_t;
+
+extern dt_provider_t *dt_provider_lookup(dtrace_hdl_t *, const char *);
+extern dt_provider_t *dt_provider_create(dtrace_hdl_t *, const char *);
+extern void dt_provider_destroy(dtrace_hdl_t *, dt_provider_t *);
+extern int dt_provider_xref(dtrace_hdl_t *, dt_provider_t *, id_t);
+
+extern dt_probe_t *dt_probe_create(dtrace_hdl_t *, dt_ident_t *, int,
+ dt_node_t *, uint_t, dt_node_t *, uint_t);
+
+extern dt_probe_t *dt_probe_info(dtrace_hdl_t *,
+ const dtrace_probedesc_t *, dtrace_probeinfo_t *);
+
+extern dt_probe_t *dt_probe_lookup(dt_provider_t *, const char *);
+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, int);
+
+extern dt_node_t *dt_probe_tag(dt_probe_t *, uint_t, dt_node_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_PROVIDER_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.c
new file mode 100644
index 000000000000..a630d300dc50
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.c
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2016 Pedro Giffuni. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/bitmap.h>
+#include <assert.h>
+#include <strings.h>
+#include <stdlib.h>
+
+#include <dt_regset.h>
+#include <dt_impl.h>
+
+dt_regset_t *
+dt_regset_create(ulong_t nregs)
+{
+ ulong_t n = BT_BITOUL(nregs);
+ dt_regset_t *drp = malloc(sizeof (dt_regset_t));
+
+ if (drp == NULL)
+ return (NULL);
+
+ drp->dr_bitmap = calloc(n, sizeof (ulong_t));
+
+ if (drp->dr_bitmap == NULL) {
+ dt_regset_destroy(drp);
+ return (NULL);
+ }
+
+ drp->dr_size = nregs;
+
+ return (drp);
+}
+
+void
+dt_regset_destroy(dt_regset_t *drp)
+{
+ free(drp->dr_bitmap);
+ free(drp);
+}
+
+void
+dt_regset_reset(dt_regset_t *drp)
+{
+ bzero(drp->dr_bitmap, sizeof (ulong_t) * BT_BITOUL(drp->dr_size));
+}
+
+void
+dt_regset_assert_free(dt_regset_t *drp)
+{
+ int reg;
+ boolean_t fail = B_FALSE;
+ for (reg = 0; reg < drp->dr_size; reg++) {
+ if (BT_TEST(drp->dr_bitmap, reg) != 0) {
+ dt_dprintf("%%r%d was left allocated\n", reg);
+ fail = B_TRUE;
+ }
+ }
+
+ /*
+ * We set this during dtest runs to check for register leaks.
+ */
+ if (fail && getenv("DTRACE_DEBUG_REGSET") != NULL)
+ abort();
+}
+
+int
+dt_regset_alloc(dt_regset_t *drp)
+{
+ ulong_t nbits = drp->dr_size - 1;
+ ulong_t maxw = nbits >> BT_ULSHIFT;
+ ulong_t wx;
+
+ for (wx = 0; wx <= maxw; wx++) {
+ if (drp->dr_bitmap[wx] != ~0UL)
+ break;
+ }
+
+ if (wx <= maxw) {
+ ulong_t maxb = (wx == maxw) ? nbits & BT_ULMASK : BT_NBIPUL - 1;
+ ulong_t word = drp->dr_bitmap[wx];
+ ulong_t bit, bx;
+ int reg;
+
+ for (bit = 1, bx = 0; bx <= maxb; bx++, bit <<= 1) {
+ if ((word & bit) == 0) {
+ reg = (int)((wx << BT_ULSHIFT) | bx);
+ BT_SET(drp->dr_bitmap, reg);
+ return (reg);
+ }
+ }
+ }
+
+ xyerror(D_NOREG, "Insufficient registers to generate code");
+ /*NOTREACHED*/
+ return (-1);
+}
+
+void
+dt_regset_free(dt_regset_t *drp, int reg)
+{
+ assert(reg >= 0 && reg < drp->dr_size);
+ assert(BT_TEST(drp->dr_bitmap, reg) != 0);
+ BT_CLEAR(drp->dr_bitmap, reg);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.h
new file mode 100644
index 000000000000..35082846d9d1
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#ifndef _DT_REGSET_H
+#define _DT_REGSET_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct dt_regset {
+ ulong_t dr_size; /* number of registers in set */
+ ulong_t *dr_bitmap; /* bitmap of active registers */
+} dt_regset_t;
+
+extern dt_regset_t *dt_regset_create(ulong_t);
+extern void dt_regset_destroy(dt_regset_t *);
+extern void dt_regset_reset(dt_regset_t *);
+extern int dt_regset_alloc(dt_regset_t *);
+extern void dt_regset_free(dt_regset_t *, int);
+extern void dt_regset_assert_free(dt_regset_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_REGSET_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.c
new file mode 100644
index 000000000000..782d66c2b8a6
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.c
@@ -0,0 +1,309 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <dt_string.h>
+
+/*
+ * Transform string s inline, converting each embedded C escape sequence string
+ * to the corresponding character. For example, the substring "\n" is replaced
+ * by an inline '\n' character. The length of the resulting string is returned.
+ */
+size_t
+stresc2chr(char *s)
+{
+ char *p, *q, c;
+ int esc = 0;
+ int x;
+
+ for (p = q = s; (c = *p) != '\0'; p++) {
+ if (esc) {
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ c -= '0';
+ p++;
+
+ if (*p >= '0' && *p <= '7') {
+ c = c * 8 + *p++ - '0';
+
+ if (*p >= '0' && *p <= '7')
+ c = c * 8 + *p - '0';
+ else
+ p--;
+ } else
+ p--;
+
+ *q++ = c;
+ break;
+
+ case 'a':
+ *q++ = '\a';
+ break;
+ case 'b':
+ *q++ = '\b';
+ break;
+ case 'f':
+ *q++ = '\f';
+ break;
+ case 'n':
+ *q++ = '\n';
+ break;
+ case 'r':
+ *q++ = '\r';
+ break;
+ case 't':
+ *q++ = '\t';
+ break;
+ case 'v':
+ *q++ = '\v';
+ break;
+
+ case 'x':
+ for (x = 0; (c = *++p) != '\0'; ) {
+ if (c >= '0' && c <= '9')
+ x = x * 16 + c - '0';
+ else if (c >= 'a' && c <= 'f')
+ x = x * 16 + c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ x = x * 16 + c - 'A' + 10;
+ else
+ break;
+ }
+ *q++ = (char)x;
+ p--;
+ break;
+
+ case '"':
+ case '\\':
+ *q++ = c;
+ break;
+ default:
+ *q++ = '\\';
+ *q++ = c;
+ }
+
+ esc = 0;
+
+ } else {
+ if ((esc = c == '\\') == 0)
+ *q++ = c;
+ }
+ }
+
+ *q = '\0';
+ return ((size_t)(q - s));
+}
+
+/*
+ * Create a copy of string s in which certain unprintable or special characters
+ * have been converted to the string representation of their C escape sequence.
+ * For example, the newline character is expanded to the string "\n".
+ */
+char *
+strchr2esc(const char *s, size_t n)
+{
+ const char *p;
+ char *q, *s2, c;
+ size_t addl = 0;
+
+ for (p = s; p < s + n; p++) {
+ switch (c = *p) {
+ case '\0':
+ case '\a':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ case '"':
+ case '\\':
+ addl++; /* 1 add'l char needed to follow \ */
+ break;
+ case ' ':
+ break;
+ default:
+ if (c < '!' || c > '~')
+ addl += 3; /* 3 add'l chars following \ */
+ }
+ }
+
+ if ((s2 = malloc(n + addl + 1)) == NULL)
+ return (NULL);
+
+ for (p = s, q = s2; p < s + n; p++) {
+ switch (c = *p) {
+ case '\0':
+ *q++ = '\\';
+ *q++ = '0';
+ break;
+ case '\a':
+ *q++ = '\\';
+ *q++ = 'a';
+ break;
+ case '\b':
+ *q++ = '\\';
+ *q++ = 'b';
+ break;
+ case '\f':
+ *q++ = '\\';
+ *q++ = 'f';
+ break;
+ case '\n':
+ *q++ = '\\';
+ *q++ = 'n';
+ break;
+ case '\r':
+ *q++ = '\\';
+ *q++ = 'r';
+ break;
+ case '\t':
+ *q++ = '\\';
+ *q++ = 't';
+ break;
+ case '\v':
+ *q++ = '\\';
+ *q++ = 'v';
+ break;
+ case '"':
+ *q++ = '\\';
+ *q++ = '"';
+ break;
+ case '\\':
+ *q++ = '\\';
+ *q++ = '\\';
+ break;
+ case ' ':
+ *q++ = c;
+ break;
+ default:
+ if (c < '!' || c > '~') {
+ *q++ = '\\';
+ *q++ = ((c >> 6) & 3) + '0';
+ *q++ = ((c >> 3) & 7) + '0';
+ *q++ = (c & 7) + '0';
+ } else
+ *q++ = c;
+ }
+
+ if (c == '\0')
+ break; /* don't continue past \0 even if p < s + n */
+ }
+
+ *q = '\0';
+ return (s2);
+}
+
+/*
+ * Return the basename (name after final /) of the given string. We use
+ * strbasename rather than basename to avoid conflicting with libgen.h's
+ * non-const function prototype.
+ */
+const char *
+strbasename(const char *s)
+{
+ const char *p = strrchr(s, '/');
+
+ if (p == NULL)
+ return (s);
+
+ return (++p);
+}
+
+/*
+ * This function tests a string against the regular expression used for idents
+ * and integers in the D lexer, and should match the superset of RGX_IDENT and
+ * RGX_INT in dt_lex.l. If an invalid character is found, the function returns
+ * a pointer to it. Otherwise NULL is returned for a valid string.
+ */
+const char *
+strbadidnum(const char *s)
+{
+ char *p;
+ int c;
+
+ if (*s == '\0')
+ return (s);
+
+ errno = 0;
+ (void) strtoull(s, &p, 0);
+
+ if (errno == 0 && *p == '\0')
+ return (NULL); /* matches RGX_INT */
+
+ while ((c = *s++) != '\0') {
+ if (isalnum(c) == 0 && c != '_' && c != '`')
+ return (s - 1);
+ }
+
+ return (NULL); /* matches RGX_IDENT */
+}
+
+/*
+ * Determine whether the string contains a glob matching pattern or is just a
+ * simple string. See gmatch(3GEN) and sh(1) for the glob syntax definition.
+ */
+int
+strisglob(const char *s)
+{
+ char c;
+
+ while ((c = *s++) != '\0') {
+ if (c == '[' || c == '?' || c == '*' || c == '\\')
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Hyphenate a string in-place by converting any instances of "__" to "-",
+ * which we use for probe names to improve readability, and return the string.
+ */
+char *
+strhyphenate(char *s)
+{
+ char *p, *q;
+
+ for (p = s, q = p + strlen(p); p < q; p++) {
+ if (p[0] == '_' && p[1] == '_') {
+ p[0] = '-';
+ bcopy(p + 2, p + 1, (size_t)(q - p) - 1);
+ }
+ }
+
+ return (s);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.h
new file mode 100644
index 000000000000..6ee626db6a35
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.h
@@ -0,0 +1,47 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _DT_STRING_H
+#define _DT_STRING_H
+
+
+#include <sys/types.h>
+#include <strings.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern size_t stresc2chr(char *);
+extern char *strchr2esc(const char *, size_t);
+extern const char *strbasename(const char *);
+extern const char *strbadidnum(const char *);
+extern int strisglob(const char *);
+extern char *strhyphenate(char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_STRING_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c
new file mode 100644
index 000000000000..a735b6674a1e
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c
@@ -0,0 +1,298 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Portions Copyright 2016 Pedro Giffuni. All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <dt_strtab.h>
+#include <dt_impl.h>
+
+static int
+dt_strtab_grow(dt_strtab_t *sp)
+{
+ char *ptr, **bufs;
+
+ if ((ptr = malloc(sp->str_bufsz)) == NULL)
+ return (-1);
+
+ bufs = realloc(sp->str_bufs, (sp->str_nbufs + 1) * sizeof (char *));
+
+ if (bufs == NULL) {
+ free(ptr);
+ return (-1);
+ }
+
+ sp->str_nbufs++;
+ sp->str_bufs = bufs;
+ sp->str_ptr = ptr;
+ sp->str_bufs[sp->str_nbufs - 1] = sp->str_ptr;
+
+ return (0);
+}
+
+dt_strtab_t *
+dt_strtab_create(size_t bufsz)
+{
+ dt_strtab_t *sp = malloc(sizeof (dt_strtab_t));
+ uint_t nbuckets = _dtrace_strbuckets;
+
+ assert(bufsz != 0);
+
+ if (sp == NULL)
+ return (NULL);
+
+ bzero(sp, sizeof (dt_strtab_t));
+ sp->str_hash = calloc(nbuckets, sizeof (dt_strhash_t *));
+
+ if (sp->str_hash == NULL)
+ goto err;
+
+ sp->str_hashsz = nbuckets;
+ sp->str_bufs = NULL;
+ sp->str_ptr = NULL;
+ sp->str_nbufs = 0;
+ sp->str_bufsz = bufsz;
+ sp->str_nstrs = 1;
+ sp->str_size = 1;
+
+ if (dt_strtab_grow(sp) == -1)
+ goto err;
+
+ *sp->str_ptr++ = '\0';
+ return (sp);
+
+err:
+ dt_strtab_destroy(sp);
+ return (NULL);
+}
+
+void
+dt_strtab_destroy(dt_strtab_t *sp)
+{
+ dt_strhash_t *hp, *hq;
+ ulong_t i;
+
+ for (i = 0; i < sp->str_hashsz; i++) {
+ for (hp = sp->str_hash[i]; hp != NULL; hp = hq) {
+ hq = hp->str_next;
+ free(hp);
+ }
+ }
+
+ for (i = 0; i < sp->str_nbufs; i++)
+ free(sp->str_bufs[i]);
+
+ if (sp->str_hash != NULL)
+ free(sp->str_hash);
+ if (sp->str_bufs != NULL)
+ free(sp->str_bufs);
+
+ free(sp);
+}
+
+ulong_t
+dt_strtab_hash(const char *key, size_t *len)
+{
+ ulong_t g, h = 0;
+ const char *p;
+ size_t n = 0;
+
+ for (p = key; *p != '\0'; p++, n++) {
+ h = (h << 4) + *p;
+
+ if ((g = (h & 0xf0000000)) != 0) {
+ h ^= (g >> 24);
+ h ^= g;
+ }
+ }
+
+ if (len != NULL)
+ *len = n;
+
+ return (h);
+}
+
+static int
+dt_strtab_compare(dt_strtab_t *sp, dt_strhash_t *hp,
+ const char *str, size_t len)
+{
+ ulong_t b = hp->str_buf;
+ const char *buf = hp->str_data;
+ size_t resid, n;
+ int rv;
+
+ while (len != 0) {
+ if (buf == sp->str_bufs[b] + sp->str_bufsz)
+ buf = sp->str_bufs[++b];
+
+ resid = sp->str_bufs[b] + sp->str_bufsz - buf;
+ n = MIN(resid, len);
+
+ if ((rv = strncmp(buf, str, n)) != 0)
+ return (rv);
+
+ buf += n;
+ str += n;
+ len -= n;
+ }
+
+ return (0);
+}
+
+static int
+dt_strtab_copyin(dt_strtab_t *sp, const char *str, size_t len)
+{
+ char *old_p = sp->str_ptr;
+ ulong_t old_n = sp->str_nbufs;
+
+ ulong_t b = sp->str_nbufs - 1;
+ size_t resid, n;
+
+ while (len != 0) {
+ if (sp->str_ptr == sp->str_bufs[b] + sp->str_bufsz) {
+ if (dt_strtab_grow(sp) == -1)
+ goto err;
+ b++;
+ }
+
+ resid = sp->str_bufs[b] + sp->str_bufsz - sp->str_ptr;
+ n = MIN(resid, len);
+ bcopy(str, sp->str_ptr, n);
+
+ sp->str_ptr += n;
+ str += n;
+ len -= n;
+ }
+
+ return (0);
+
+err:
+ while (sp->str_nbufs != old_n)
+ free(sp->str_bufs[--sp->str_nbufs]);
+
+ sp->str_ptr = old_p;
+ return (-1);
+}
+
+ssize_t
+dt_strtab_index(dt_strtab_t *sp, const char *str)
+{
+ dt_strhash_t *hp;
+ size_t len;
+ ulong_t h;
+
+ if (str == NULL || str[0] == '\0')
+ return (0); /* we keep a \0 at offset 0 to simplify things */
+
+ h = dt_strtab_hash(str, &len) % sp->str_hashsz;
+
+ for (hp = sp->str_hash[h]; hp != NULL; hp = hp->str_next) {
+ if (dt_strtab_compare(sp, hp, str, len + 1) == 0)
+ return (hp->str_off);
+ }
+
+ return (-1);
+}
+
+ssize_t
+dt_strtab_insert(dt_strtab_t *sp, const char *str)
+{
+ dt_strhash_t *hp;
+ size_t len;
+ ssize_t off;
+ ulong_t h;
+
+ if ((off = dt_strtab_index(sp, str)) != -1)
+ return (off);
+
+ h = dt_strtab_hash(str, &len) % sp->str_hashsz;
+
+ /*
+ * Create a new hash bucket, initialize it, and insert it at the front
+ * of the hash chain for the appropriate bucket.
+ */
+ if ((hp = malloc(sizeof (dt_strhash_t))) == NULL)
+ return (-1L);
+
+ hp->str_data = sp->str_ptr;
+ hp->str_buf = sp->str_nbufs - 1;
+ hp->str_off = sp->str_size;
+ hp->str_len = len;
+ hp->str_next = sp->str_hash[h];
+
+ /*
+ * Now copy the string data into our buffer list, and then update
+ * the global counts of strings and bytes. Return str's byte offset.
+ */
+ if (dt_strtab_copyin(sp, str, len + 1) == -1) {
+ free(hp);
+ return (-1L);
+ }
+
+ sp->str_nstrs++;
+ sp->str_size += len + 1;
+ sp->str_hash[h] = hp;
+
+ return (hp->str_off);
+}
+
+size_t
+dt_strtab_size(const dt_strtab_t *sp)
+{
+ return (sp->str_size);
+}
+
+ssize_t
+dt_strtab_write(const dt_strtab_t *sp, dt_strtab_write_f *func, void *private)
+{
+ ssize_t res, total = 0;
+ ulong_t i;
+ size_t n;
+
+ for (i = 0; i < sp->str_nbufs; i++, total += res) {
+ if (i == sp->str_nbufs - 1)
+ n = sp->str_ptr - sp->str_bufs[i];
+ else
+ n = sp->str_bufsz;
+
+ if ((res = func(sp->str_bufs[i], n, total, private)) <= 0)
+ break;
+ }
+
+ if (total == 0 && sp->str_size != 0)
+ return (-1);
+
+ return (total);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h
new file mode 100644
index 000000000000..551dabbf6765
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h
@@ -0,0 +1,72 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_STRTAB_H
+#define _DT_STRTAB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct dt_strhash {
+ const char *str_data; /* pointer to actual string data */
+ ulong_t str_buf; /* index of string data buffer */
+ size_t str_off; /* offset in bytes of this string */
+ size_t str_len; /* length in bytes of this string */
+ struct dt_strhash *str_next; /* next string in hash chain */
+} dt_strhash_t;
+
+typedef struct dt_strtab {
+ dt_strhash_t **str_hash; /* array of hash buckets */
+ ulong_t str_hashsz; /* size of hash bucket array */
+ char **str_bufs; /* array of buffer pointers */
+ char *str_ptr; /* pointer to current buffer location */
+ ulong_t str_nbufs; /* size of buffer pointer array */
+ size_t str_bufsz; /* size of individual buffer */
+ ulong_t str_nstrs; /* total number of strings in strtab */
+ size_t str_size; /* total size of strings in bytes */
+} dt_strtab_t;
+
+typedef ssize_t dt_strtab_write_f(const char *, size_t, size_t, void *);
+
+extern dt_strtab_t *dt_strtab_create(size_t);
+extern void dt_strtab_destroy(dt_strtab_t *);
+extern ssize_t dt_strtab_index(dt_strtab_t *, const char *);
+extern ssize_t dt_strtab_insert(dt_strtab_t *, const char *);
+extern size_t dt_strtab_size(const dt_strtab_t *);
+extern ssize_t dt_strtab_write(const dt_strtab_t *,
+ dt_strtab_write_f *, void *);
+extern ulong_t dt_strtab_hash(const char *, size_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_STRTAB_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
new file mode 100644
index 000000000000..2d8c24a0a596
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
@@ -0,0 +1,995 @@
+/*
+ * 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 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifdef illumos
+#include <sys/sysmacros.h>
+#endif
+#include <sys/isa_defs.h>
+
+#include <strings.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#ifdef illumos
+#include <alloca.h>
+#else
+#include <sys/sysctl.h>
+#include <libproc_compat.h>
+#endif
+#include <assert.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <dt_impl.h>
+
+static const struct {
+ size_t dtps_offset;
+ size_t dtps_len;
+} dtrace_probespecs[] = {
+ { offsetof(dtrace_probedesc_t, dtpd_provider), DTRACE_PROVNAMELEN },
+ { offsetof(dtrace_probedesc_t, dtpd_mod), DTRACE_MODNAMELEN },
+ { offsetof(dtrace_probedesc_t, dtpd_func), DTRACE_FUNCNAMELEN },
+ { offsetof(dtrace_probedesc_t, dtpd_name), DTRACE_NAMELEN }
+};
+
+int
+dtrace_xstr2desc(dtrace_hdl_t *dtp, dtrace_probespec_t spec,
+ const char *s, int argc, char *const argv[], dtrace_probedesc_t *pdp)
+{
+ size_t off, len, vlen, wlen;
+ const char *p, *q, *v, *w;
+
+ char buf[32]; /* for id_t as %d (see below) */
+
+ if (spec < DTRACE_PROBESPEC_NONE || spec > DTRACE_PROBESPEC_NAME)
+ return (dt_set_errno(dtp, EINVAL));
+
+ bzero(pdp, sizeof (dtrace_probedesc_t));
+ p = s + strlen(s) - 1;
+
+ do {
+ for (len = 0; p >= s && *p != ':'; len++)
+ p--; /* move backward until we find a delimiter */
+
+ q = p + 1;
+ vlen = 0;
+ w = NULL;
+ wlen = 0;
+
+ if ((v = strchr(q, '$')) != NULL && v < q + len) {
+ /*
+ * Set vlen to the length of the variable name and then
+ * reset len to the length of the text prior to '$'. If
+ * the name begins with a digit, interpret it using the
+ * the argv[] array. Otherwise we look in dt_macros.
+ * For the moment, all dt_macros variables are of type
+ * id_t (see dtrace_update() for more details on that).
+ */
+ vlen = (size_t)(q + len - v);
+ len = (size_t)(v - q);
+
+ /*
+ * If the variable string begins with $$, skip past the
+ * leading dollar sign since $ and $$ are equivalent
+ * macro reference operators in a probe description.
+ */
+ if (vlen > 2 && v[1] == '$') {
+ vlen--;
+ v++;
+ }
+
+ if (isdigit(v[1])) {
+ long i;
+
+ errno = 0;
+ i = strtol(v + 1, (char **)&w, 10);
+
+ wlen = vlen - (w - v);
+
+ if (i < 0 || i >= argc || errno != 0)
+ return (dt_set_errno(dtp, EDT_BADSPCV));
+
+ v = argv[i];
+ vlen = strlen(v);
+
+ if (yypcb != NULL && yypcb->pcb_sargv == argv)
+ yypcb->pcb_sflagv[i] |= DT_IDFLG_REF;
+
+ } else if (vlen > 1) {
+ char *vstr = alloca(vlen);
+ dt_ident_t *idp;
+
+ (void) strncpy(vstr, v + 1, vlen - 1);
+ vstr[vlen - 1] = '\0';
+ idp = dt_idhash_lookup(dtp->dt_macros, vstr);
+
+ if (idp == NULL)
+ return (dt_set_errno(dtp, EDT_BADSPCV));
+
+ v = buf;
+ vlen = snprintf(buf, 32, "%d", idp->di_id);
+
+ } else
+ return (dt_set_errno(dtp, EDT_BADSPCV));
+ }
+
+ if (spec == DTRACE_PROBESPEC_NONE)
+ return (dt_set_errno(dtp, EDT_BADSPEC));
+
+ if (len + vlen >= dtrace_probespecs[spec].dtps_len)
+ return (dt_set_errno(dtp, ENAMETOOLONG));
+
+ off = dtrace_probespecs[spec--].dtps_offset;
+ bcopy(q, (char *)pdp + off, len);
+ bcopy(v, (char *)pdp + off + len, vlen);
+ bcopy(w, (char *)pdp + off + len + vlen, wlen);
+ } while (--p >= s);
+
+ pdp->dtpd_id = DTRACE_IDNONE;
+ return (0);
+}
+
+int
+dtrace_str2desc(dtrace_hdl_t *dtp, dtrace_probespec_t spec,
+ const char *s, dtrace_probedesc_t *pdp)
+{
+ return (dtrace_xstr2desc(dtp, spec, s, 0, NULL, pdp));
+}
+
+int
+dtrace_id2desc(dtrace_hdl_t *dtp, dtrace_id_t id, dtrace_probedesc_t *pdp)
+{
+ bzero(pdp, sizeof (dtrace_probedesc_t));
+ pdp->dtpd_id = id;
+
+ if (dt_ioctl(dtp, DTRACEIOC_PROBES, pdp) == -1 ||
+ pdp->dtpd_id != id)
+ return (dt_set_errno(dtp, EDT_BADID));
+
+ return (0);
+}
+
+char *
+dtrace_desc2str(const dtrace_probedesc_t *pdp, char *buf, size_t len)
+{
+ if (pdp->dtpd_id == 0) {
+ (void) snprintf(buf, len, "%s:%s:%s:%s", pdp->dtpd_provider,
+ pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
+ } else
+ (void) snprintf(buf, len, "%u", pdp->dtpd_id);
+
+ return (buf);
+}
+
+char *
+dtrace_attr2str(dtrace_attribute_t attr, char *buf, size_t len)
+{
+ const char *name = dtrace_stability_name(attr.dtat_name);
+ const char *data = dtrace_stability_name(attr.dtat_data);
+ const char *class = dtrace_class_name(attr.dtat_class);
+
+ if (name == NULL || data == NULL || class == NULL)
+ return (NULL); /* one or more invalid attributes */
+
+ (void) snprintf(buf, len, "%s/%s/%s", name, data, class);
+ return (buf);
+}
+
+static char *
+dt_getstrattr(char *p, char **qp)
+{
+ char *q;
+
+ if (*p == '\0')
+ return (NULL);
+
+ if ((q = strchr(p, '/')) == NULL)
+ q = p + strlen(p);
+ else
+ *q++ = '\0';
+
+ *qp = q;
+ return (p);
+}
+
+int
+dtrace_str2attr(const char *str, dtrace_attribute_t *attr)
+{
+ dtrace_stability_t s;
+ dtrace_class_t c;
+ char *p, *q;
+
+ if (str == NULL || attr == NULL)
+ return (-1); /* invalid function arguments */
+
+ *attr = _dtrace_maxattr;
+ p = alloca(strlen(str) + 1);
+ (void) strcpy(p, str);
+
+ if ((p = dt_getstrattr(p, &q)) == NULL)
+ return (0);
+
+ for (s = 0; s <= DTRACE_STABILITY_MAX; s++) {
+ if (strcasecmp(p, dtrace_stability_name(s)) == 0) {
+ attr->dtat_name = s;
+ break;
+ }
+ }
+
+ if (s > DTRACE_STABILITY_MAX)
+ return (-1);
+
+ if ((p = dt_getstrattr(q, &q)) == NULL)
+ return (0);
+
+ for (s = 0; s <= DTRACE_STABILITY_MAX; s++) {
+ if (strcasecmp(p, dtrace_stability_name(s)) == 0) {
+ attr->dtat_data = s;
+ break;
+ }
+ }
+
+ if (s > DTRACE_STABILITY_MAX)
+ return (-1);
+
+ if ((p = dt_getstrattr(q, &q)) == NULL)
+ return (0);
+
+ for (c = 0; c <= DTRACE_CLASS_MAX; c++) {
+ if (strcasecmp(p, dtrace_class_name(c)) == 0) {
+ attr->dtat_class = c;
+ break;
+ }
+ }
+
+ if (c > DTRACE_CLASS_MAX || (p = dt_getstrattr(q, &q)) != NULL)
+ return (-1);
+
+ return (0);
+}
+
+const char *
+dtrace_stability_name(dtrace_stability_t s)
+{
+ switch (s) {
+ case DTRACE_STABILITY_INTERNAL: return ("Internal");
+ case DTRACE_STABILITY_PRIVATE: return ("Private");
+ case DTRACE_STABILITY_OBSOLETE: return ("Obsolete");
+ case DTRACE_STABILITY_EXTERNAL: return ("External");
+ case DTRACE_STABILITY_UNSTABLE: return ("Unstable");
+ case DTRACE_STABILITY_EVOLVING: return ("Evolving");
+ case DTRACE_STABILITY_STABLE: return ("Stable");
+ case DTRACE_STABILITY_STANDARD: return ("Standard");
+ default: return (NULL);
+ }
+}
+
+const char *
+dtrace_class_name(dtrace_class_t c)
+{
+ switch (c) {
+ case DTRACE_CLASS_UNKNOWN: return ("Unknown");
+ case DTRACE_CLASS_CPU: return ("CPU");
+ case DTRACE_CLASS_PLATFORM: return ("Platform");
+ case DTRACE_CLASS_GROUP: return ("Group");
+ case DTRACE_CLASS_ISA: return ("ISA");
+ case DTRACE_CLASS_COMMON: return ("Common");
+ default: return (NULL);
+ }
+}
+
+dtrace_attribute_t
+dt_attr_min(dtrace_attribute_t a1, dtrace_attribute_t a2)
+{
+ dtrace_attribute_t am;
+
+ am.dtat_name = MIN(a1.dtat_name, a2.dtat_name);
+ am.dtat_data = MIN(a1.dtat_data, a2.dtat_data);
+ am.dtat_class = MIN(a1.dtat_class, a2.dtat_class);
+
+ return (am);
+}
+
+dtrace_attribute_t
+dt_attr_max(dtrace_attribute_t a1, dtrace_attribute_t a2)
+{
+ dtrace_attribute_t am;
+
+ am.dtat_name = MAX(a1.dtat_name, a2.dtat_name);
+ am.dtat_data = MAX(a1.dtat_data, a2.dtat_data);
+ am.dtat_class = MAX(a1.dtat_class, a2.dtat_class);
+
+ return (am);
+}
+
+/*
+ * Compare two attributes and return an integer value in the following ranges:
+ *
+ * <0 if any of a1's attributes are less than a2's attributes
+ * =0 if all of a1's attributes are equal to a2's attributes
+ * >0 if all of a1's attributes are greater than or equal to a2's attributes
+ *
+ * To implement this function efficiently, we subtract a2's attributes from
+ * a1's to obtain a negative result if an a1 attribute is less than its a2
+ * counterpart. We then OR the intermediate results together, relying on the
+ * twos-complement property that if any result is negative, the bitwise union
+ * will also be negative since the highest bit will be set in the result.
+ */
+int
+dt_attr_cmp(dtrace_attribute_t a1, dtrace_attribute_t a2)
+{
+ return (((int)a1.dtat_name - a2.dtat_name) |
+ ((int)a1.dtat_data - a2.dtat_data) |
+ ((int)a1.dtat_class - a2.dtat_class));
+}
+
+char *
+dt_attr_str(dtrace_attribute_t a, char *buf, size_t len)
+{
+ static const char stability[] = "ipoxuesS";
+ static const char class[] = "uCpgIc";
+
+ if (a.dtat_name < sizeof (stability) &&
+ a.dtat_data < sizeof (stability) && a.dtat_class < sizeof (class)) {
+ (void) snprintf(buf, len, "[%c/%c/%c]", stability[a.dtat_name],
+ stability[a.dtat_data], class[a.dtat_class]);
+ } else {
+ (void) snprintf(buf, len, "[%u/%u/%u]",
+ a.dtat_name, a.dtat_data, a.dtat_class);
+ }
+
+ return (buf);
+}
+
+char *
+dt_version_num2str(dt_version_t v, char *buf, size_t len)
+{
+ uint_t M = DT_VERSION_MAJOR(v);
+ uint_t m = DT_VERSION_MINOR(v);
+ uint_t u = DT_VERSION_MICRO(v);
+
+ if (u == 0)
+ (void) snprintf(buf, len, "%u.%u", M, m);
+ else
+ (void) snprintf(buf, len, "%u.%u.%u", M, m, u);
+
+ return (buf);
+}
+
+int
+dt_version_str2num(const char *s, dt_version_t *vp)
+{
+ int i = 0, n[3] = { 0, 0, 0 };
+ char c;
+
+ while ((c = *s++) != '\0') {
+ if (isdigit(c))
+ n[i] = n[i] * 10 + c - '0';
+ else if (c != '.' || i++ >= sizeof (n) / sizeof (n[0]) - 1)
+ return (-1);
+ }
+
+ if (n[0] > DT_VERSION_MAJMAX ||
+ n[1] > DT_VERSION_MINMAX ||
+ n[2] > DT_VERSION_MICMAX)
+ return (-1);
+
+ if (vp != NULL)
+ *vp = DT_VERSION_NUMBER(n[0], n[1], n[2]);
+
+ return (0);
+}
+
+int
+dt_version_defined(dt_version_t v)
+{
+ int i;
+
+ for (i = 0; _dtrace_versions[i] != 0; i++) {
+ if (_dtrace_versions[i] == v)
+ return (1);
+ }
+
+ return (0);
+}
+
+char *
+dt_cpp_add_arg(dtrace_hdl_t *dtp, const char *str)
+{
+ char *arg;
+
+ if (dtp->dt_cpp_argc == dtp->dt_cpp_args) {
+ int olds = dtp->dt_cpp_args;
+ int news = olds * 2;
+ char **argv = realloc(dtp->dt_cpp_argv, sizeof (char *) * news);
+
+ if (argv == NULL)
+ return (NULL);
+
+ bzero(&argv[olds], sizeof (char *) * olds);
+ dtp->dt_cpp_argv = argv;
+ dtp->dt_cpp_args = news;
+ }
+
+ if ((arg = strdup(str)) == NULL)
+ return (NULL);
+
+ assert(dtp->dt_cpp_argc < dtp->dt_cpp_args);
+ dtp->dt_cpp_argv[dtp->dt_cpp_argc++] = arg;
+ return (arg);
+}
+
+char *
+dt_cpp_pop_arg(dtrace_hdl_t *dtp)
+{
+ char *arg;
+
+ if (dtp->dt_cpp_argc <= 1)
+ return (NULL); /* dt_cpp_argv[0] cannot be popped */
+
+ arg = dtp->dt_cpp_argv[--dtp->dt_cpp_argc];
+ dtp->dt_cpp_argv[dtp->dt_cpp_argc] = NULL;
+
+ return (arg);
+}
+
+/*PRINTFLIKE1*/
+void
+dt_dprintf(const char *format, ...)
+{
+ if (_dtrace_debug) {
+ va_list alist;
+
+ va_start(alist, format);
+ (void) fputs("libdtrace DEBUG: ", stderr);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+ }
+}
+
+int
+#ifdef illumos
+dt_ioctl(dtrace_hdl_t *dtp, int val, void *arg)
+#else
+dt_ioctl(dtrace_hdl_t *dtp, u_long val, void *arg)
+#endif
+{
+ const dtrace_vector_t *v = dtp->dt_vector;
+
+#ifndef illumos
+ /* Avoid sign extension. */
+ val &= 0xffffffff;
+#endif
+
+ if (v != NULL)
+ return (v->dtv_ioctl(dtp->dt_varg, val, arg));
+
+ if (dtp->dt_fd >= 0)
+ return (ioctl(dtp->dt_fd, val, arg));
+
+ errno = EBADF;
+ return (-1);
+}
+
+int
+dt_status(dtrace_hdl_t *dtp, processorid_t cpu)
+{
+ const dtrace_vector_t *v = dtp->dt_vector;
+
+ if (v == NULL) {
+#ifdef illumos
+ return (p_online(cpu, P_STATUS));
+#else
+ int maxid = 0;
+ size_t len = sizeof(maxid);
+ if (sysctlbyname("kern.smp.maxid", &maxid, &len, NULL, 0) != 0)
+ return (cpu == 0 ? 1 : -1);
+ else
+ return (cpu <= maxid ? 1 : -1);
+#endif
+ }
+
+ return (v->dtv_status(dtp->dt_varg, cpu));
+}
+
+long
+dt_sysconf(dtrace_hdl_t *dtp, int name)
+{
+ const dtrace_vector_t *v = dtp->dt_vector;
+
+ if (v == NULL)
+ return (sysconf(name));
+
+ return (v->dtv_sysconf(dtp->dt_varg, name));
+}
+
+/*
+ * Wrapper around write(2) to handle partial writes. For maximum safety of
+ * output files and proper error reporting, we continuing writing in the
+ * face of partial writes until write(2) fails or 'buf' is completely written.
+ * We also record any errno in the specified dtrace_hdl_t as well as 'errno'.
+ */
+ssize_t
+dt_write(dtrace_hdl_t *dtp, int fd, const void *buf, size_t n)
+{
+ ssize_t resid = n;
+ ssize_t len;
+
+ while (resid != 0) {
+ if ((len = write(fd, buf, resid)) <= 0)
+ break;
+
+ resid -= len;
+ buf = (char *)buf + len;
+ }
+
+ if (resid == n && n != 0)
+ return (dt_set_errno(dtp, errno));
+
+ return (n - resid);
+}
+
+/*
+ * This function handles all output from libdtrace, as well as the
+ * dtrace_sprintf() case. If we're here due to dtrace_sprintf(), then
+ * dt_sprintf_buflen will be non-zero; in this case, we sprintf into the
+ * specified buffer and return. Otherwise, if output is buffered (denoted by
+ * a NULL fp), we sprintf the desired output into the buffered buffer
+ * (expanding the buffer if required). If we don't satisfy either of these
+ * conditions (that is, if we are to actually generate output), then we call
+ * fprintf with the specified fp. In this case, we need to deal with one of
+ * the more annoying peculiarities of libc's printf routines: any failed
+ * write persistently sets an error flag inside the FILE causing every
+ * subsequent write to fail, but only the caller that initiated the error gets
+ * the errno. Since libdtrace clients often intercept SIGINT, this case is
+ * particularly frustrating since we don't want the EINTR on one attempt to
+ * write to the output file to preclude later attempts to write. This
+ * function therefore does a clearerr() if any error occurred, and saves the
+ * errno for the caller inside the specified dtrace_hdl_t.
+ */
+/*PRINTFLIKE3*/
+int
+dt_printf(dtrace_hdl_t *dtp, FILE *fp, const char *format, ...)
+{
+ va_list ap;
+ va_list ap2;
+ int n;
+
+#ifndef illumos
+ /*
+ * On FreeBSD, check if output is currently being re-directed
+ * to another file. If so, output to that file instead of the
+ * one the caller has specified.
+ */
+ if (dtp->dt_freopen_fp != NULL)
+ fp = dtp->dt_freopen_fp;
+#endif
+
+ va_start(ap, format);
+
+ if (dtp->dt_sprintf_buflen != 0) {
+ int len;
+ char *buf;
+
+ assert(dtp->dt_sprintf_buf != NULL);
+
+ buf = &dtp->dt_sprintf_buf[len = strlen(dtp->dt_sprintf_buf)];
+ len = dtp->dt_sprintf_buflen - len;
+ assert(len >= 0);
+
+ va_copy(ap2, ap);
+ if ((n = vsnprintf(buf, len, format, ap2)) < 0)
+ n = dt_set_errno(dtp, errno);
+
+ va_end(ap2);
+ va_end(ap);
+
+ return (n);
+ }
+
+ if (fp == NULL) {
+ int needed, rval;
+ size_t avail;
+
+ /*
+ * Using buffered output is not allowed if a handler has
+ * not been installed.
+ */
+ if (dtp->dt_bufhdlr == NULL) {
+ va_end(ap);
+ return (dt_set_errno(dtp, EDT_NOBUFFERED));
+ }
+
+ if (dtp->dt_buffered_buf == NULL) {
+ assert(dtp->dt_buffered_size == 0);
+ dtp->dt_buffered_size = 1;
+ dtp->dt_buffered_buf = malloc(dtp->dt_buffered_size);
+
+ if (dtp->dt_buffered_buf == NULL) {
+ va_end(ap);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ dtp->dt_buffered_offs = 0;
+ dtp->dt_buffered_buf[0] = '\0';
+ }
+
+ va_copy(ap2, ap);
+ if ((needed = vsnprintf(NULL, 0, format, ap2)) < 0) {
+ rval = dt_set_errno(dtp, errno);
+ va_end(ap2);
+ va_end(ap);
+ return (rval);
+ }
+ va_end(ap2);
+
+ if (needed == 0) {
+ va_end(ap);
+ return (0);
+ }
+
+ for (;;) {
+ char *newbuf;
+
+ assert(dtp->dt_buffered_offs < dtp->dt_buffered_size);
+ avail = dtp->dt_buffered_size - dtp->dt_buffered_offs;
+
+ if (needed + 1 < avail)
+ break;
+
+ if ((newbuf = realloc(dtp->dt_buffered_buf,
+ dtp->dt_buffered_size << 1)) == NULL) {
+ va_end(ap);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ dtp->dt_buffered_buf = newbuf;
+ dtp->dt_buffered_size <<= 1;
+ }
+
+ va_copy(ap2, ap);
+ if (vsnprintf(&dtp->dt_buffered_buf[dtp->dt_buffered_offs],
+ avail, format, ap2) < 0) {
+ rval = dt_set_errno(dtp, errno);
+ va_end(ap2);
+ va_end(ap);
+ return (rval);
+ }
+ va_end(ap2);
+
+ dtp->dt_buffered_offs += needed;
+ assert(dtp->dt_buffered_buf[dtp->dt_buffered_offs] == '\0');
+ va_end(ap);
+ return (0);
+ }
+
+ va_copy(ap2, ap);
+ n = vfprintf(fp, format, ap2);
+ fflush(fp);
+ va_end(ap2);
+ va_end(ap);
+
+ if (n < 0) {
+ clearerr(fp);
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (n);
+}
+
+int
+dt_buffered_flush(dtrace_hdl_t *dtp, dtrace_probedata_t *pdata,
+ const dtrace_recdesc_t *rec, const dtrace_aggdata_t *agg, uint32_t flags)
+{
+ dtrace_bufdata_t data;
+
+ if (dtp->dt_buffered_offs == 0)
+ return (0);
+
+ data.dtbda_handle = dtp;
+ data.dtbda_buffered = dtp->dt_buffered_buf;
+ data.dtbda_probe = pdata;
+ data.dtbda_recdesc = rec;
+ data.dtbda_aggdata = agg;
+ data.dtbda_flags = flags;
+
+ if ((*dtp->dt_bufhdlr)(&data, dtp->dt_bufarg) == DTRACE_HANDLE_ABORT)
+ return (dt_set_errno(dtp, EDT_DIRABORT));
+
+ dtp->dt_buffered_offs = 0;
+ dtp->dt_buffered_buf[0] = '\0';
+
+ return (0);
+}
+
+void
+dt_buffered_destroy(dtrace_hdl_t *dtp)
+{
+ free(dtp->dt_buffered_buf);
+ dtp->dt_buffered_buf = NULL;
+ dtp->dt_buffered_offs = 0;
+ dtp->dt_buffered_size = 0;
+}
+
+void *
+dt_zalloc(dtrace_hdl_t *dtp, size_t size)
+{
+ void *data;
+
+ if ((data = malloc(size)) == NULL)
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+ else
+ bzero(data, size);
+
+ return (data);
+}
+
+void *
+dt_alloc(dtrace_hdl_t *dtp, size_t size)
+{
+ void *data;
+
+ if ((data = malloc(size)) == NULL)
+ (void) dt_set_errno(dtp, EDT_NOMEM);
+
+ return (data);
+}
+
+void
+dt_free(dtrace_hdl_t *dtp, void *data)
+{
+ assert(dtp != NULL); /* ensure sane use of this interface */
+ free(data);
+}
+
+void
+dt_difo_free(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
+{
+ if (dp == NULL)
+ return; /* simplify caller code */
+
+ dt_free(dtp, dp->dtdo_buf);
+ dt_free(dtp, dp->dtdo_inttab);
+ dt_free(dtp, dp->dtdo_strtab);
+ dt_free(dtp, dp->dtdo_vartab);
+ dt_free(dtp, dp->dtdo_kreltab);
+ dt_free(dtp, dp->dtdo_ureltab);
+ dt_free(dtp, dp->dtdo_xlmtab);
+
+ dt_free(dtp, dp);
+}
+
+/*
+ * dt_gmatch() is similar to gmatch(3GEN) and dtrace(7D) globbing, but also
+ * implements the behavior that an empty pattern matches any string.
+ */
+int
+dt_gmatch(const char *s, const char *p)
+{
+ return (p == NULL || *p == '\0' || gmatch(s, p));
+}
+
+char *
+dt_basename(char *str)
+{
+ char *last = strrchr(str, '/');
+
+ if (last == NULL)
+ return (str);
+
+ return (last + 1);
+}
+
+/*
+ * dt_popc() is a fast implementation of population count. The algorithm is
+ * from "Hacker's Delight" by Henry Warren, Jr with a 64-bit equivalent added.
+ */
+ulong_t
+dt_popc(ulong_t x)
+{
+#if defined(_ILP32)
+ x = x - ((x >> 1) & 0x55555555UL);
+ x = (x & 0x33333333UL) + ((x >> 2) & 0x33333333UL);
+ x = (x + (x >> 4)) & 0x0F0F0F0FUL;
+ x = x + (x >> 8);
+ x = x + (x >> 16);
+ return (x & 0x3F);
+#elif defined(_LP64)
+ x = x - ((x >> 1) & 0x5555555555555555ULL);
+ x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
+ x = (x + (x >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
+ x = x + (x >> 8);
+ x = x + (x >> 16);
+ x = x + (x >> 32);
+ return (x & 0x7F);
+#else
+/* This should be a #warning but for now ignore error. Err: "need td_popc() implementation" */
+#endif
+}
+
+/*
+ * dt_popcb() is a bitmap-based version of population count that returns the
+ * number of one bits in the specified bitmap 'bp' at bit positions below 'n'.
+ */
+ulong_t
+dt_popcb(const ulong_t *bp, ulong_t n)
+{
+ ulong_t maxb = n & BT_ULMASK;
+ ulong_t maxw = n >> BT_ULSHIFT;
+ ulong_t w, popc = 0;
+
+ if (n == 0)
+ return (0);
+
+ for (w = 0; w < maxw; w++)
+ popc += dt_popc(bp[w]);
+
+ return (popc + dt_popc(bp[maxw] & ((1UL << maxb) - 1)));
+}
+
+#ifdef illumos
+struct _rwlock;
+struct _lwp_mutex;
+
+int
+dt_rw_read_held(pthread_rwlock_t *lock)
+{
+ extern int _rw_read_held(struct _rwlock *);
+ return (_rw_read_held((struct _rwlock *)lock));
+}
+
+int
+dt_rw_write_held(pthread_rwlock_t *lock)
+{
+ extern int _rw_write_held(struct _rwlock *);
+ return (_rw_write_held((struct _rwlock *)lock));
+}
+#endif
+
+int
+dt_mutex_held(pthread_mutex_t *lock)
+{
+#ifdef illumos
+ extern int _mutex_held(struct _lwp_mutex *);
+ return (_mutex_held((struct _lwp_mutex *)lock));
+#else
+ return (1);
+#endif
+}
+
+static int
+dt_string2str(char *s, char *str, int nbytes)
+{
+ int len = strlen(s);
+
+ if (nbytes == 0) {
+ /*
+ * Like snprintf(3C), we don't check the value of str if the
+ * number of bytes is 0.
+ */
+ return (len);
+ }
+
+ if (nbytes <= len) {
+ (void) strncpy(str, s, nbytes - 1);
+ /*
+ * Like snprintf(3C) (and unlike strncpy(3C)), we guarantee
+ * that the string is null-terminated.
+ */
+ str[nbytes - 1] = '\0';
+ } else {
+ (void) strcpy(str, s);
+ }
+
+ return (len);
+}
+
+int
+dtrace_addr2str(dtrace_hdl_t *dtp, uint64_t addr, char *str, int nbytes)
+{
+ dtrace_syminfo_t dts;
+ GElf_Sym sym;
+
+ size_t n = 20; /* for 0x%llx\0 */
+ char *s;
+ int err;
+
+ if ((err = dtrace_lookup_by_addr(dtp, addr, &sym, &dts)) == 0)
+ n += strlen(dts.dts_object) + strlen(dts.dts_name) + 2; /* +` */
+
+ s = alloca(n);
+
+ if (err == 0 && addr != sym.st_value) {
+ (void) snprintf(s, n, "%s`%s+0x%llx", dts.dts_object,
+ dts.dts_name, (u_longlong_t)addr - sym.st_value);
+ } else if (err == 0) {
+ (void) snprintf(s, n, "%s`%s",
+ dts.dts_object, dts.dts_name);
+ } else {
+ /*
+ * We'll repeat the lookup, but this time we'll specify a NULL
+ * GElf_Sym -- indicating that we're only interested in the
+ * containing module.
+ */
+ if (dtrace_lookup_by_addr(dtp, addr, NULL, &dts) == 0) {
+ (void) snprintf(s, n, "%s`0x%llx", dts.dts_object,
+ (u_longlong_t)addr);
+ } else {
+ (void) snprintf(s, n, "0x%llx", (u_longlong_t)addr);
+ }
+ }
+
+ return (dt_string2str(s, str, nbytes));
+}
+
+int
+dtrace_uaddr2str(dtrace_hdl_t *dtp, pid_t pid,
+ uint64_t addr, char *str, int nbytes)
+{
+ char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
+ struct ps_prochandle *P = NULL;
+ GElf_Sym sym;
+ char *obj;
+
+ if (pid != 0)
+ P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
+
+ if (P == NULL) {
+ (void) snprintf(c, sizeof (c), "0x%jx", (uintmax_t)addr);
+ return (dt_string2str(c, str, nbytes));
+ }
+
+ dt_proc_lock(dtp, P);
+
+ if (Plookup_by_addr(P, addr, name, sizeof (name), &sym) == 0) {
+ (void) Pobjname(P, addr, objname, sizeof (objname));
+
+ obj = dt_basename(objname);
+
+ if (addr > sym.st_value) {
+ (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", obj,
+ name, (u_longlong_t)(addr - sym.st_value));
+ } else {
+ (void) snprintf(c, sizeof (c), "%s`%s", obj, name);
+ }
+ } else if (Pobjname(P, addr, objname, sizeof (objname)) != 0) {
+ (void) snprintf(c, sizeof (c), "%s`0x%jx",
+ dt_basename(objname), (uintmax_t)addr);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%jx", (uintmax_t)addr);
+ }
+
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+
+ return (dt_string2str(c, str, nbytes));
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c
new file mode 100644
index 000000000000..8bd052384d68
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c
@@ -0,0 +1,516 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * Syntactic sugar features are implemented by transforming the D parse tree
+ * such that it only uses the subset of D that is supported by the rest of the
+ * compiler / the kernel. A clause containing these language features is
+ * referred to as a "super-clause", and its transformation typically entails
+ * creating several "sub-clauses" to implement it. For diagnosability, the
+ * sub-clauses will be printed if the "-xtree=8" flag is specified.
+ *
+ * Currently, the only syntactic sugar feature is "if/else" statements. Each
+ * basic block (e.g. the body of the "if" and "else" statements, and the
+ * statements before and after) is turned into its own sub-clause, with a
+ * predicate that causes it to be executed only if the code flows to this point.
+ * Nested if/else statements are supported.
+ *
+ * This infrastructure is designed to accommodate other syntactic sugar features
+ * in the future.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/sysmacros.h>
+
+#include <assert.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <dt_module.h>
+#include <dt_program.h>
+#include <dt_provider.h>
+#include <dt_printf.h>
+#include <dt_pid.h>
+#include <dt_grammar.h>
+#include <dt_ident.h>
+#include <dt_string.h>
+#include <dt_impl.h>
+
+typedef struct dt_sugar_parse {
+ dtrace_hdl_t *dtsp_dtp; /* dtrace handle */
+ dt_node_t *dtsp_pdescs; /* probe descriptions */
+ int dtsp_num_conditions; /* number of condition variables */
+ int dtsp_num_ifs; /* number of "if" statements */
+ dt_node_t *dtsp_clause_list; /* list of clauses */
+} dt_sugar_parse_t;
+
+static void dt_sugar_visit_stmts(dt_sugar_parse_t *, dt_node_t *, int);
+
+/*
+ * Return a node for "self->%error".
+ *
+ * Note that the "%" is part of the variable name, and is included so that
+ * this variable name can not collide with any user-specified variable.
+ *
+ * This error variable is used to keep track of if there has been an error
+ * in any of the sub-clauses, and is used to prevent execution of subsequent
+ * sub-clauses following an error.
+ */
+static dt_node_t *
+dt_sugar_new_error_var(void)
+{
+ return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("self")),
+ dt_node_ident(strdup("%error"))));
+}
+
+/*
+ * Append this clause to the clause list.
+ */
+static void
+dt_sugar_append_clause(dt_sugar_parse_t *dp, dt_node_t *clause)
+{
+ dp->dtsp_clause_list = dt_node_link(dp->dtsp_clause_list, clause);
+}
+
+/*
+ * Prepend this clause to the clause list.
+ */
+static void
+dt_sugar_prepend_clause(dt_sugar_parse_t *dp, dt_node_t *clause)
+{
+ dp->dtsp_clause_list = dt_node_link(clause, dp->dtsp_clause_list);
+}
+
+/*
+ * Return a node for "this->%condition_<condid>", or NULL if condid==0.
+ *
+ * Note that the "%" is part of the variable name, and is included so that
+ * this variable name can not collide with any user-specified variable.
+ */
+static dt_node_t *
+dt_sugar_new_condition_var(int condid)
+{
+ char *str;
+
+ if (condid == 0)
+ return (NULL);
+ assert(condid > 0);
+
+ (void) asprintf(&str, "%%condition_%d", ABS(condid));
+ return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("this")),
+ dt_node_ident(str)));
+}
+
+/*
+ * Return new clause to evaluate predicate and set newcond. condid is
+ * the condition that we are already under, or 0 if none.
+ * The new clause will be of the form:
+ *
+ * dp_pdescs
+ * /!self->%error/
+ * {
+ * this->%condition_<newcond> =
+ * (this->%condition_<condid> && pred);
+ * }
+ *
+ * Note: if condid==0, we will instead do "... = (1 && pred)", to effectively
+ * convert the pred to a boolean.
+ *
+ * Note: Unless an error has been encountered, we always set the condition
+ * variable (either to 0 or 1). This lets us avoid resetting the condition
+ * variables back to 0 when the super-clause completes.
+ */
+static dt_node_t *
+dt_sugar_new_condition_impl(dt_sugar_parse_t *dp,
+ dt_node_t *pred, int condid, int newcond)
+{
+ dt_node_t *value, *body, *newpred;
+
+ /* predicate is !self->%error */
+ newpred = dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var());
+
+ if (condid == 0) {
+ /*
+ * value is (1 && pred)
+ *
+ * Note, D doesn't allow a probe-local "this" variable to
+ * be reused as a different type, even from a different probe.
+ * Therefore, value can't simply be <pred>, because then
+ * its type could be different when we reuse this condid
+ * in a different meta-clause.
+ */
+ value = dt_node_op2(DT_TOK_LAND, dt_node_int(1), pred);
+ } else {
+ /* value is (this->%condition_<condid> && pred) */
+ value = dt_node_op2(DT_TOK_LAND,
+ dt_sugar_new_condition_var(condid), pred);
+ }
+
+ /* body is "this->%condition_<retval> = <value>;" */
+ body = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
+ dt_sugar_new_condition_var(newcond), value));
+
+ return (dt_node_clause(dp->dtsp_pdescs, newpred, body));
+}
+
+/*
+ * Generate a new clause to evaluate predicate and set a new condition variable,
+ * whose ID will be returned. The new clause will be appended to
+ * dp_first_new_clause.
+ */
+static int
+dt_sugar_new_condition(dt_sugar_parse_t *dp, dt_node_t *pred, int condid)
+{
+ dp->dtsp_num_conditions++;
+ dt_sugar_append_clause(dp, dt_sugar_new_condition_impl(dp,
+ pred, condid, dp->dtsp_num_conditions));
+ return (dp->dtsp_num_conditions);
+}
+
+/*
+ * Visit the specified node and all of its descendants. Currently this is only
+ * used to count the number of "if" statements (dtsp_num_ifs).
+ */
+static void
+dt_sugar_visit_all(dt_sugar_parse_t *dp, dt_node_t *dnp)
+{
+ dt_node_t *arg;
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_FREE:
+ case DT_NODE_INT:
+ case DT_NODE_STRING:
+ case DT_NODE_SYM:
+ case DT_NODE_TYPE:
+ case DT_NODE_PROBE:
+ case DT_NODE_PDESC:
+ case DT_NODE_IDENT:
+ break;
+
+ case DT_NODE_FUNC:
+ for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_OP1:
+ dt_sugar_visit_all(dp, dnp->dn_child);
+ break;
+
+ case DT_NODE_OP2:
+ dt_sugar_visit_all(dp, dnp->dn_left);
+ dt_sugar_visit_all(dp, dnp->dn_right);
+ if (dnp->dn_op == DT_TOK_LBRAC) {
+ dt_node_t *ln = dnp->dn_right;
+ while (ln->dn_list != NULL) {
+ dt_sugar_visit_all(dp, ln->dn_list);
+ ln = ln->dn_list;
+ }
+ }
+ break;
+
+ case DT_NODE_OP3:
+ dt_sugar_visit_all(dp, dnp->dn_expr);
+ dt_sugar_visit_all(dp, dnp->dn_left);
+ dt_sugar_visit_all(dp, dnp->dn_right);
+ break;
+
+ case DT_NODE_DEXPR:
+ case DT_NODE_DFUNC:
+ dt_sugar_visit_all(dp, dnp->dn_expr);
+ break;
+
+ case DT_NODE_AGG:
+ for (arg = dnp->dn_aggtup; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+
+ if (dnp->dn_aggfun)
+ dt_sugar_visit_all(dp, dnp->dn_aggfun);
+ break;
+
+ case DT_NODE_CLAUSE:
+ for (arg = dnp->dn_pdescs; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+
+ if (dnp->dn_pred != NULL)
+ dt_sugar_visit_all(dp, dnp->dn_pred);
+
+ for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_INLINE: {
+ const dt_idnode_t *inp = dnp->dn_ident->di_iarg;
+
+ dt_sugar_visit_all(dp, inp->din_root);
+ break;
+ }
+ case DT_NODE_MEMBER:
+ if (dnp->dn_membexpr)
+ dt_sugar_visit_all(dp, dnp->dn_membexpr);
+ break;
+
+ case DT_NODE_XLATOR:
+ for (arg = dnp->dn_members; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_PROVIDER:
+ for (arg = dnp->dn_probes; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_PROG:
+ for (arg = dnp->dn_list; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_IF:
+ dp->dtsp_num_ifs++;
+ dt_sugar_visit_all(dp, dnp->dn_conditional);
+
+ for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ for (arg = dnp->dn_alternate_body; arg != NULL;
+ arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+
+ break;
+
+ default:
+ (void) dnerror(dnp, D_UNKNOWN, "bad node %p, kind %d\n",
+ (void *)dnp, dnp->dn_kind);
+ }
+}
+
+/*
+ * Return a new clause which resets the error variable to zero:
+ *
+ * dp_pdescs{ self->%error = 0; }
+ *
+ * This clause will be executed at the beginning of each meta-clause, to
+ * ensure the error variable is unset (in case the previous meta-clause
+ * failed).
+ */
+static dt_node_t *
+dt_sugar_new_clearerror_clause(dt_sugar_parse_t *dp)
+{
+ dt_node_t *stmt = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
+ dt_sugar_new_error_var(), dt_node_int(0)));
+ return (dt_node_clause(dp->dtsp_pdescs, NULL, stmt));
+}
+
+/*
+ * Evaluate the conditional, and recursively visit the body of the "if"
+ * statement (and the "else", if present).
+ */
+static void
+dt_sugar_do_if(dt_sugar_parse_t *dp, dt_node_t *if_stmt, int precondition)
+{
+ int newid;
+
+ assert(if_stmt->dn_kind == DT_NODE_IF);
+
+ /* condition */
+ newid = dt_sugar_new_condition(dp,
+ if_stmt->dn_conditional, precondition);
+
+ /* body of if */
+ dt_sugar_visit_stmts(dp, if_stmt->dn_body, newid);
+
+ /*
+ * Visit the body of the "else" statement, if present. Note that we
+ * generate a new condition which is the inverse of the previous
+ * condition.
+ */
+ if (if_stmt->dn_alternate_body != NULL) {
+ dt_node_t *pred =
+ dt_node_op1(DT_TOK_LNEG, dt_sugar_new_condition_var(newid));
+ dt_sugar_visit_stmts(dp, if_stmt->dn_alternate_body,
+ dt_sugar_new_condition(dp, pred, precondition));
+ }
+}
+
+/*
+ * Generate a new clause to evaluate the statements based on the condition.
+ * The new clause will be appended to dp_first_new_clause.
+ *
+ * dp_pdescs
+ * /!self->%error && this->%condition_<condid>/
+ * {
+ * stmts
+ * }
+ */
+static void
+dt_sugar_new_basic_block(dt_sugar_parse_t *dp, int condid, dt_node_t *stmts)
+{
+ dt_node_t *pred = NULL;
+
+ if (condid == 0) {
+ /*
+ * Don't bother with !error on the first clause, because if
+ * there is only one clause, we don't add the prelude to
+ * zero out %error.
+ */
+ if (dp->dtsp_num_conditions != 0) {
+ pred = dt_node_op1(DT_TOK_LNEG,
+ dt_sugar_new_error_var());
+ }
+ } else {
+ pred = dt_node_op2(DT_TOK_LAND,
+ dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var()),
+ dt_sugar_new_condition_var(condid));
+ }
+ dt_sugar_append_clause(dp,
+ dt_node_clause(dp->dtsp_pdescs, pred, stmts));
+}
+
+/*
+ * Visit all the statements in this list, and break them into basic blocks,
+ * generating new clauses for "if" and "else" statements.
+ */
+static void
+dt_sugar_visit_stmts(dt_sugar_parse_t *dp, dt_node_t *stmts, int precondition)
+{
+ dt_node_t *stmt;
+ dt_node_t *prev_stmt = NULL;
+ dt_node_t *next_stmt;
+ dt_node_t *first_stmt_in_basic_block = NULL;
+
+ for (stmt = stmts; stmt != NULL; stmt = next_stmt) {
+ next_stmt = stmt->dn_list;
+
+ if (stmt->dn_kind != DT_NODE_IF) {
+ if (first_stmt_in_basic_block == NULL)
+ first_stmt_in_basic_block = stmt;
+ prev_stmt = stmt;
+ continue;
+ }
+
+ /*
+ * Remove this and following statements from the previous
+ * clause.
+ */
+ if (prev_stmt != NULL)
+ prev_stmt->dn_list = NULL;
+
+ /*
+ * Generate clause for statements preceding the "if"
+ */
+ if (first_stmt_in_basic_block != NULL) {
+ dt_sugar_new_basic_block(dp, precondition,
+ first_stmt_in_basic_block);
+ }
+
+ dt_sugar_do_if(dp, stmt, precondition);
+
+ first_stmt_in_basic_block = NULL;
+
+ prev_stmt = stmt;
+ }
+
+ /* generate clause for statements after last "if". */
+ if (first_stmt_in_basic_block != NULL) {
+ dt_sugar_new_basic_block(dp, precondition,
+ first_stmt_in_basic_block);
+ }
+}
+
+/*
+ * Generate a new clause which will set the error variable when an error occurs.
+ * Only one of these clauses is created per program (e.g. script file).
+ * The clause is:
+ *
+ * dtrace:::ERROR{ self->%error = 1; }
+ */
+static dt_node_t *
+dt_sugar_makeerrorclause(void)
+{
+ dt_node_t *acts, *pdesc;
+
+ pdesc = dt_node_pdesc_by_name(strdup("dtrace:::ERROR"));
+
+ acts = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
+ dt_sugar_new_error_var(), dt_node_int(1)));
+
+ return (dt_node_clause(pdesc, NULL, acts));
+}
+
+/*
+ * Transform the super-clause into straight-D, returning the new list of
+ * sub-clauses.
+ */
+dt_node_t *
+dt_compile_sugar(dtrace_hdl_t *dtp, dt_node_t *clause)
+{
+ dt_sugar_parse_t dp = { 0 };
+ int condid = 0;
+
+ dp.dtsp_dtp = dtp;
+ dp.dtsp_pdescs = clause->dn_pdescs;
+
+ /* make dt_node_int() generate an "int"-typed integer */
+ yyintdecimal = B_TRUE;
+ yyintsuffix[0] = '\0';
+ yyintprefix = 0;
+
+ dt_sugar_visit_all(&dp, clause);
+
+ if (dp.dtsp_num_ifs == 0 && dp.dtsp_num_conditions == 0) {
+ /*
+ * There is nothing that modifies the number of clauses. Use
+ * the existing clause as-is, with its predicate intact. This
+ * ensures that in the absence of D sugar, the body of the
+ * clause can create a variable that is referenced in the
+ * predicate.
+ */
+ dt_sugar_append_clause(&dp, dt_node_clause(clause->dn_pdescs,
+ clause->dn_pred, clause->dn_acts));
+ } else {
+ if (clause->dn_pred != NULL) {
+ condid = dt_sugar_new_condition(&dp,
+ clause->dn_pred, condid);
+ }
+
+ if (clause->dn_acts == NULL) {
+ /*
+ * dt_sugar_visit_stmts() does not emit a clause with
+ * an empty body (e.g. if there's an empty "if" body),
+ * but we need the empty body here so that we
+ * continue to get the default tracing action.
+ */
+ dt_sugar_new_basic_block(&dp, condid, NULL);
+ } else {
+ dt_sugar_visit_stmts(&dp, clause->dn_acts, condid);
+ }
+ }
+
+ if (dp.dtsp_num_conditions != 0) {
+ dt_sugar_prepend_clause(&dp,
+ dt_sugar_new_clearerror_clause(&dp));
+ }
+
+ if (dp.dtsp_clause_list != NULL &&
+ dp.dtsp_clause_list->dn_list != NULL && !dtp->dt_has_sugar) {
+ dtp->dt_has_sugar = B_TRUE;
+ dt_sugar_prepend_clause(&dp, dt_sugar_makeerrorclause());
+ }
+ return (dp.dtsp_clause_list);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_work.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_work.c
new file mode 100644
index 000000000000..07565e0f7850
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_work.c
@@ -0,0 +1,320 @@
+/*
+ * 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.
+ *
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <dt_impl.h>
+#include <stddef.h>
+#include <errno.h>
+#include <assert.h>
+#include <time.h>
+
+static const struct {
+ int dtslt_option;
+ size_t dtslt_offs;
+} _dtrace_sleeptab[] = {
+ { DTRACEOPT_STATUSRATE, offsetof(dtrace_hdl_t, dt_laststatus) },
+ { DTRACEOPT_AGGRATE, offsetof(dtrace_hdl_t, dt_lastagg) },
+ { DTRACEOPT_SWITCHRATE, offsetof(dtrace_hdl_t, dt_lastswitch) },
+ { DTRACEOPT_MAX, 0 }
+};
+
+void
+dtrace_sleep(dtrace_hdl_t *dtp)
+{
+ dt_proc_hash_t *dph = dtp->dt_procs;
+ dtrace_optval_t policy = dtp->dt_options[DTRACEOPT_BUFPOLICY];
+ dt_proc_notify_t *dprn;
+
+ hrtime_t earliest = INT64_MAX;
+ struct timespec tv;
+ hrtime_t now;
+ int i;
+
+ for (i = 0; _dtrace_sleeptab[i].dtslt_option < DTRACEOPT_MAX; i++) {
+ uintptr_t a = (uintptr_t)dtp + _dtrace_sleeptab[i].dtslt_offs;
+ int opt = _dtrace_sleeptab[i].dtslt_option;
+ dtrace_optval_t interval = dtp->dt_options[opt];
+
+ /*
+ * If the buffering policy is set to anything other than
+ * "switch", we ignore the aggrate and switchrate -- they're
+ * meaningless.
+ */
+ if (policy != DTRACEOPT_BUFPOLICY_SWITCH &&
+ _dtrace_sleeptab[i].dtslt_option != DTRACEOPT_STATUSRATE)
+ continue;
+
+ if (*((hrtime_t *)a) + interval < earliest)
+ earliest = *((hrtime_t *)a) + interval;
+ }
+
+ (void) pthread_mutex_lock(&dph->dph_lock);
+
+ now = gethrtime();
+
+ if (earliest < now) {
+ (void) pthread_mutex_unlock(&dph->dph_lock);
+ return; /* sleep duration has already past */
+ }
+
+#ifdef illumos
+ tv.tv_sec = (earliest - now) / NANOSEC;
+ tv.tv_nsec = (earliest - now) % NANOSEC;
+
+ /*
+ * Wait for either 'tv' nanoseconds to pass or to receive notification
+ * that a process is in an interesting state. Regardless of why we
+ * awaken, iterate over any pending notifications and process them.
+ */
+ (void) pthread_cond_reltimedwait_np(&dph->dph_cv, &dph->dph_lock, &tv);
+#else
+ earliest -= now;
+ clock_gettime(CLOCK_REALTIME,&tv);
+ tv.tv_sec += earliest / NANOSEC;
+ tv.tv_nsec += earliest % NANOSEC;
+ while (tv.tv_nsec > NANOSEC) {
+ tv.tv_sec += 1;
+ tv.tv_nsec -= NANOSEC;
+ }
+
+ /*
+ * Wait for either 'tv' nanoseconds to pass or to receive notification
+ * that a process is in an interesting state. Regardless of why we
+ * awaken, iterate over any pending notifications and process them.
+ */
+ (void) pthread_cond_timedwait(&dph->dph_cv, &dph->dph_lock, &tv);
+#endif
+
+ while ((dprn = dph->dph_notify) != NULL) {
+ if (dtp->dt_prochdlr != NULL) {
+ char *err = dprn->dprn_errmsg;
+ if (*err == '\0')
+ err = NULL;
+
+ dtp->dt_prochdlr(dprn->dprn_dpr->dpr_proc, err,
+ dtp->dt_procarg);
+ }
+
+ dph->dph_notify = dprn->dprn_next;
+ dt_free(dtp, dprn);
+ }
+
+ (void) pthread_mutex_unlock(&dph->dph_lock);
+}
+
+int
+dtrace_status(dtrace_hdl_t *dtp)
+{
+ int gen = dtp->dt_statusgen;
+ dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_STATUSRATE];
+ hrtime_t now = gethrtime();
+
+ if (!dtp->dt_active)
+ return (DTRACE_STATUS_NONE);
+
+ if (dtp->dt_stopped)
+ return (DTRACE_STATUS_STOPPED);
+
+ if (dtp->dt_laststatus != 0) {
+ if (now - dtp->dt_laststatus < interval)
+ return (DTRACE_STATUS_NONE);
+
+ dtp->dt_laststatus += interval;
+ } else {
+ dtp->dt_laststatus = now;
+ }
+
+ if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ dtp->dt_statusgen ^= 1;
+
+ if (dt_handle_status(dtp, &dtp->dt_status[dtp->dt_statusgen],
+ &dtp->dt_status[gen]) == -1)
+ return (-1);
+
+ if (dtp->dt_status[gen].dtst_exiting) {
+ if (!dtp->dt_stopped)
+ (void) dtrace_stop(dtp);
+
+ return (DTRACE_STATUS_EXITED);
+ }
+
+ if (dtp->dt_status[gen].dtst_filled == 0)
+ return (DTRACE_STATUS_OKAY);
+
+ if (dtp->dt_options[DTRACEOPT_BUFPOLICY] != DTRACEOPT_BUFPOLICY_FILL)
+ return (DTRACE_STATUS_OKAY);
+
+ if (!dtp->dt_stopped) {
+ if (dtrace_stop(dtp) == -1)
+ return (-1);
+ }
+
+ return (DTRACE_STATUS_FILLED);
+}
+
+int
+dtrace_go(dtrace_hdl_t *dtp)
+{
+ dtrace_enable_io_t args;
+ void *dof;
+ int error, r;
+
+ if (dtp->dt_active)
+ return (dt_set_errno(dtp, EINVAL));
+
+ /*
+ * If a dtrace:::ERROR program and callback are registered, enable the
+ * program before we start tracing. If this fails for a vector open
+ * with ENOTTY, we permit dtrace_go() to succeed so that vector clients
+ * such as mdb's dtrace module can execute the rest of dtrace_go() even
+ * though they do not provide support for the DTRACEIOC_ENABLE ioctl.
+ */
+ if (dtp->dt_errprog != NULL &&
+ dtrace_program_exec(dtp, dtp->dt_errprog, NULL) == -1 && (
+ dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL))
+ return (-1); /* dt_errno has been set for us */
+
+ if ((dof = dtrace_getopt_dof(dtp)) == NULL)
+ return (-1); /* dt_errno has been set for us */
+
+ args.dof = dof;
+ args.n_matched = 0;
+ r = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
+ error = errno;
+ dtrace_dof_destroy(dtp, dof);
+
+ if (r == -1 && (error != ENOTTY || dtp->dt_vector == NULL))
+ return (dt_set_errno(dtp, error));
+
+ if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) {
+ if (errno == EACCES)
+ return (dt_set_errno(dtp, EDT_DESTRUCTIVE));
+
+ if (errno == EALREADY)
+ return (dt_set_errno(dtp, EDT_ISANON));
+
+ if (errno == ENOENT)
+ return (dt_set_errno(dtp, EDT_NOANON));
+
+ if (errno == E2BIG)
+ return (dt_set_errno(dtp, EDT_ENDTOOBIG));
+
+ if (errno == ENOSPC)
+ return (dt_set_errno(dtp, EDT_BUFTOOSMALL));
+
+ return (dt_set_errno(dtp, errno));
+ }
+
+ dtp->dt_active = 1;
+
+ if (dt_options_load(dtp) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ return (dt_aggregate_go(dtp));
+}
+
+int
+dtrace_stop(dtrace_hdl_t *dtp)
+{
+ int gen = dtp->dt_statusgen;
+
+ if (dtp->dt_stopped)
+ return (0);
+
+ if (dt_ioctl(dtp, DTRACEIOC_STOP, &dtp->dt_endedon) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ dtp->dt_stopped = 1;
+
+ /*
+ * Now that we're stopped, we're going to get status one final time.
+ */
+ if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ if (dt_handle_status(dtp, &dtp->dt_status[gen ^ 1],
+ &dtp->dt_status[gen]) == -1)
+ return (-1);
+
+ return (0);
+}
+
+
+dtrace_workstatus_t
+dtrace_work(dtrace_hdl_t *dtp, FILE *fp,
+ dtrace_consume_probe_f *pfunc, dtrace_consume_rec_f *rfunc, void *arg)
+{
+ int status = dtrace_status(dtp);
+ dtrace_optval_t policy = dtp->dt_options[DTRACEOPT_BUFPOLICY];
+ dtrace_workstatus_t rval;
+
+ switch (status) {
+ case DTRACE_STATUS_EXITED:
+ case DTRACE_STATUS_FILLED:
+ case DTRACE_STATUS_STOPPED:
+ /*
+ * Tracing is stopped. We now want to force dtrace_consume()
+ * and dtrace_aggregate_snap() to proceed, regardless of
+ * switchrate and aggrate. We do this by clearing the times.
+ */
+ dtp->dt_lastswitch = 0;
+ dtp->dt_lastagg = 0;
+ rval = DTRACE_WORKSTATUS_DONE;
+ break;
+
+ case DTRACE_STATUS_NONE:
+ case DTRACE_STATUS_OKAY:
+ rval = DTRACE_WORKSTATUS_OKAY;
+ break;
+
+ case -1:
+ return (DTRACE_WORKSTATUS_ERROR);
+ }
+
+ if ((status == DTRACE_STATUS_NONE || status == DTRACE_STATUS_OKAY) &&
+ policy != DTRACEOPT_BUFPOLICY_SWITCH) {
+ /*
+ * There either isn't any status or things are fine -- and
+ * this is a "ring" or "fill" buffer. We don't want to consume
+ * any of the trace data or snapshot the aggregations; we just
+ * return.
+ */
+ assert(rval == DTRACE_WORKSTATUS_OKAY);
+ return (rval);
+ }
+
+ if (dtrace_aggregate_snap(dtp) == -1)
+ return (DTRACE_WORKSTATUS_ERROR);
+
+ if (dtrace_consume(dtp, fp, pfunc, rfunc, arg) == -1)
+ return (DTRACE_WORKSTATUS_ERROR);
+
+ return (rval);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c
new file mode 100644
index 000000000000..832a2523572b
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c
@@ -0,0 +1,388 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+#include <strings.h>
+#include <assert.h>
+
+#include <dt_xlator.h>
+#include <dt_parser.h>
+#include <dt_grammar.h>
+#include <dt_module.h>
+#include <dt_impl.h>
+
+/*
+ * Create a member node corresponding to one of the output members of a dynamic
+ * translator. We set the member's dn_membexpr to a DT_NODE_XLATOR node that
+ * has dn_op set to DT_TOK_XLATE and refers back to the translator itself. The
+ * code generator will then use this as the indicator for dynamic translation.
+ */
+/*ARGSUSED*/
+static int
+dt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
+{
+ dt_xlator_t *dxp = arg;
+ dtrace_hdl_t *dtp = dxp->dx_hdl;
+ dt_node_t *enp, *mnp;
+
+ if ((enp = dt_node_xalloc(dtp, DT_NODE_XLATOR)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ enp->dn_link = dxp->dx_nodes;
+ dxp->dx_nodes = enp;
+
+ if ((mnp = dt_node_xalloc(dtp, DT_NODE_MEMBER)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ mnp->dn_link = dxp->dx_nodes;
+ dxp->dx_nodes = mnp;
+
+ /*
+ * For the member expression, we use a DT_NODE_XLATOR/TOK_XLATE whose
+ * xlator refers back to the translator and whose dn_xmember refers to
+ * the current member. These refs will be used by dt_cg.c and dt_as.c.
+ */
+ enp->dn_op = DT_TOK_XLATE;
+ enp->dn_xlator = dxp;
+ enp->dn_xmember = mnp;
+ dt_node_type_assign(enp, dxp->dx_dst_ctfp, type, B_FALSE);
+
+ /*
+ * For the member itself, we use a DT_NODE_MEMBER as usual with the
+ * appropriate name, output type, and member expression set to 'enp'.
+ */
+ if (dxp->dx_members != NULL) {
+ assert(enp->dn_link->dn_kind == DT_NODE_MEMBER);
+ enp->dn_link->dn_list = mnp;
+ } else
+ dxp->dx_members = mnp;
+
+ mnp->dn_membname = strdup(name);
+ mnp->dn_membexpr = enp;
+ dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type, B_FALSE);
+
+ if (mnp->dn_membname == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ return (0);
+}
+
+dt_xlator_t *
+dt_xlator_create(dtrace_hdl_t *dtp,
+ const dtrace_typeinfo_t *src, const dtrace_typeinfo_t *dst,
+ const char *name, dt_node_t *members, dt_node_t *nodes)
+{
+ dt_xlator_t *dxp = dt_zalloc(dtp, sizeof (dt_xlator_t));
+ dtrace_typeinfo_t ptr = *dst;
+ dt_xlator_t **map;
+ dt_node_t *dnp;
+ uint_t kind;
+
+ if (dxp == NULL)
+ return (NULL);
+
+ dxp->dx_hdl = dtp;
+ dxp->dx_id = dtp->dt_xlatorid++;
+ dxp->dx_gen = dtp->dt_gen;
+ dxp->dx_arg = -1;
+
+ if ((map = dt_alloc(dtp, sizeof (void *) * (dxp->dx_id + 1))) == NULL) {
+ dt_free(dtp, dxp);
+ return (NULL);
+ }
+
+ dt_list_append(&dtp->dt_xlators, dxp);
+ bcopy(dtp->dt_xlatormap, map, sizeof (void *) * dxp->dx_id);
+ dt_free(dtp, dtp->dt_xlatormap);
+ dtp->dt_xlatormap = map;
+ dtp->dt_xlatormap[dxp->dx_id] = dxp;
+
+ if (dt_type_pointer(&ptr) == -1) {
+ ptr.dtt_ctfp = NULL;
+ ptr.dtt_type = CTF_ERR;
+ }
+
+ dxp->dx_ident = dt_ident_create(name ? name : "T",
+ DT_IDENT_SCALAR, DT_IDFLG_REF | DT_IDFLG_ORPHAN, 0,
+ _dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
+
+ if (dxp->dx_ident == NULL)
+ goto err; /* no memory for identifier */
+
+ dxp->dx_ident->di_ctfp = src->dtt_ctfp;
+ dxp->dx_ident->di_type = src->dtt_type;
+
+ /*
+ * If an input parameter name is given, this is a static translator
+ * definition: create an idhash and identifier for the parameter.
+ */
+ if (name != NULL) {
+ dxp->dx_locals = dt_idhash_create("xlparams", NULL, 0, 0);
+
+ if (dxp->dx_locals == NULL)
+ goto err; /* no memory for identifier hash */
+
+ dt_idhash_xinsert(dxp->dx_locals, dxp->dx_ident);
+ }
+
+ dxp->dx_souid.di_name = "translator";
+ dxp->dx_souid.di_kind = DT_IDENT_XLSOU;
+ dxp->dx_souid.di_flags = DT_IDFLG_REF;
+ dxp->dx_souid.di_id = dxp->dx_id;
+ dxp->dx_souid.di_attr = _dtrace_defattr;
+ dxp->dx_souid.di_ops = &dt_idops_thaw;
+ dxp->dx_souid.di_data = dxp;
+ dxp->dx_souid.di_ctfp = dst->dtt_ctfp;
+ dxp->dx_souid.di_type = dst->dtt_type;
+ dxp->dx_souid.di_gen = dtp->dt_gen;
+
+ dxp->dx_ptrid.di_name = "translator";
+ dxp->dx_ptrid.di_kind = DT_IDENT_XLPTR;
+ dxp->dx_ptrid.di_flags = DT_IDFLG_REF;
+ dxp->dx_ptrid.di_id = dxp->dx_id;
+ dxp->dx_ptrid.di_attr = _dtrace_defattr;
+ dxp->dx_ptrid.di_ops = &dt_idops_thaw;
+ dxp->dx_ptrid.di_data = dxp;
+ dxp->dx_ptrid.di_ctfp = ptr.dtt_ctfp;
+ dxp->dx_ptrid.di_type = ptr.dtt_type;
+ dxp->dx_ptrid.di_gen = dtp->dt_gen;
+
+ /*
+ * If a deferred pragma is pending on the keyword "translator", run all
+ * the deferred pragmas on dx_souid and then copy results to dx_ptrid.
+ * See the code in dt_pragma.c for details on deferred ident pragmas.
+ */
+ if (dtp->dt_globals->dh_defer != NULL && yypcb->pcb_pragmas != NULL &&
+ dt_idhash_lookup(yypcb->pcb_pragmas, "translator") != NULL) {
+ dtp->dt_globals->dh_defer(dtp->dt_globals, &dxp->dx_souid);
+ dxp->dx_ptrid.di_attr = dxp->dx_souid.di_attr;
+ dxp->dx_ptrid.di_vers = dxp->dx_souid.di_vers;
+ }
+
+ dxp->dx_src_ctfp = src->dtt_ctfp;
+ dxp->dx_src_type = src->dtt_type;
+ dxp->dx_src_base = ctf_type_resolve(src->dtt_ctfp, src->dtt_type);
+
+ dxp->dx_dst_ctfp = dst->dtt_ctfp;
+ dxp->dx_dst_type = dst->dtt_type;
+ dxp->dx_dst_base = ctf_type_resolve(dst->dtt_ctfp, dst->dtt_type);
+
+ kind = ctf_type_kind(dst->dtt_ctfp, dxp->dx_dst_base);
+ assert(kind == CTF_K_STRUCT || kind == CTF_K_UNION);
+
+ /*
+ * If no input parameter is given, we're making a dynamic translator:
+ * create member nodes for every member of the output type. Otherwise
+ * retain the member and allocation node lists presented by the parser.
+ */
+ if (name == NULL) {
+ if (ctf_member_iter(dxp->dx_dst_ctfp, dxp->dx_dst_base,
+ dt_xlator_create_member, dxp) != 0)
+ goto err;
+ } else {
+ dxp->dx_members = members;
+ dxp->dx_nodes = nodes;
+ }
+
+ /*
+ * Assign member IDs to each member and allocate space for DIFOs
+ * if and when this translator is eventually compiled.
+ */
+ for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
+ dnp->dn_membxlator = dxp;
+ dnp->dn_membid = dxp->dx_nmembers++;
+ }
+
+ dxp->dx_membdif = dt_zalloc(dtp,
+ sizeof (dtrace_difo_t *) * dxp->dx_nmembers);
+
+ if (dxp->dx_membdif == NULL) {
+ dxp->dx_nmembers = 0;
+ goto err;
+ }
+
+ return (dxp);
+
+err:
+ dt_xlator_destroy(dtp, dxp);
+ return (NULL);
+}
+
+void
+dt_xlator_destroy(dtrace_hdl_t *dtp, dt_xlator_t *dxp)
+{
+ uint_t i;
+
+ dt_node_link_free(&dxp->dx_nodes);
+
+ if (dxp->dx_locals != NULL)
+ dt_idhash_destroy(dxp->dx_locals);
+ else if (dxp->dx_ident != NULL)
+ dt_ident_destroy(dxp->dx_ident);
+
+ for (i = 0; i < dxp->dx_nmembers; i++)
+ dt_difo_free(dtp, dxp->dx_membdif[i]);
+
+ dt_free(dtp, dxp->dx_membdif);
+ dt_list_delete(&dtp->dt_xlators, dxp);
+ dt_free(dtp, dxp);
+}
+
+dt_xlator_t *
+dt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags)
+{
+ ctf_file_t *src_ctfp = src->dn_ctfp;
+ ctf_id_t src_type = src->dn_type;
+ ctf_id_t src_base = ctf_type_resolve(src_ctfp, src_type);
+
+ ctf_file_t *dst_ctfp = dst->dn_ctfp;
+ ctf_id_t dst_type = dst->dn_type;
+ ctf_id_t dst_base = ctf_type_resolve(dst_ctfp, dst_type);
+ uint_t dst_kind = ctf_type_kind(dst_ctfp, dst_base);
+
+ int ptr = dst_kind == CTF_K_POINTER;
+ dtrace_typeinfo_t src_dtt, dst_dtt;
+ dt_node_t xn = { 0 };
+ dt_xlator_t *dxp = NULL;
+
+ if (src_base == CTF_ERR || dst_base == CTF_ERR)
+ return (NULL); /* fail if these are unresolvable types */
+
+ /*
+ * Translators are always defined using a struct or union type, so if
+ * we are attempting to translate to type "T *", we internally look
+ * for a translation to type "T" by following the pointer reference.
+ */
+ if (ptr) {
+ dst_type = ctf_type_reference(dst_ctfp, dst_type);
+ dst_base = ctf_type_resolve(dst_ctfp, dst_type);
+ dst_kind = ctf_type_kind(dst_ctfp, dst_base);
+ }
+
+ if (dst_kind != CTF_K_UNION && dst_kind != CTF_K_STRUCT)
+ return (NULL); /* fail if the output isn't a struct or union */
+
+ /*
+ * In order to find a matching translator, we iterate over the set of
+ * available translators in three passes. First, we look for a
+ * translation from the exact source type to the resolved destination.
+ * Second, we look for a translation from the resolved source type to
+ * the resolved destination. Third, we look for a translation from a
+ * compatible source type (using the same rules as parameter formals)
+ * to the resolved destination. If all passes fail, return NULL.
+ */
+ for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
+ dxp = dt_list_next(dxp)) {
+ if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_type,
+ src_ctfp, src_type) &&
+ ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
+ dst_ctfp, dst_base))
+ goto out;
+ }
+
+ if (flags & DT_XLATE_EXACT)
+ goto out; /* skip remaining passes if exact match required */
+
+ for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
+ dxp = dt_list_next(dxp)) {
+ if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_base,
+ src_ctfp, src_type) &&
+ ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
+ dst_ctfp, dst_base))
+ goto out;
+ }
+
+ for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
+ dxp = dt_list_next(dxp)) {
+ dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type,
+ B_FALSE);
+ if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
+ dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn))
+ goto out;
+ }
+
+out:
+ if (ptr && dxp != NULL && dxp->dx_ptrid.di_type == CTF_ERR)
+ return (NULL); /* no translation available to pointer type */
+
+ if (dxp != NULL || !(flags & DT_XLATE_EXTERN) ||
+ dtp->dt_xlatemode == DT_XL_STATIC)
+ return (dxp); /* we succeeded or not allowed to extern */
+
+ /*
+ * If we get here, then we didn't find an existing translator, but the
+ * caller and xlatemode permit us to create an extern to a dynamic one.
+ */
+ src_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, src_ctfp)->dm_name;
+ src_dtt.dtt_ctfp = src_ctfp;
+ src_dtt.dtt_type = src_type;
+
+ dst_dtt = (dtrace_typeinfo_t){
+ .dtt_object = dt_module_lookup_by_ctf(dtp, dst_ctfp)->dm_name,
+ .dtt_ctfp = dst_ctfp,
+ .dtt_type = dst_type,
+ };
+
+ return (dt_xlator_create(dtp, &src_dtt, &dst_dtt, NULL, NULL, NULL));
+}
+
+dt_xlator_t *
+dt_xlator_lookup_id(dtrace_hdl_t *dtp, id_t id)
+{
+ assert(id >= 0 && id < dtp->dt_xlatorid);
+ return (dtp->dt_xlatormap[id]);
+}
+
+dt_ident_t *
+dt_xlator_ident(dt_xlator_t *dxp, ctf_file_t *ctfp, ctf_id_t type)
+{
+ if (ctf_type_kind(ctfp, ctf_type_resolve(ctfp, type)) == CTF_K_POINTER)
+ return (&dxp->dx_ptrid);
+ else
+ return (&dxp->dx_souid);
+}
+
+dt_node_t *
+dt_xlator_member(dt_xlator_t *dxp, const char *name)
+{
+ dt_node_t *dnp;
+
+ for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
+ if (strcmp(dnp->dn_membname, name) == 0)
+ return (dnp);
+ }
+
+ return (NULL);
+}
+
+int
+dt_xlator_dynamic(const dt_xlator_t *dxp)
+{
+ return (dxp->dx_locals == NULL);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.h
new file mode 100644
index 000000000000..a30f3aff64dd
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DT_XLATOR_H
+#define _DT_XLATOR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libctf.h>
+#include <dtrace.h>
+#include <dt_ident.h>
+#include <dt_list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dt_node;
+
+typedef struct dt_xlator {
+ dt_list_t dx_list; /* list forward/back pointers */
+ dt_idhash_t *dx_locals; /* hash of local scope identifiers */
+ dt_ident_t *dx_ident; /* identifier ref for input param */
+ dt_ident_t dx_souid; /* fake identifier for sou output */
+ dt_ident_t dx_ptrid; /* fake identifier for ptr output */
+ ctf_file_t *dx_src_ctfp; /* CTF container for input type */
+ ctf_id_t dx_src_type; /* CTF reference for input type */
+ ctf_id_t dx_src_base; /* CTF reference for input base */
+ ctf_file_t *dx_dst_ctfp; /* CTF container for output type */
+ ctf_id_t dx_dst_type; /* CTF reference for output type */
+ ctf_id_t dx_dst_base; /* CTF reference for output base */
+ struct dt_node *dx_members; /* list of member translations */
+ uint_t dx_nmembers; /* length of dx_members list */
+ dtrace_difo_t **dx_membdif; /* DIF for member expressions */
+ struct dt_node *dx_nodes; /* list of parse tree nodes */
+ dtrace_hdl_t *dx_hdl; /* back pointer to containing handle */
+ ulong_t dx_gen; /* generation number that created me */
+ id_t dx_id; /* global translator id */
+ int dx_arg; /* dynamic argument index */
+} dt_xlator_t;
+
+extern dt_xlator_t *dt_xlator_create(dtrace_hdl_t *,
+ const dtrace_typeinfo_t *, const dtrace_typeinfo_t *,
+ const char *, struct dt_node *, struct dt_node *);
+
+extern void dt_xlator_destroy(dtrace_hdl_t *, dt_xlator_t *);
+
+#define DT_XLATE_FUZZY 0x0 /* lookup any matching translator */
+#define DT_XLATE_EXACT 0x1 /* lookup only exact type matches */
+#define DT_XLATE_EXTERN 0x2 /* extern translator if none exists */
+
+extern dt_xlator_t *dt_xlator_lookup(dtrace_hdl_t *,
+ struct dt_node *, struct dt_node *, int);
+
+extern dt_xlator_t *dt_xlator_lookup_id(dtrace_hdl_t *, id_t);
+extern dt_ident_t *dt_xlator_ident(dt_xlator_t *, ctf_file_t *, ctf_id_t);
+extern struct dt_node *dt_xlator_member(dt_xlator_t *, const char *);
+extern int dt_xlator_dynamic(const dt_xlator_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DT_XLATOR_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
new file mode 100644
index 000000000000..f0bc83a7fc7b
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
@@ -0,0 +1,618 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _DTRACE_H
+#define _DTRACE_H
+
+#include <sys/dtrace.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <gelf.h>
+#include <libproc.h>
+#ifndef illumos
+#include <rtld_db.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * DTrace Dynamic Tracing Software: Library Interfaces
+ *
+ * Note: The contents of this file are private to the implementation of the
+ * Solaris system and DTrace subsystem and are subject to change at any time
+ * without notice. Applications and drivers using these interfaces will fail
+ * to run on future releases. These interfaces should not be used for any
+ * purpose except those expressly outlined in dtrace(7D) and libdtrace(3LIB).
+ * Please refer to the "Solaris Dynamic Tracing Guide" for more information.
+ */
+
+#define DTRACE_VERSION 3 /* library ABI interface version */
+
+struct ps_prochandle;
+struct dt_node;
+typedef struct dtrace_hdl dtrace_hdl_t;
+typedef struct dtrace_prog dtrace_prog_t;
+typedef struct dtrace_vector dtrace_vector_t;
+typedef struct dtrace_aggdata dtrace_aggdata_t;
+
+#define DTRACE_O_NODEV 0x01 /* do not open dtrace(7D) device */
+#define DTRACE_O_NOSYS 0x02 /* do not load /system/object modules */
+#define DTRACE_O_LP64 0x04 /* force D compiler to be LP64 */
+#define DTRACE_O_ILP32 0x08 /* force D compiler to be ILP32 */
+#define DTRACE_O_MASK 0x0f /* mask of valid flags to dtrace_open */
+
+extern dtrace_hdl_t *dtrace_open(int, int, int *);
+extern dtrace_hdl_t *dtrace_vopen(int, int, int *,
+ const dtrace_vector_t *, void *);
+
+extern int dtrace_go(dtrace_hdl_t *);
+extern int dtrace_stop(dtrace_hdl_t *);
+extern void dtrace_sleep(dtrace_hdl_t *);
+extern void dtrace_close(dtrace_hdl_t *);
+
+extern int dtrace_errno(dtrace_hdl_t *);
+extern const char *dtrace_errmsg(dtrace_hdl_t *, int);
+extern const char *dtrace_faultstr(dtrace_hdl_t *, int);
+extern const char *dtrace_subrstr(dtrace_hdl_t *, int);
+
+extern int dtrace_setopt(dtrace_hdl_t *, const char *, const char *);
+extern int dtrace_getopt(dtrace_hdl_t *, const char *, dtrace_optval_t *);
+
+extern void dtrace_update(dtrace_hdl_t *);
+extern int dtrace_ctlfd(dtrace_hdl_t *);
+
+/*
+ * DTrace Program Interface
+ *
+ * DTrace programs can be created by compiling ASCII text files containing
+ * D programs or by compiling in-memory C strings that specify a D program.
+ * Once created, callers can examine the list of program statements and
+ * enable the probes and actions described by these statements.
+ */
+
+typedef struct dtrace_proginfo {
+ dtrace_attribute_t dpi_descattr; /* minimum probedesc attributes */
+ dtrace_attribute_t dpi_stmtattr; /* minimum statement attributes */
+ uint_t dpi_aggregates; /* number of aggregates specified in program */
+ uint_t dpi_recgens; /* number of record generating probes in prog */
+ uint_t dpi_matches; /* number of probes matched by program */
+ uint_t dpi_speculations; /* number of speculations specified in prog */
+} dtrace_proginfo_t;
+
+#define DTRACE_C_DIFV 0x0001 /* DIF verbose mode: show each compiled DIFO */
+#define DTRACE_C_EMPTY 0x0002 /* Permit compilation of empty D source files */
+#define DTRACE_C_ZDEFS 0x0004 /* Permit probe defs that match zero probes */
+#define DTRACE_C_EATTR 0x0008 /* Error if program attributes less than min */
+#define DTRACE_C_CPP 0x0010 /* Preprocess input file with cpp(1) utility */
+#define DTRACE_C_KNODEF 0x0020 /* Permit unresolved kernel symbols in DIFO */
+#define DTRACE_C_UNODEF 0x0040 /* Permit unresolved user symbols in DIFO */
+#define DTRACE_C_PSPEC 0x0080 /* Interpret ambiguous specifiers as probes */
+#define DTRACE_C_ETAGS 0x0100 /* Prefix error messages with error tags */
+#define DTRACE_C_ARGREF 0x0200 /* Do not require all macro args to be used */
+#define DTRACE_C_DEFARG 0x0800 /* Use 0/"" as value for unspecified args */
+#define DTRACE_C_NOLIBS 0x1000 /* Do not process D system libraries */
+#define DTRACE_C_CTL 0x2000 /* Only process control directives */
+#define DTRACE_C_MASK 0x3bff /* mask of all valid flags to dtrace_*compile */
+
+extern dtrace_prog_t *dtrace_program_strcompile(dtrace_hdl_t *,
+ const char *, dtrace_probespec_t, uint_t, int, char *const []);
+
+extern dtrace_prog_t *dtrace_program_fcompile(dtrace_hdl_t *,
+ FILE *, uint_t, int, char *const []);
+
+extern int dtrace_program_exec(dtrace_hdl_t *, dtrace_prog_t *,
+ dtrace_proginfo_t *);
+extern void dtrace_program_info(dtrace_hdl_t *, dtrace_prog_t *,
+ dtrace_proginfo_t *);
+
+#define DTRACE_D_STRIP 0x01 /* strip non-loadable sections from program */
+#define DTRACE_D_PROBES 0x02 /* include provider and probe definitions */
+#define DTRACE_D_MASK 0x03 /* mask of valid flags to dtrace_dof_create */
+
+extern int dtrace_program_link(dtrace_hdl_t *, dtrace_prog_t *,
+ uint_t, const char *, int, char *const []);
+
+extern int dtrace_program_header(dtrace_hdl_t *, FILE *, const char *);
+
+extern void *dtrace_dof_create(dtrace_hdl_t *, dtrace_prog_t *, uint_t);
+extern void dtrace_dof_destroy(dtrace_hdl_t *, void *);
+
+extern void *dtrace_getopt_dof(dtrace_hdl_t *);
+extern void *dtrace_geterr_dof(dtrace_hdl_t *);
+
+typedef struct dtrace_stmtdesc {
+ dtrace_ecbdesc_t *dtsd_ecbdesc; /* ECB description */
+ dtrace_actdesc_t *dtsd_action; /* action list */
+ dtrace_actdesc_t *dtsd_action_last; /* last action in action list */
+ void *dtsd_aggdata; /* aggregation data */
+ void *dtsd_fmtdata; /* type-specific output data */
+ void *dtsd_strdata; /* type-specific string data */
+ void (*dtsd_callback)(void); /* callback function for EPID */
+ void *dtsd_data; /* callback data pointer */
+ dtrace_attribute_t dtsd_descattr; /* probedesc attributes */
+ dtrace_attribute_t dtsd_stmtattr; /* statement attributes */
+} dtrace_stmtdesc_t;
+
+typedef int dtrace_stmt_f(dtrace_hdl_t *, dtrace_prog_t *,
+ dtrace_stmtdesc_t *, void *);
+
+extern dtrace_stmtdesc_t *dtrace_stmt_create(dtrace_hdl_t *,
+ dtrace_ecbdesc_t *);
+extern dtrace_actdesc_t *dtrace_stmt_action(dtrace_hdl_t *,
+ dtrace_stmtdesc_t *);
+extern int dtrace_stmt_add(dtrace_hdl_t *, dtrace_prog_t *,
+ dtrace_stmtdesc_t *);
+extern int dtrace_stmt_iter(dtrace_hdl_t *, dtrace_prog_t *,
+ dtrace_stmt_f *, void *);
+extern void dtrace_stmt_destroy(dtrace_hdl_t *, dtrace_stmtdesc_t *);
+
+/*
+ * DTrace Data Consumption Interface
+ */
+typedef enum {
+ DTRACEFLOW_ENTRY,
+ DTRACEFLOW_RETURN,
+ DTRACEFLOW_NONE
+} dtrace_flowkind_t;
+
+#define DTRACE_CONSUME_ERROR -1 /* error while processing */
+#define DTRACE_CONSUME_THIS 0 /* consume this probe/record */
+#define DTRACE_CONSUME_NEXT 1 /* advance to next probe/rec */
+#define DTRACE_CONSUME_ABORT 2 /* abort consumption */
+
+typedef struct dtrace_probedata {
+ dtrace_hdl_t *dtpda_handle; /* handle to DTrace library */
+ dtrace_eprobedesc_t *dtpda_edesc; /* enabled probe description */
+ dtrace_probedesc_t *dtpda_pdesc; /* probe description */
+ processorid_t dtpda_cpu; /* CPU for data */
+ caddr_t dtpda_data; /* pointer to raw data */
+ dtrace_flowkind_t dtpda_flow; /* flow kind */
+ const char *dtpda_prefix; /* recommended flow prefix */
+ int dtpda_indent; /* recommended flow indent */
+} dtrace_probedata_t;
+
+typedef int dtrace_consume_probe_f(const dtrace_probedata_t *, void *);
+typedef int dtrace_consume_rec_f(const dtrace_probedata_t *,
+ const dtrace_recdesc_t *, void *);
+
+extern int dtrace_consume(dtrace_hdl_t *, FILE *,
+ dtrace_consume_probe_f *, dtrace_consume_rec_f *, void *);
+
+#define DTRACE_STATUS_NONE 0 /* no status; not yet time */
+#define DTRACE_STATUS_OKAY 1 /* status okay */
+#define DTRACE_STATUS_EXITED 2 /* exit() was called; tracing stopped */
+#define DTRACE_STATUS_FILLED 3 /* fill buffer filled; tracing stoped */
+#define DTRACE_STATUS_STOPPED 4 /* tracing already stopped */
+
+extern int dtrace_status(dtrace_hdl_t *);
+
+/*
+ * DTrace Formatted Output Interfaces
+ *
+ * To format output associated with a given dtrace_stmtdesc, the caller can
+ * invoke one of the following functions, passing the opaque dtsd_fmtdata and a
+ * list of record descriptions. These functions return either -1 to indicate
+ * an error, or a positive integer indicating the number of records consumed.
+ * For anonymous enablings, the consumer can use the dtrd_format member of
+ * the record description to obtain a format description. The dtfd_string
+ * member of the format description may be passed to dtrace_print{fa}_create()
+ * to create the opaque format data.
+ */
+extern void *dtrace_printf_create(dtrace_hdl_t *, const char *);
+extern void *dtrace_printa_create(dtrace_hdl_t *, const char *);
+extern size_t dtrace_printf_format(dtrace_hdl_t *, void *, char *, size_t);
+
+extern int dtrace_fprintf(dtrace_hdl_t *, FILE *, void *,
+ const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
+ const void *, size_t);
+
+extern int dtrace_fprinta(dtrace_hdl_t *, FILE *, void *,
+ const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
+ const void *, size_t);
+
+extern int dtrace_system(dtrace_hdl_t *, FILE *, void *,
+ const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
+ const void *, size_t);
+
+extern int dtrace_freopen(dtrace_hdl_t *, FILE *, void *,
+ const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
+ const void *, size_t);
+
+/*
+ * Type-specific output printing
+ *
+ * The print() action will associate a string data record that is actually the
+ * fully-qualified type name of the data traced by the DIFEXPR action. This is
+ * stored in the same 'format' record from the kernel, but we know by virtue of
+ * the fact that the action is still DIFEXPR that it is actually a reference to
+ * plain string data.
+ */
+extern int dtrace_print(dtrace_hdl_t *, FILE *, const char *,
+ caddr_t, size_t);
+
+/*
+ * DTrace Work Interface
+ */
+typedef enum {
+ DTRACE_WORKSTATUS_ERROR = -1,
+ DTRACE_WORKSTATUS_OKAY,
+ DTRACE_WORKSTATUS_DONE
+} dtrace_workstatus_t;
+
+extern dtrace_workstatus_t dtrace_work(dtrace_hdl_t *, FILE *,
+ dtrace_consume_probe_f *, dtrace_consume_rec_f *, void *);
+
+/*
+ * DTrace Handler Interface
+ */
+#define DTRACE_HANDLE_ABORT -1 /* abort current operation */
+#define DTRACE_HANDLE_OK 0 /* handled okay; continue */
+
+typedef struct dtrace_errdata {
+ dtrace_hdl_t *dteda_handle; /* handle to DTrace library */
+ dtrace_eprobedesc_t *dteda_edesc; /* enabled probe inducing err */
+ dtrace_probedesc_t *dteda_pdesc; /* probe inducing error */
+ processorid_t dteda_cpu; /* CPU of error */
+ int dteda_action; /* action inducing error */
+ int dteda_offset; /* offset in DIFO of error */
+ int dteda_fault; /* specific fault */
+ uint64_t dteda_addr; /* address of fault, if any */
+ const char *dteda_msg; /* preconstructed message */
+} dtrace_errdata_t;
+
+typedef int dtrace_handle_err_f(const dtrace_errdata_t *, void *);
+extern int dtrace_handle_err(dtrace_hdl_t *, dtrace_handle_err_f *, void *);
+
+typedef enum {
+ DTRACEDROP_PRINCIPAL, /* drop to principal buffer */
+ DTRACEDROP_AGGREGATION, /* drop to aggregation buffer */
+ DTRACEDROP_DYNAMIC, /* dynamic drop */
+ DTRACEDROP_DYNRINSE, /* dyn drop due to rinsing */
+ DTRACEDROP_DYNDIRTY, /* dyn drop due to dirty */
+ DTRACEDROP_SPEC, /* speculative drop */
+ DTRACEDROP_SPECBUSY, /* spec drop due to busy */
+ DTRACEDROP_SPECUNAVAIL, /* spec drop due to unavail */
+ DTRACEDROP_STKSTROVERFLOW, /* stack string tab overflow */
+ DTRACEDROP_DBLERROR /* error in ERROR probe */
+} dtrace_dropkind_t;
+
+typedef struct dtrace_dropdata {
+ dtrace_hdl_t *dtdda_handle; /* handle to DTrace library */
+ processorid_t dtdda_cpu; /* CPU, if any */
+ dtrace_dropkind_t dtdda_kind; /* kind of drop */
+ uint64_t dtdda_drops; /* number of drops */
+ uint64_t dtdda_total; /* total drops */
+ const char *dtdda_msg; /* preconstructed message */
+} dtrace_dropdata_t;
+
+typedef int dtrace_handle_drop_f(const dtrace_dropdata_t *, void *);
+extern int dtrace_handle_drop(dtrace_hdl_t *, dtrace_handle_drop_f *, void *);
+
+typedef void dtrace_handle_proc_f(struct ps_prochandle *, const char *, void *);
+extern int dtrace_handle_proc(dtrace_hdl_t *, dtrace_handle_proc_f *, void *);
+
+#define DTRACE_BUFDATA_AGGKEY 0x0001 /* aggregation key */
+#define DTRACE_BUFDATA_AGGVAL 0x0002 /* aggregation value */
+#define DTRACE_BUFDATA_AGGFORMAT 0x0004 /* aggregation format data */
+#define DTRACE_BUFDATA_AGGLAST 0x0008 /* last for this key/val */
+
+typedef struct dtrace_bufdata {
+ dtrace_hdl_t *dtbda_handle; /* handle to DTrace library */
+ const char *dtbda_buffered; /* buffered output */
+ dtrace_probedata_t *dtbda_probe; /* probe data */
+ const dtrace_recdesc_t *dtbda_recdesc; /* record description */
+ const dtrace_aggdata_t *dtbda_aggdata; /* aggregation data, if agg. */
+ uint32_t dtbda_flags; /* flags; see above */
+} dtrace_bufdata_t;
+
+typedef int dtrace_handle_buffered_f(const dtrace_bufdata_t *, void *);
+extern int dtrace_handle_buffered(dtrace_hdl_t *,
+ dtrace_handle_buffered_f *, void *);
+
+typedef struct dtrace_setoptdata {
+ dtrace_hdl_t *dtsda_handle; /* handle to DTrace library */
+ const dtrace_probedata_t *dtsda_probe; /* probe data */
+ const char *dtsda_option; /* option that was set */
+ dtrace_optval_t dtsda_oldval; /* old value */
+ dtrace_optval_t dtsda_newval; /* new value */
+} dtrace_setoptdata_t;
+
+typedef int dtrace_handle_setopt_f(const dtrace_setoptdata_t *, void *);
+extern int dtrace_handle_setopt(dtrace_hdl_t *,
+ dtrace_handle_setopt_f *, void *);
+
+/*
+ * DTrace Aggregate Interface
+ */
+
+#define DTRACE_A_PERCPU 0x0001
+#define DTRACE_A_KEEPDELTA 0x0002
+#define DTRACE_A_ANONYMOUS 0x0004
+#define DTRACE_A_TOTAL 0x0008
+#define DTRACE_A_MINMAXBIN 0x0010
+#define DTRACE_A_HASNEGATIVES 0x0020
+#define DTRACE_A_HASPOSITIVES 0x0040
+
+#define DTRACE_AGGZOOM_MAX 0.95 /* height of max bar */
+
+#define DTRACE_AGGWALK_ERROR -1 /* error while processing */
+#define DTRACE_AGGWALK_NEXT 0 /* proceed to next element */
+#define DTRACE_AGGWALK_ABORT 1 /* abort aggregation walk */
+#define DTRACE_AGGWALK_CLEAR 2 /* clear this element */
+#define DTRACE_AGGWALK_NORMALIZE 3 /* normalize this element */
+#define DTRACE_AGGWALK_DENORMALIZE 4 /* denormalize this element */
+#define DTRACE_AGGWALK_REMOVE 5 /* remove this element */
+
+struct dtrace_aggdata {
+ dtrace_hdl_t *dtada_handle; /* handle to DTrace library */
+ dtrace_aggdesc_t *dtada_desc; /* aggregation description */
+ dtrace_eprobedesc_t *dtada_edesc; /* enabled probe description */
+ dtrace_probedesc_t *dtada_pdesc; /* probe description */
+ caddr_t dtada_data; /* pointer to raw data */
+ uint64_t dtada_normal; /* the normal -- 1 for denorm */
+ size_t dtada_size; /* total size of the data */
+ caddr_t dtada_delta; /* delta data, if available */
+ caddr_t *dtada_percpu; /* per CPU data, if avail */
+ caddr_t *dtada_percpu_delta; /* per CPU delta, if avail */
+ int64_t dtada_total; /* per agg total, if avail */
+ uint16_t dtada_minbin; /* minimum bin, if avail */
+ uint16_t dtada_maxbin; /* maximum bin, if avail */
+ uint32_t dtada_flags; /* flags */
+};
+
+typedef int dtrace_aggregate_f(const dtrace_aggdata_t *, void *);
+typedef int dtrace_aggregate_walk_f(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+typedef int dtrace_aggregate_walk_joined_f(const dtrace_aggdata_t **,
+ const int, void *);
+
+extern void dtrace_aggregate_clear(dtrace_hdl_t *);
+extern int dtrace_aggregate_snap(dtrace_hdl_t *);
+extern int dtrace_aggregate_print(dtrace_hdl_t *, FILE *,
+ dtrace_aggregate_walk_f *);
+
+extern int dtrace_aggregate_walk(dtrace_hdl_t *, dtrace_aggregate_f *, void *);
+
+extern int dtrace_aggregate_walk_joined(dtrace_hdl_t *,
+ dtrace_aggvarid_t *, int, dtrace_aggregate_walk_joined_f *, void *);
+
+extern int dtrace_aggregate_walk_sorted(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+
+extern int dtrace_aggregate_walk_keysorted(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+
+extern int dtrace_aggregate_walk_valsorted(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+
+extern int dtrace_aggregate_walk_keyvarsorted(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+
+extern int dtrace_aggregate_walk_valvarsorted(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+
+extern int dtrace_aggregate_walk_keyrevsorted(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+
+extern int dtrace_aggregate_walk_valrevsorted(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+
+extern int dtrace_aggregate_walk_keyvarrevsorted(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+
+extern int dtrace_aggregate_walk_valvarrevsorted(dtrace_hdl_t *,
+ dtrace_aggregate_f *, void *);
+
+#define DTRACE_AGD_PRINTED 0x1 /* aggregation printed in program */
+
+/*
+ * DTrace Process Control Interface
+ *
+ * Library clients who wish to have libdtrace create or grab processes for
+ * monitoring of their symbol table changes may use these interfaces to
+ * request that libdtrace obtain control of the process using libproc.
+ */
+
+extern struct ps_prochandle *dtrace_proc_create(dtrace_hdl_t *,
+ const char *, char *const *, proc_child_func *, void *);
+
+extern struct ps_prochandle *dtrace_proc_grab(dtrace_hdl_t *, pid_t, int);
+extern void dtrace_proc_release(dtrace_hdl_t *, struct ps_prochandle *);
+extern void dtrace_proc_continue(dtrace_hdl_t *, struct ps_prochandle *);
+
+/*
+ * DTrace Object, Symbol, and Type Interfaces
+ *
+ * Library clients can use libdtrace to perform symbol and C type information
+ * lookups by symbol name, symbol address, or C type name, or to lookup meta-
+ * information cached for each of the program objects in use by DTrace. The
+ * resulting struct contain pointers to arbitrary-length strings, including
+ * object, symbol, and type names, that are persistent until the next call to
+ * dtrace_update(). Once dtrace_update() is called, any cached values must
+ * be flushed and not used subsequently by the client program.
+ */
+
+#define DTRACE_OBJ_EXEC ((const char *)0L) /* primary executable file */
+#define DTRACE_OBJ_RTLD ((const char *)1L) /* run-time link-editor */
+#define DTRACE_OBJ_CDEFS ((const char *)2L) /* C include definitions */
+#define DTRACE_OBJ_DDEFS ((const char *)3L) /* D program definitions */
+#define DTRACE_OBJ_EVERY ((const char *)-1L) /* all known objects */
+#define DTRACE_OBJ_KMODS ((const char *)-2L) /* all kernel objects */
+#define DTRACE_OBJ_UMODS ((const char *)-3L) /* all user objects */
+
+typedef struct dtrace_objinfo {
+ const char *dto_name; /* object file scope name */
+ const char *dto_file; /* object file path (if any) */
+ int dto_id; /* object file id (if any) */
+ uint_t dto_flags; /* object flags (see below) */
+ GElf_Addr dto_text_va; /* address of text section */
+ GElf_Xword dto_text_size; /* size of text section */
+ GElf_Addr dto_data_va; /* address of data section */
+ GElf_Xword dto_data_size; /* size of data section */
+ GElf_Addr dto_bss_va; /* address of BSS */
+ GElf_Xword dto_bss_size; /* size of BSS */
+} dtrace_objinfo_t;
+
+#define DTRACE_OBJ_F_KERNEL 0x1 /* object is a kernel module */
+#define DTRACE_OBJ_F_PRIMARY 0x2 /* object is a primary module */
+
+typedef int dtrace_obj_f(dtrace_hdl_t *, const dtrace_objinfo_t *, void *);
+
+extern int dtrace_object_iter(dtrace_hdl_t *, dtrace_obj_f *, void *);
+extern int dtrace_object_info(dtrace_hdl_t *, const char *, dtrace_objinfo_t *);
+
+typedef struct dtrace_syminfo {
+ const char *dts_object; /* object name */
+ const char *dts_name; /* symbol name */
+ ulong_t dts_id; /* symbol id */
+} dtrace_syminfo_t;
+
+extern int dtrace_lookup_by_name(dtrace_hdl_t *, const char *, const char *,
+ GElf_Sym *, dtrace_syminfo_t *);
+
+extern int dtrace_lookup_by_addr(dtrace_hdl_t *, GElf_Addr addr,
+ GElf_Sym *, dtrace_syminfo_t *);
+
+typedef struct dtrace_typeinfo {
+ const char *dtt_object; /* object containing type */
+ ctf_file_t *dtt_ctfp; /* CTF container handle */
+ ctf_id_t dtt_type; /* CTF type identifier */
+ uint_t dtt_flags; /* Misc. flags */
+} dtrace_typeinfo_t;
+
+#define DTT_FL_USER 0x1 /* user type */
+
+extern int dtrace_lookup_by_type(dtrace_hdl_t *, const char *, const char *,
+ dtrace_typeinfo_t *);
+
+extern int dtrace_symbol_type(dtrace_hdl_t *, const GElf_Sym *,
+ const dtrace_syminfo_t *, dtrace_typeinfo_t *);
+
+extern int dtrace_type_strcompile(dtrace_hdl_t *,
+ const char *, dtrace_typeinfo_t *);
+
+extern int dtrace_type_fcompile(dtrace_hdl_t *,
+ FILE *, dtrace_typeinfo_t *);
+
+extern struct dt_node *dt_compile_sugar(dtrace_hdl_t *,
+ struct dt_node *);
+
+
+/*
+ * DTrace Probe Interface
+ *
+ * Library clients can use these functions to iterate over the set of available
+ * probe definitions and inquire as to their attributes. The probe iteration
+ * interfaces report probes that are declared as well as those from dtrace(7D).
+ */
+typedef struct dtrace_probeinfo {
+ dtrace_attribute_t dtp_attr; /* name attributes */
+ dtrace_attribute_t dtp_arga; /* arg attributes */
+ const dtrace_typeinfo_t *dtp_argv; /* arg types */
+ int dtp_argc; /* arg count */
+} dtrace_probeinfo_t;
+
+typedef int dtrace_probe_f(dtrace_hdl_t *, const dtrace_probedesc_t *, void *);
+
+extern int dtrace_probe_iter(dtrace_hdl_t *,
+ const dtrace_probedesc_t *pdp, dtrace_probe_f *, void *);
+
+extern int dtrace_probe_info(dtrace_hdl_t *,
+ const dtrace_probedesc_t *, dtrace_probeinfo_t *);
+
+/*
+ * DTrace Vector Interface
+ *
+ * The DTrace library normally speaks directly to dtrace(7D). However,
+ * this communication may be vectored elsewhere. Consumers who wish to
+ * perform a vectored open must fill in the vector, and use the dtrace_vopen()
+ * entry point to obtain a library handle.
+ */
+struct dtrace_vector {
+#ifdef illumos
+ int (*dtv_ioctl)(void *, int, void *);
+#else
+ int (*dtv_ioctl)(void *, u_long, void *);
+#endif
+ int (*dtv_lookup_by_addr)(void *, GElf_Addr, GElf_Sym *,
+ dtrace_syminfo_t *);
+ int (*dtv_status)(void *, processorid_t);
+ long (*dtv_sysconf)(void *, int);
+};
+
+/*
+ * DTrace Utility Functions
+ *
+ * Library clients can use these functions to convert addresses strings, to
+ * convert between string and integer probe descriptions and the
+ * dtrace_probedesc_t representation, and to perform similar conversions on
+ * stability attributes.
+ */
+extern int dtrace_addr2str(dtrace_hdl_t *, uint64_t, char *, int);
+extern int dtrace_uaddr2str(dtrace_hdl_t *, pid_t, uint64_t, char *, int);
+
+extern int dtrace_xstr2desc(dtrace_hdl_t *, dtrace_probespec_t,
+ const char *, int, char *const [], dtrace_probedesc_t *);
+
+extern int dtrace_str2desc(dtrace_hdl_t *, dtrace_probespec_t,
+ const char *, dtrace_probedesc_t *);
+
+extern int dtrace_id2desc(dtrace_hdl_t *, dtrace_id_t, dtrace_probedesc_t *);
+
+#define DTRACE_DESC2STR_MAX 1024 /* min buf size for dtrace_desc2str() */
+
+extern char *dtrace_desc2str(const dtrace_probedesc_t *, char *, size_t);
+
+#define DTRACE_ATTR2STR_MAX 64 /* min buf size for dtrace_attr2str() */
+
+extern char *dtrace_attr2str(dtrace_attribute_t, char *, size_t);
+extern int dtrace_str2attr(const char *, dtrace_attribute_t *);
+
+extern const char *dtrace_stability_name(dtrace_stability_t);
+extern const char *dtrace_class_name(dtrace_class_t);
+
+extern int dtrace_provider_modules(dtrace_hdl_t *, const char **, int);
+
+extern const char *const _dtrace_version;
+extern int _dtrace_debug;
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef illumos
+#define _SC_CPUID_MAX _SC_NPROCESSORS_CONF
+#define _SC_NPROCESSORS_MAX _SC_NPROCESSORS_CONF
+#endif
+
+#endif /* _DTRACE_H */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/mkerrno.sh b/cddl/contrib/opensolaris/lib/libdtrace/common/mkerrno.sh
new file mode 100755
index 000000000000..50b7f1c1b908
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/mkerrno.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# 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.
+#
+# 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 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+echo "\
+/*\n\
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.\n\
+ * Use is subject to license terms.\n\
+ */\n\
+\n\
+#pragma ident\t\"%Z%%M%\t%I%\t%E% SMI\"\n"
+
+pattern='^#define[ ]\(E[A-Z0-9]*\)[ ]*\([A-Z0-9]*\).*$'
+replace='inline int \1 = \2;@#pragma D binding "1.0" \1'
+
+sed -n "s/$pattern/$replace/p" | tr '@' '\n'
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/mkerrtags.sh b/cddl/contrib/opensolaris/lib/libdtrace/common/mkerrtags.sh
new file mode 100644
index 000000000000..d5651ff727fc
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/mkerrtags.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# 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.
+#
+# 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 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+BSDECHO=-e
+
+echo ${BSDECHO} "\
+/*\n\
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.\n\
+ * Use is subject to license terms.\n\
+ */\n\
+\n\
+#pragma ident\t\"%Z%%M%\t%I%\t%E% SMI\"\n\
+\n\
+#include <dt_errtags.h>
+\n\
+static const char *const _dt_errtags[] = {"
+
+pattern='^ \(D_[A-Z0-9_]*\),*'
+replace=' "\1",'
+
+sed -n "s/$pattern/$replace/p" || exit 1
+
+echo ${BSDECHO} "\
+};\n\
+\n\
+static const int _dt_ntag = sizeof (_dt_errtags) / sizeof (_dt_errtags[0]);\n\
+\n\
+const char *
+dt_errtag(dt_errtag_t tag)
+{
+ return (_dt_errtags[(tag > 0 && tag < _dt_ntag) ? tag : 0]);
+}"
+
+exit 0
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/mknames.sh b/cddl/contrib/opensolaris/lib/libdtrace/common/mknames.sh
new file mode 100644
index 000000000000..2fdc2fa636d5
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/mknames.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# 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.
+#
+# 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 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+BSDECHO=-e
+
+echo ${BSDECHO} "\
+/*\n\
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.\n\
+ * Use is subject to license terms.\n\
+ */\n\
+\n\
+#pragma ident\t\"%Z%%M%\t%I%\t%E% SMI\"\n\
+\n\
+#include <dtrace.h>\n\
+\n\
+/*ARGSUSED*/
+const char *\n\
+dtrace_subrstr(dtrace_hdl_t *dtp, int subr)\n\
+{\n\
+ switch (subr) {"
+
+nawk '
+/^#define[ ]*DIF_SUBR_/ && $2 != "DIF_SUBR_MAX" {
+ printf("\tcase %s: return (\"%s\");\n", $2, tolower(substr($2, 10)));
+}'
+
+echo ${BSDECHO} "\
+ default: return (\"unknown\");\n\
+ }\n\
+}"
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/mksignal.sh b/cddl/contrib/opensolaris/lib/libdtrace/common/mksignal.sh
new file mode 100755
index 000000000000..1bffa6468c2b
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/mksignal.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# 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.
+#
+# 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 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+echo "\
+/*\n\
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.\n\
+ * Use is subject to license terms.\n\
+ */\n\
+\n\
+#pragma ident\t\"%Z%%M%\t%I%\t%E% SMI\"\n"
+
+pattern='^#define[ ]*_*\(SIG[A-Z0-9]*\)[ ]\{1,\}\([A-Z0-9]*\).*$'
+replace='inline int \1 = \2;@#pragma D binding "1.0" \1'
+
+sed -n "s/$pattern/$replace/p;/SIGRTMAX/q" | tr '@' '\n'
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/i386/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/i386/dt_isadep.c
new file mode 100644
index 000000000000..5d8d034fe216
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/i386/dt_isadep.c
@@ -0,0 +1,520 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+#include <dis_tables.h>
+
+#ifdef __FreeBSD__
+#include <libproc.h>
+#include <libproc_compat.h>
+#endif
+
+#define DT_POPL_EBP 0x5d
+#define DT_RET 0xc3
+#define DT_RET16 0xc2
+#define DT_LEAVE 0xc9
+#define DT_JMP32 0xe9
+#define DT_JMP8 0xeb
+#define DT_REP 0xf3
+
+#define DT_MOVL_EBP_ESP 0xe58b
+
+#define DT_ISJ32(op16) (((op16) & 0xfff0) == 0x0f80)
+#define DT_ISJ8(op8) (((op8) & 0xf0) == 0x70)
+
+#define DT_MODRM_REG(modrm) (((modrm) >> 3) & 0x7)
+
+static int dt_instr_size(uchar_t *, dtrace_hdl_t *, pid_t, uintptr_t, char);
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+ ftp->ftps_type = DTFTP_ENTRY;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = 0;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+static int
+dt_pid_has_jump_table(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ uint8_t *text, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+ ulong_t i;
+ int size;
+#ifdef illumos
+ pid_t pid = Pstatus(P)->pr_pid;
+ char dmodel = Pstatus(P)->pr_dmodel;
+#else
+ pid_t pid = proc_getpid(P);
+ char dmodel = proc_getmodel(P);
+#endif
+
+ /*
+ * Take a pass through the function looking for a register-dependant
+ * jmp instruction. This could be a jump table so we have to be
+ * ultra conservative.
+ */
+ for (i = 0; i < ftp->ftps_size; i += size) {
+ size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i,
+ dmodel);
+
+ /*
+ * Assume the worst if we hit an illegal instruction.
+ */
+ if (size <= 0) {
+ dt_dprintf("error at %#lx (assuming jump table)\n", i);
+ return (1);
+ }
+
+#ifdef notyet
+ /*
+ * Register-dependant jmp instructions start with a 0xff byte
+ * and have the modrm.reg field set to 4. They can have an
+ * optional REX prefix on the 64-bit ISA.
+ */
+ if ((text[i] == 0xff && DT_MODRM_REG(text[i + 1]) == 4) ||
+ (dmodel == PR_MODEL_LP64 && (text[i] & 0xf0) == 0x40 &&
+ text[i + 1] == 0xff && DT_MODRM_REG(text[i + 2]) == 4)) {
+ dt_dprintf("found a suspected jump table at %s:%lx\n",
+ ftp->ftps_func, i);
+ return (1);
+ }
+#endif
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+ uint8_t *text;
+ ulong_t i, end;
+ int size;
+#ifdef illumos
+ pid_t pid = Pstatus(P)->pr_pid;
+ char dmodel = Pstatus(P)->pr_dmodel;
+#else
+ pid_t pid = proc_getpid(P);
+ char dmodel = proc_getmodel(P);
+#endif
+
+ /*
+ * We allocate a few extra bytes at the end so we don't have to check
+ * for overrunning the buffer.
+ */
+ if ((text = calloc(1, symp->st_size + 4)) == NULL) {
+ dt_dprintf("mr sparkle: malloc() failed\n");
+ return (DT_PROC_ERR);
+ }
+
+ if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
+ dt_dprintf("mr sparkle: Pread() failed\n");
+ free(text);
+ return (DT_PROC_ERR);
+ }
+
+ ftp->ftps_type = DTFTP_RETURN;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ /*
+ * If there's a jump table in the function we're only willing to
+ * instrument these specific (and equivalent) instruction sequences:
+ * leave
+ * [rep] ret
+ * and
+ * movl %ebp,%esp
+ * popl %ebp
+ * [rep] ret
+ *
+ * We do this to avoid accidentally interpreting jump table
+ * offsets as actual instructions.
+ */
+ if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
+ for (i = 0, end = ftp->ftps_size; i < end; i += size) {
+ size = dt_instr_size(&text[i], dtp, pid,
+ symp->st_value + i, dmodel);
+
+ /* bail if we hit an invalid opcode */
+ if (size <= 0)
+ break;
+
+ if (text[i] == DT_LEAVE && text[i + 1] == DT_RET) {
+ dt_dprintf("leave/ret at %lx\n", i + 1);
+ ftp->ftps_offs[ftp->ftps_noffs++] = i + 1;
+ size = 2;
+ } else if (text[i] == DT_LEAVE &&
+ text[i + 1] == DT_REP && text[i + 2] == DT_RET) {
+ dt_dprintf("leave/rep ret at %lx\n", i + 1);
+ ftp->ftps_offs[ftp->ftps_noffs++] = i + 1;
+ size = 3;
+ } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP &&
+ text[i + 2] == DT_POPL_EBP &&
+ text[i + 3] == DT_RET) {
+ dt_dprintf("movl/popl/ret at %lx\n", i + 3);
+ ftp->ftps_offs[ftp->ftps_noffs++] = i + 3;
+ size = 4;
+ } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP &&
+ text[i + 2] == DT_POPL_EBP &&
+ text[i + 3] == DT_REP &&
+ text[i + 4] == DT_RET) {
+ dt_dprintf("movl/popl/rep ret at %lx\n", i + 3);
+ ftp->ftps_offs[ftp->ftps_noffs++] = i + 3;
+ size = 5;
+ }
+ }
+ } else {
+ for (i = 0, end = ftp->ftps_size; i < end; i += size) {
+ size = dt_instr_size(&text[i], dtp, pid,
+ symp->st_value + i, dmodel);
+
+ /* bail if we hit an invalid opcode */
+ if (size <= 0)
+ break;
+
+ /* ordinary ret */
+ if (size == 1 && text[i] == DT_RET)
+ goto is_ret;
+
+ /* two-byte ret */
+ if (size == 2 && text[i] == DT_REP &&
+ text[i + 1] == DT_RET)
+ goto is_ret;
+
+ /* ret <imm16> */
+ if (size == 3 && text[i] == DT_RET16)
+ goto is_ret;
+
+ /* two-byte ret <imm16> */
+ if (size == 4 && text[i] == DT_REP &&
+ text[i + 1] == DT_RET16)
+ goto is_ret;
+
+ /* 32-bit displacement jmp outside of the function */
+ if (size == 5 && text[i] == DT_JMP32 && symp->st_size <=
+ (uintptr_t)(i + size + *(int32_t *)&text[i + 1]))
+ goto is_ret;
+
+ /* 8-bit displacement jmp outside of the function */
+ if (size == 2 && text[i] == DT_JMP8 && symp->st_size <=
+ (uintptr_t)(i + size + *(int8_t *)&text[i + 1]))
+ goto is_ret;
+
+ /* 32-bit disp. conditional jmp outside of the func. */
+ if (size == 6 && DT_ISJ32(*(uint16_t *)&text[i]) &&
+ symp->st_size <=
+ (uintptr_t)(i + size + *(int32_t *)&text[i + 2]))
+ goto is_ret;
+
+ /* 8-bit disp. conditional jmp outside of the func. */
+ if (size == 2 && DT_ISJ8(text[i]) && symp->st_size <=
+ (uintptr_t)(i + size + *(int8_t *)&text[i + 1]))
+ goto is_ret;
+
+ continue;
+is_ret:
+ dt_dprintf("return at offset %lx\n", i);
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ }
+
+ free(text);
+ if (ftp->ftps_noffs > 0) {
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+ }
+
+ return (ftp->ftps_noffs);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+
+ if (strcmp("-", ftp->ftps_func) == 0) {
+ ftp->ftps_offs[0] = off;
+ } else {
+ uint8_t *text;
+ ulong_t i;
+ int size;
+#ifdef illumos
+ pid_t pid = Pstatus(P)->pr_pid;
+ char dmodel = Pstatus(P)->pr_dmodel;
+#else
+ pid_t pid = proc_getpid(P);
+ char dmodel = proc_getmodel(P);
+#endif
+
+ if ((text = malloc(symp->st_size)) == NULL) {
+ dt_dprintf("mr sparkle: malloc() failed\n");
+ return (DT_PROC_ERR);
+ }
+
+ if (Pread(P, text, symp->st_size, symp->st_value) !=
+ symp->st_size) {
+ dt_dprintf("mr sparkle: Pread() failed\n");
+ free(text);
+ return (DT_PROC_ERR);
+ }
+
+ /*
+ * We can't instrument offsets in functions with jump tables
+ * as we might interpret a jump table offset as an
+ * instruction.
+ */
+ if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
+ free(text);
+ return (0);
+ }
+
+ for (i = 0; i < symp->st_size; i += size) {
+ if (i == off) {
+ ftp->ftps_offs[0] = i;
+ break;
+ }
+
+ /*
+ * If we've passed the desired offset without a
+ * match, then the given offset must not lie on a
+ * instruction boundary.
+ */
+ if (i > off) {
+ free(text);
+ return (DT_PROC_ALIGN);
+ }
+
+ size = dt_instr_size(&text[i], dtp, pid,
+ symp->st_value + i, dmodel);
+
+ /*
+ * If we hit an invalid instruction, bail as if we
+ * couldn't find the offset.
+ */
+ if (size <= 0) {
+ free(text);
+ return (DT_PROC_ALIGN);
+ }
+ }
+
+ free(text);
+ }
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (ftp->ftps_noffs);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+ uint8_t *text;
+ int size;
+ ulong_t i, end = symp->st_size;
+#ifdef illumos
+ pid_t pid = Pstatus(P)->pr_pid;
+ char dmodel = Pstatus(P)->pr_dmodel;
+#else
+ pid_t pid = proc_getpid(P);
+ char dmodel = proc_getmodel(P);
+#endif
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ if ((text = malloc(symp->st_size)) == NULL) {
+ dt_dprintf("mr sparkle: malloc() failed\n");
+ return (DT_PROC_ERR);
+ }
+
+ if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
+ dt_dprintf("mr sparkle: Pread() failed\n");
+ free(text);
+ return (DT_PROC_ERR);
+ }
+
+ /*
+ * We can't instrument offsets in functions with jump tables as
+ * we might interpret a jump table offset as an instruction.
+ */
+ if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
+ free(text);
+ return (0);
+ }
+
+ if (strcmp("*", pattern) == 0) {
+ for (i = 0; i < end; i += size) {
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+
+ size = dt_instr_size(&text[i], dtp, pid,
+ symp->st_value + i, dmodel);
+
+ /* bail if we hit an invalid opcode */
+ if (size <= 0)
+ break;
+ }
+ } else {
+ char name[sizeof (i) * 2 + 1];
+
+ for (i = 0; i < end; i += size) {
+ (void) snprintf(name, sizeof (name), "%lx", i);
+ if (gmatch(name, pattern))
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+
+ size = dt_instr_size(&text[i], dtp, pid,
+ symp->st_value + i, dmodel);
+
+ /* bail if we hit an invalid opcode */
+ if (size <= 0)
+ break;
+ }
+ }
+
+ free(text);
+ if (ftp->ftps_noffs > 0) {
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+ }
+
+ return (ftp->ftps_noffs);
+}
+
+typedef struct dtrace_dis {
+ uchar_t *instr;
+ dtrace_hdl_t *dtp;
+ pid_t pid;
+ uintptr_t addr;
+} dtrace_dis_t;
+
+static int
+dt_getbyte(void *data)
+{
+ dtrace_dis_t *dis = data;
+ int ret = *dis->instr;
+
+ if (ret == FASTTRAP_INSTR) {
+ fasttrap_instr_query_t instr;
+
+ instr.ftiq_pid = dis->pid;
+ instr.ftiq_pc = dis->addr;
+
+ /*
+ * If we hit a byte that looks like the fasttrap provider's
+ * trap instruction (which doubles as the breakpoint
+ * instruction for debuggers) we need to query the kernel
+ * for the real value. This may just be part of an immediate
+ * value so there's no need to return an error if the
+ * kernel doesn't know about this address.
+ */
+ if (ioctl(dis->dtp->dt_ftfd, FASTTRAPIOC_GETINSTR, &instr) == 0)
+ ret = instr.ftiq_instr;
+ }
+
+ dis->addr++;
+ dis->instr++;
+
+ return (ret);
+}
+
+static int
+dt_instr_size(uchar_t *instr, dtrace_hdl_t *dtp, pid_t pid, uintptr_t addr,
+ char dmodel)
+{
+ dtrace_dis_t data;
+ dis86_t x86dis;
+ uint_t cpu_mode;
+
+ data.instr = instr;
+ data.dtp = dtp;
+ data.pid = pid;
+ data.addr = addr;
+
+ x86dis.d86_data = &data;
+ x86dis.d86_get_byte = dt_getbyte;
+ x86dis.d86_check_func = NULL;
+
+ cpu_mode = (dmodel == PR_MODEL_ILP32) ? SIZE32 : SIZE64;
+
+ if (dtrace_disx86(&x86dis, cpu_mode) != 0)
+ return (-1);
+
+ /*
+ * If the instruction was a single-byte breakpoint, there may be
+ * another debugger attached to this process. The original instruction
+ * can't be recovered so this must fail.
+ */
+ if (x86dis.d86_len == 1 &&
+ (uchar_t)x86dis.d86_bytes[0] == FASTTRAP_INSTR)
+ return (-1);
+
+ return (x86dis.d86_len);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/i386/regs.d.in b/cddl/contrib/opensolaris/lib/libdtrace/i386/regs.d.in
new file mode 100644
index 000000000000..3328f33515b0
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/i386/regs.d.in
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+inline int R_GS = @GS@;
+#pragma D binding "1.0" R_GS
+inline int R_FS = @FS@;
+#pragma D binding "1.0" R_FS
+inline int R_ES = @ES@;
+#pragma D binding "1.0" R_ES
+inline int R_DS = @DS@;
+#pragma D binding "1.0" R_DS
+
+inline int R_EDI = @EDI@;
+#pragma D binding "1.0" R_EDI
+inline int R_ESI = @ESI@;
+#pragma D binding "1.0" R_ESI
+inline int R_EBP = @EBP@;
+#pragma D binding "1.0" R_EBP
+inline int R_ESP = @ESP@;
+#pragma D binding "1.0" R_ESP
+inline int R_EBX = @EBX@;
+#pragma D binding "1.0" R_EBX
+inline int R_EDX = @EDX@;
+#pragma D binding "1.0" R_EDX
+inline int R_ECX = @ECX@;
+#pragma D binding "1.0" R_ECX
+inline int R_EAX = @EAX@;
+#pragma D binding "1.0" R_EAX
+
+inline int R_TRAPNO = @TRAPNO@;
+#pragma D binding "1.0" R_TRAPNO
+inline int R_ERR = @ERR@;
+#pragma D binding "1.0" R_ERR
+inline int R_EIP = @EIP@;
+#pragma D binding "1.0" R_EIP
+inline int R_CS = @CS@;
+#pragma D binding "1.0" R_CS
+inline int R_EFL = @EFL@;
+#pragma D binding "1.0" R_EFL
+inline int R_UESP = @UESP@;
+#pragma D binding "1.0" R_UESP
+inline int R_SS = @SS@;
+#pragma D binding "1.0" R_SS
+
+inline int R_PC = R_EIP;
+#pragma D binding "1.0" R_PC
+inline int R_SP = R_UESP;
+#pragma D binding "1.0" R_SP
+inline int R_PS = R_EFL;
+#pragma D binding "1.0" R_PS
+inline int R_R0 = R_EAX;
+#pragma D binding "1.0" R_R0
+inline int R_R1 = R_EBX;
+#pragma D binding "1.0" R_R1
+
+inline int R_RSP = @REG_RSP@;
+#pragma D binding "1.0" R_RSP
+inline int R_RFL = @REG_RFL@;
+#pragma D binding "1.0" R_RFL
+inline int R_RIP = @REG_RIP@;
+#pragma D binding "1.0" R_RIP
+inline int R_RAX = @REG_RAX@;
+#pragma D binding "1.0" R_RAX
+inline int R_RCX = @REG_RCX@;
+#pragma D binding "1.0" R_RCX
+inline int R_RDX = @REG_RDX@;
+#pragma D binding "1.0" R_RDX
+inline int R_RBX = @REG_RBX@;
+#pragma D binding "1.0" R_RBX
+inline int R_RBP = @REG_RBP@;
+#pragma D binding "1.0" R_RBP
+inline int R_RSI = @REG_RSI@;
+#pragma D binding "1.0" R_RSI
+inline int R_RDI = @REG_RDI@;
+#pragma D binding "1.0" R_RDI
+inline int R_R8 = @REG_R8@;
+#pragma D binding "1.0" R_R8
+inline int R_R9 = @REG_R9@;
+#pragma D binding "1.0" R_R9
+inline int R_R10 = @REG_R10@;
+#pragma D binding "1.0" R_R10
+inline int R_R11 = @REG_R11@;
+#pragma D binding "1.0" R_R11
+inline int R_R12 = @REG_R12@;
+#pragma D binding "1.0" R_R12
+inline int R_R13 = @REG_R13@;
+#pragma D binding "1.0" R_R13
+inline int R_R14 = @REG_R14@;
+#pragma D binding "1.0" R_R14
+inline int R_R15 = @REG_R15@;
+#pragma D binding "1.0" R_R15
+
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/i386/regs.sed.in b/cddl/contrib/opensolaris/lib/libdtrace/i386/regs.sed.in
new file mode 100644
index 000000000000..2b2080fc9d03
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/i386/regs.sed.in
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file is a sed script which is first preprocessed by cpp or cc -E to
+ * define a set of sed directives which replace #define tokens with their
+ * values. After preprocessing, whitespace is eliminated, and any @ symbols
+ * are translated into single space. The resulting sed script is then run
+ * over regs.d.in to replace the #define tokens listed below to create the
+ * finished regs.d. Refer to the rules in libdtrace/i386/Makefile for more
+ * information.
+ */
+
+#include <sys/regset.h>
+
+#define SED_REPLACE(x) s/#x/x/g
+#define SED_REPLACE64(x) s/#x/SS @+@1@+@ x/g
+
+SED_REPLACE(GS)
+SED_REPLACE(FS)
+SED_REPLACE(ES)
+SED_REPLACE(DS)
+SED_REPLACE(EDI)
+SED_REPLACE(ESI)
+SED_REPLACE(EBP)
+SED_REPLACE(ESP)
+SED_REPLACE(EBX)
+SED_REPLACE(EDX)
+SED_REPLACE(ECX)
+SED_REPLACE(EAX)
+SED_REPLACE(TRAPNO)
+SED_REPLACE(ERR)
+SED_REPLACE(EIP)
+SED_REPLACE(CS)
+SED_REPLACE(EFL)
+SED_REPLACE(UESP)
+SED_REPLACE(SS)
+
+SED_REPLACE64(REG_RSP)
+SED_REPLACE64(REG_RFL)
+SED_REPLACE64(REG_RIP)
+SED_REPLACE64(REG_RAX)
+SED_REPLACE64(REG_RCX)
+SED_REPLACE64(REG_RDX)
+SED_REPLACE64(REG_RBX)
+SED_REPLACE64(REG_RBP)
+SED_REPLACE64(REG_RSI)
+SED_REPLACE64(REG_RDI)
+SED_REPLACE64(REG_R8)
+SED_REPLACE64(REG_R9)
+SED_REPLACE64(REG_R10)
+SED_REPLACE64(REG_R11)
+SED_REPLACE64(REG_R12)
+SED_REPLACE64(REG_R13)
+SED_REPLACE64(REG_R14)
+SED_REPLACE64(REG_R15)
+
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/mips/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/mips/dt_isadep.c
new file mode 100644
index 000000000000..1aeb95f3dfd7
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/mips/dt_isadep.c
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+
+ dt_dprintf("%s: unimplemented\n", __func__);
+ return (DT_PROC_ERR);
+}
+
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+
+ dt_dprintf("%s: unimplemented\n", __func__);
+ return (DT_PROC_ERR);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+
+ dt_dprintf("%s: unimplemented\n", __func__);
+ return (DT_PROC_ERR);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+
+ dt_dprintf("%s: unimplemented\n", __func__);
+ return (DT_PROC_ERR);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
new file mode 100644
index 000000000000..f4b02c9fe381
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+#include <libproc_compat.h>
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+ ftp->ftps_type = DTFTP_ENTRY;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = 0;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+
+ uintptr_t temp;
+ uint32_t *text;
+ int i;
+ int srdepth = 0;
+
+ if ((text = malloc(symp->st_size + 4)) == NULL) {
+ dt_dprintf("mr sparkle: malloc() failed\n");
+ return (DT_PROC_ERR);
+ }
+
+ if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
+ dt_dprintf("mr sparkle: Pread() failed\n");
+ free(text);
+ return (DT_PROC_ERR);
+ }
+
+ /*
+ * Leave a dummy instruction in the last slot to simplify edge
+ * conditions.
+ */
+ text[symp->st_size / 4] = 0;
+
+ ftp->ftps_type = DTFTP_RETURN;
+ ftp->ftps_pc = symp->st_value;
+ ftp->ftps_size = symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ for (i = 0; i < symp->st_size / 4; i++) {
+
+ if ((text[i] & 0xfc000001) != 0x48000000 &&
+ text[i] != 0x4e800020)
+ continue;
+
+ /*
+ * Check for a jump within this function. If it's outside this
+ * function then it's a tail-call, so a return point.
+ */
+ if ((text[i] & 0xfc000000) == 0x48000000) {
+ temp = (text[i] & 0x03fffffc);
+ /* Bit 30 denotes an absolute address. */
+ if (!(text[i] & 0x02)) {
+ temp += symp->st_value + i * 4;
+ }
+ else {
+ /* Sign extend the absolute address. */
+ if (temp & 0x02000000) {
+ temp |= (UINTPTR_MAX - 0x03ffffff);
+ }
+ }
+ if (temp >= symp->st_value &&
+ temp <= (symp->st_value + symp->st_size))
+ continue;
+ }
+ dt_dprintf("return at offset %x\n", i * 4);
+ ftp->ftps_offs[ftp->ftps_noffs++] = i * 4;
+ }
+
+ free(text);
+ if (ftp->ftps_noffs > 0) {
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+ }
+
+
+ return (ftp->ftps_noffs);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+ if (off & 0x3)
+ return (DT_PROC_ALIGN);
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = off;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+ ulong_t i;
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ /*
+ * If we're matching against everything, just iterate through each
+ * instruction in the function, otherwise look for matching offset
+ * names by constructing the string and comparing it against the
+ * pattern.
+ */
+ if (strcmp("*", pattern) == 0) {
+ for (i = 0; i < symp->st_size; i += 4) {
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ } else {
+ char name[sizeof (i) * 2 + 1];
+
+ for (i = 0; i < symp->st_size; i += 4) {
+ (void) sprintf(name, "%lx", i);
+ if (gmatch(name, pattern))
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ }
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (ftp->ftps_noffs);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/riscv/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/riscv/dt_isadep.c
new file mode 100644
index 000000000000..9f5af8570490
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/riscv/dt_isadep.c
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2014 Howard Su
+ * Copyright 2015 George V. Neville-Neil
+ * Copyright 2015 Ruslan Bukin <br@bsdpad.com>
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+#if !defined(sun)
+#include <libproc_compat.h>
+#endif
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+
+ ftp->ftps_type = DTFTP_ENTRY;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = 0;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+
+ dt_dprintf("%s: unimplemented\n", __func__);
+
+ return (DT_PROC_ERR);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+
+ if (!ALIGNED_POINTER(off, 4))
+ return (DT_PROC_ALIGN);
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = off;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+ ulong_t i;
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ /*
+ * If we're matching against everything, just iterate through each
+ * instruction in the function, otherwise look for matching offset
+ * names by constructing the string and comparing it against the
+ * pattern.
+ */
+ if (strcmp("*", pattern) == 0) {
+ for (i = 0; i < symp->st_size; i += 4) {
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ } else {
+ char name[sizeof (i) * 2 + 1];
+
+ for (i = 0; i < symp->st_size; i += 4) {
+ (void) sprintf(name, "%lx", i);
+ if (gmatch(name, pattern))
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ }
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (ftp->ftps_noffs);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/sparc/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/sparc/dt_isadep.c
new file mode 100644
index 000000000000..ed05275e7f83
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/sparc/dt_isadep.c
@@ -0,0 +1,338 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+#define OP(x) ((x) >> 30)
+#define OP2(x) (((x) >> 22) & 0x07)
+#define COND(x) (((x) >> 25) & 0x0f)
+#define A(x) (((x) >> 29) & 0x01)
+
+#define OP_BRANCH 0
+
+#define OP2_BPcc 0x1
+#define OP2_Bicc 0x2
+#define OP2_BPr 0x3
+#define OP2_FBPfcc 0x5
+#define OP2_FBfcc 0x6
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+ ftp->ftps_type = DTFTP_ENTRY;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = 0;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+
+ uint32_t *text;
+ int i;
+ int srdepth = 0;
+
+ if ((text = malloc(symp->st_size + 4)) == NULL) {
+ dt_dprintf("mr sparkle: malloc() failed\n");
+ return (DT_PROC_ERR);
+ }
+
+ if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
+ dt_dprintf("mr sparkle: Pread() failed\n");
+ free(text);
+ return (DT_PROC_ERR);
+ }
+
+ /*
+ * Leave a dummy instruction in the last slot to simplify edge
+ * conditions.
+ */
+ text[symp->st_size / 4] = 0;
+
+ ftp->ftps_type = DTFTP_RETURN;
+ ftp->ftps_pc = symp->st_value;
+ ftp->ftps_size = symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ for (i = 0; i < symp->st_size / 4; i++) {
+ /*
+ * If we encounter an existing tracepoint, query the
+ * kernel to find out the instruction that was
+ * replaced at this spot.
+ */
+ while (text[i] == FASTTRAP_INSTR) {
+ fasttrap_instr_query_t instr;
+
+ instr.ftiq_pid = Pstatus(P)->pr_pid;
+ instr.ftiq_pc = symp->st_value + i * 4;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_GETINSTR,
+ &instr) != 0) {
+
+ if (errno == ESRCH || errno == ENOENT) {
+ if (Pread(P, &text[i], 4,
+ instr.ftiq_pc) != 4) {
+ dt_dprintf("mr sparkle: "
+ "Pread() failed\n");
+ free(text);
+ return (DT_PROC_ERR);
+ }
+ continue;
+ }
+
+ free(text);
+ dt_dprintf("mr sparkle: getinstr query "
+ "failed: %s\n", strerror(errno));
+ return (DT_PROC_ERR);
+ }
+
+ text[i] = instr.ftiq_instr;
+ break;
+ }
+
+ /* save */
+ if ((text[i] & 0xc1f80000) == 0x81e00000) {
+ srdepth++;
+ continue;
+ }
+
+ /* restore */
+ if ((text[i] & 0xc1f80000) == 0x81e80000) {
+ srdepth--;
+ continue;
+ }
+
+ if (srdepth > 0) {
+ /* ret */
+ if (text[i] == 0x81c7e008)
+ goto is_ret;
+
+ /* return */
+ if (text[i] == 0x81cfe008)
+ goto is_ret;
+
+ /* call or jmpl w/ restore in the slot */
+ if (((text[i] & 0xc0000000) == 0x40000000 ||
+ (text[i] & 0xc1f80000) == 0x81c00000) &&
+ (text[i + 1] & 0xc1f80000) == 0x81e80000)
+ goto is_ret;
+
+ /* call to one of the stret routines */
+ if ((text[i] & 0xc0000000) == 0x40000000) {
+ int32_t disp = text[i] << 2;
+ uint64_t dest = ftp->ftps_pc + i * 4 + disp;
+
+ dt_dprintf("dest = %llx\n", (u_longlong_t)dest);
+
+ if (dest == stret[0] || dest == stret[1] ||
+ dest == stret[2] || dest == stret[3])
+ goto is_ret;
+ }
+ } else {
+ /* external call */
+ if ((text[i] & 0xc0000000) == 0x40000000) {
+ int32_t dst = text[i] << 2;
+
+ dst += i * 4;
+
+ if ((uintptr_t)dst >= (uintptr_t)symp->st_size)
+ goto is_ret;
+ }
+
+ /* jmpl into %g0 -- this includes the retl pseudo op */
+ if ((text[i] & 0xfff80000) == 0x81c00000)
+ goto is_ret;
+
+ /* external branch -- possible return site */
+ if (OP(text[i]) == OP_BRANCH) {
+ int32_t dst;
+ int baa;
+
+ switch (OP2(text[i])) {
+ case OP2_BPcc:
+ dst = text[i] & 0x7ffff;
+ dst <<= 13;
+ dst >>= 11;
+
+ baa = COND(text[i]) == 8 && A(text[i]);
+ break;
+ case OP2_Bicc:
+ dst = text[i] & 0x3fffff;
+ dst <<= 10;
+ dst >>= 8;
+
+ baa = COND(text[i]) == 8 && A(text[i]);
+ break;
+ case OP2_BPr:
+ dst = (((text[i]) >> 6) & 0xc000) |
+ ((text[i]) & 0x3fff);
+ dst <<= 16;
+ dst >>= 14;
+
+ baa = 0;
+ break;
+ case OP2_FBPfcc:
+ dst = text[i] & 0x7ffff;
+ dst <<= 13;
+ dst >>= 11;
+
+ baa = COND(text[i]) == 8 && A(text[i]);
+ break;
+ case OP2_FBfcc:
+ dst = text[i] & 0x3fffff;
+ dst <<= 10;
+ dst >>= 8;
+
+ baa = COND(text[i]) == 8 && A(text[i]);
+ break;
+ default:
+ continue;
+ }
+
+ dst += i * 4;
+
+ /*
+ * Interpret branches outside of the function's
+ * bounds as potential return sites. If the
+ * branch is a ba,a don't skip the instruction
+ * in the delay slot.
+ */
+ if ((uintptr_t)dst >=
+ (uintptr_t)symp->st_size) {
+ if (baa)
+ goto is_ret_baa;
+ else
+ goto is_ret;
+ }
+ }
+ }
+
+ continue;
+is_ret:
+ i++;
+is_ret_baa:
+ dt_dprintf("return at offset %x\n", i * 4);
+ ftp->ftps_offs[ftp->ftps_noffs++] = i * 4;
+ }
+
+ free(text);
+ if (ftp->ftps_noffs > 0) {
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+ }
+
+
+ return (ftp->ftps_noffs);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+ if (off & 0x3)
+ return (DT_PROC_ALIGN);
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = off;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (1);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+ fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+ ulong_t i;
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ /*
+ * If we're matching against everything, just iterate through each
+ * instruction in the function, otherwise look for matching offset
+ * names by constructing the string and comparing it against the
+ * pattern.
+ */
+ if (strcmp("*", pattern) == 0) {
+ for (i = 0; i < symp->st_size; i += 4) {
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ } else {
+ char name[sizeof (i) * 2 + 1];
+
+ for (i = 0; i < symp->st_size; i += 4) {
+ (void) sprintf(name, "%lx", i);
+ if (gmatch(name, pattern))
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ }
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+
+ return (ftp->ftps_noffs);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/sparc/regs.d b/cddl/contrib/opensolaris/lib/libdtrace/sparc/regs.d
new file mode 100644
index 000000000000..7c4bc0fac519
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/sparc/regs.d
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+inline int R_G0 = 0;
+#pragma D binding "1.0" R_G0
+inline int R_G1 = 1;
+#pragma D binding "1.0" R_G1
+inline int R_G2 = 2;
+#pragma D binding "1.0" R_G2
+inline int R_G3 = 3;
+#pragma D binding "1.0" R_G3
+inline int R_G4 = 4;
+#pragma D binding "1.0" R_G4
+inline int R_G5 = 5;
+#pragma D binding "1.0" R_G5
+inline int R_G6 = 6;
+#pragma D binding "1.0" R_G6
+inline int R_G7 = 7;
+#pragma D binding "1.0" R_G7
+
+inline int R_O0 = 8;
+#pragma D binding "1.0" R_O0
+inline int R_O1 = 9;
+#pragma D binding "1.0" R_O1
+inline int R_O2 = 10;
+#pragma D binding "1.0" R_O2
+inline int R_O3 = 11;
+#pragma D binding "1.0" R_O3
+inline int R_O4 = 12;
+#pragma D binding "1.0" R_O4
+inline int R_O5 = 13;
+#pragma D binding "1.0" R_O5
+inline int R_O6 = 14;
+#pragma D binding "1.0" R_O6
+inline int R_O7 = 15;
+#pragma D binding "1.0" R_O7
+
+inline int R_L0 = 16;
+#pragma D binding "1.0" R_L0
+inline int R_L1 = 17;
+#pragma D binding "1.0" R_L1
+inline int R_L2 = 18;
+#pragma D binding "1.0" R_L2
+inline int R_L3 = 19;
+#pragma D binding "1.0" R_L3
+inline int R_L4 = 20;
+#pragma D binding "1.0" R_L4
+inline int R_L5 = 21;
+#pragma D binding "1.0" R_L5
+inline int R_L6 = 22;
+#pragma D binding "1.0" R_L6
+inline int R_L7 = 23;
+#pragma D binding "1.0" R_L7
+
+inline int R_I0 = 24;
+#pragma D binding "1.0" R_I0
+inline int R_I1 = 25;
+#pragma D binding "1.0" R_I1
+inline int R_I2 = 26;
+#pragma D binding "1.0" R_I2
+inline int R_I3 = 27;
+#pragma D binding "1.0" R_I3
+inline int R_I4 = 28;
+#pragma D binding "1.0" R_I4
+inline int R_I5 = 29;
+#pragma D binding "1.0" R_I5
+inline int R_I6 = 30;
+#pragma D binding "1.0" R_I6
+inline int R_I7 = 31;
+#pragma D binding "1.0" R_I7
+
+inline int R_CCR = 32;
+#pragma D binding "1.0" R_CCR
+inline int R_PC = 33;
+#pragma D binding "1.0" R_PC
+inline int R_nPC = 34;
+#pragma D binding "1.0" R_nPC
+inline int R_NPC = R_nPC;
+#pragma D binding "1.0" R_NPC
+inline int R_Y = 35;
+#pragma D binding "1.0" R_Y
+inline int R_ASI = 36;
+#pragma D binding "1.0" R_ASI
+inline int R_FPRS = 37;
+#pragma D binding "1.0" R_FPRS
+inline int R_PS = R_CCR;
+#pragma D binding "1.0" R_PS
+inline int R_SP = R_O6;
+#pragma D binding "1.0" R_SP
+inline int R_FP = R_I6;
+#pragma D binding "1.0" R_FP
+inline int R_R0 = R_O0;
+#pragma D binding "1.0" R_R0
+inline int R_R1 = R_O1;
+#pragma D binding "1.0" R_R1
diff --git a/cddl/contrib/opensolaris/lib/libgen/common/gmatch.c b/cddl/contrib/opensolaris/lib/libgen/common/gmatch.c
new file mode 100644
index 000000000000..ae65019d3e9f
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libgen/common/gmatch.c
@@ -0,0 +1,175 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef illumos
+#pragma weak gmatch = _gmatch
+
+#include "gen_synonyms.h"
+#endif
+#include <sys/types.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifdef illumos
+#include <widec.h>
+#include "_range.h"
+#else
+#include <ctype.h>
+/* DOODAD */ static int multibyte = 0;
+#define WCHAR_CSMASK 0x30000000
+#define valid_range(c1, c2) \
+ (((c1) & WCHAR_CSMASK) == ((c2) & WCHAR_CSMASK) && \
+ ((c1) > 0xff || !iscntrl((int)c1)) && ((c2) > 0xff || \
+ !iscntrl((int)c2)))
+#endif
+
+#define Popwchar(p, c) \
+ n = mbtowc(&cl, p, MB_LEN_MAX); \
+ c = cl; \
+ if (n <= 0) \
+ return (0); \
+ p += n
+
+int
+gmatch(const char *s, const char *p)
+{
+ const char *olds;
+ wchar_t scc, c;
+ int n;
+ wchar_t cl;
+
+ olds = s;
+ n = mbtowc(&cl, s, MB_LEN_MAX);
+ if (n <= 0) {
+ s++;
+ scc = n;
+ } else {
+ scc = cl;
+ s += n;
+ }
+ n = mbtowc(&cl, p, MB_LEN_MAX);
+ if (n < 0)
+ return (0);
+ if (n == 0)
+ return (scc == 0);
+ p += n;
+ c = cl;
+
+ switch (c) {
+ case '[':
+ if (scc <= 0)
+ return (0);
+ {
+ int ok;
+ wchar_t lc = 0;
+ int notflag = 0;
+
+ ok = 0;
+ if (*p == '!') {
+ notflag = 1;
+ p++;
+ }
+ Popwchar(p, c);
+ do
+ {
+ if (c == '-' && lc && *p != ']') {
+ Popwchar(p, c);
+ if (c == '\\') {
+ Popwchar(p, c);
+ }
+ if (notflag) {
+ if (!multibyte ||
+ valid_range(lc, c)) {
+ if (scc < lc || scc > c)
+ ok++;
+ else
+ return (0);
+ }
+ } else {
+ if (!multibyte ||
+ valid_range(lc, c))
+ if (lc <= scc &&
+ scc <= c)
+ ok++;
+ }
+ } else if (c == '\\') {
+ /* skip to quoted character */
+ Popwchar(p, c);
+ }
+ lc = c;
+ if (notflag) {
+ if (scc != lc)
+ ok++;
+ else
+ return (0);
+ }
+ else
+ {
+ if (scc == lc)
+ ok++;
+ }
+ Popwchar(p, c);
+ } while (c != ']');
+ return (ok ? gmatch(s, p) : 0);
+ }
+
+ case '\\':
+ /* skip to quoted character and see if it matches */
+ Popwchar(p, c);
+
+ default:
+ if (c != scc)
+ return (0);
+ /*FALLTHRU*/
+
+ case '?':
+ return (scc > 0 ? gmatch(s, p) : 0);
+
+ case '*':
+ while (*p == '*')
+ p++;
+
+ if (*p == 0)
+ return (1);
+ s = olds;
+ while (*s) {
+ if (gmatch(s, p))
+ return (1);
+ n = mbtowc(&cl, s, MB_LEN_MAX);
+ if (n < 0)
+ /* skip past illegal byte sequence */
+ s++;
+ else
+ s += n;
+ }
+ return (0);
+ }
+}
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
new file mode 100644
index 000000000000..c6fbfe97a9af
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
@@ -0,0 +1,1286 @@
+/*
+ * 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 (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <solaris.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <string.h>
+#include <libintl.h>
+#include <stdarg.h>
+#include "libnvpair.h"
+
+/*
+ * libnvpair - A tools library for manipulating <name, value> pairs.
+ *
+ * This library provides routines packing an unpacking nv pairs
+ * for transporting data across process boundaries, transporting
+ * between kernel and userland, and possibly saving onto disk files.
+ */
+
+/*
+ * Print control structure.
+ */
+
+#define DEFINEOP(opname, vtype) \
+ struct { \
+ int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
+ const char *, vtype); \
+ void *arg; \
+ } opname
+
+#define DEFINEARROP(opname, vtype) \
+ struct { \
+ int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
+ const char *, vtype, uint_t); \
+ void *arg; \
+ } opname
+
+struct nvlist_printops {
+ DEFINEOP(print_boolean, int);
+ DEFINEOP(print_boolean_value, boolean_t);
+ DEFINEOP(print_byte, uchar_t);
+ DEFINEOP(print_int8, int8_t);
+ DEFINEOP(print_uint8, uint8_t);
+ DEFINEOP(print_int16, int16_t);
+ DEFINEOP(print_uint16, uint16_t);
+ DEFINEOP(print_int32, int32_t);
+ DEFINEOP(print_uint32, uint32_t);
+ DEFINEOP(print_int64, int64_t);
+ DEFINEOP(print_uint64, uint64_t);
+ DEFINEOP(print_double, double);
+ DEFINEOP(print_string, char *);
+ DEFINEOP(print_hrtime, hrtime_t);
+ DEFINEOP(print_nvlist, nvlist_t *);
+ DEFINEARROP(print_boolean_array, boolean_t *);
+ DEFINEARROP(print_byte_array, uchar_t *);
+ DEFINEARROP(print_int8_array, int8_t *);
+ DEFINEARROP(print_uint8_array, uint8_t *);
+ DEFINEARROP(print_int16_array, int16_t *);
+ DEFINEARROP(print_uint16_array, uint16_t *);
+ DEFINEARROP(print_int32_array, int32_t *);
+ DEFINEARROP(print_uint32_array, uint32_t *);
+ DEFINEARROP(print_int64_array, int64_t *);
+ DEFINEARROP(print_uint64_array, uint64_t *);
+ DEFINEARROP(print_string_array, char **);
+ DEFINEARROP(print_nvlist_array, nvlist_t **);
+};
+
+struct nvlist_prtctl {
+ FILE *nvprt_fp; /* output destination */
+ enum nvlist_indent_mode nvprt_indent_mode; /* see above */
+ int nvprt_indent; /* absolute indent, or tab depth */
+ int nvprt_indentinc; /* indent or tab increment */
+ const char *nvprt_nmfmt; /* member name format, max one %s */
+ const char *nvprt_eomfmt; /* after member format, e.g. "\n" */
+ const char *nvprt_btwnarrfmt; /* between array members */
+ int nvprt_btwnarrfmt_nl; /* nvprt_eoamfmt includes newline? */
+ struct nvlist_printops *nvprt_dfltops;
+ struct nvlist_printops *nvprt_custops;
+};
+
+#define DFLTPRTOP(pctl, type) \
+ ((pctl)->nvprt_dfltops->print_##type.op)
+
+#define DFLTPRTOPARG(pctl, type) \
+ ((pctl)->nvprt_dfltops->print_##type.arg)
+
+#define CUSTPRTOP(pctl, type) \
+ ((pctl)->nvprt_custops->print_##type.op)
+
+#define CUSTPRTOPARG(pctl, type) \
+ ((pctl)->nvprt_custops->print_##type.arg)
+
+#define RENDER(pctl, type, nvl, name, val) \
+ { \
+ int done = 0; \
+ if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
+ done = CUSTPRTOP(pctl, type)(pctl, \
+ CUSTPRTOPARG(pctl, type), nvl, name, val); \
+ } \
+ if (!done) { \
+ (void) DFLTPRTOP(pctl, type)(pctl, \
+ DFLTPRTOPARG(pctl, type), nvl, name, val); \
+ } \
+ (void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
+ }
+
+#define ARENDER(pctl, type, nvl, name, arrp, count) \
+ { \
+ int done = 0; \
+ if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
+ done = CUSTPRTOP(pctl, type)(pctl, \
+ CUSTPRTOPARG(pctl, type), nvl, name, arrp, count); \
+ } \
+ if (!done) { \
+ (void) DFLTPRTOP(pctl, type)(pctl, \
+ DFLTPRTOPARG(pctl, type), nvl, name, arrp, count); \
+ } \
+ (void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
+ }
+
+static void nvlist_print_with_indent(nvlist_t *, nvlist_prtctl_t);
+
+/*
+ * ======================================================================
+ * | |
+ * | Indentation |
+ * | |
+ * ======================================================================
+ */
+
+static void
+indent(nvlist_prtctl_t pctl, int onemore)
+{
+ int depth;
+
+ switch (pctl->nvprt_indent_mode) {
+ case NVLIST_INDENT_ABS:
+ (void) fprintf(pctl->nvprt_fp, "%*s",
+ pctl->nvprt_indent + onemore * pctl->nvprt_indentinc, "");
+ break;
+
+ case NVLIST_INDENT_TABBED:
+ depth = pctl->nvprt_indent + onemore;
+ while (depth-- > 0)
+ (void) fprintf(pctl->nvprt_fp, "\t");
+ }
+}
+
+/*
+ * ======================================================================
+ * | |
+ * | Default nvlist member rendering functions. |
+ * | |
+ * ======================================================================
+ */
+
+/*
+ * Generate functions to print single-valued nvlist members.
+ *
+ * type_and_variant - suffix to form function name
+ * vtype - C type for the member value
+ * ptype - C type to cast value to for printing
+ * vfmt - format string for pair value, e.g "%d" or "0x%llx"
+ */
+
+#define NVLIST_PRTFUNC(type_and_variant, vtype, ptype, vfmt) \
+static int \
+nvprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
+ nvlist_t *nvl, const char *name, vtype value) \
+{ \
+ FILE *fp = pctl->nvprt_fp; \
+ NOTE(ARGUNUSED(private)) \
+ NOTE(ARGUNUSED(nvl)) \
+ indent(pctl, 1); \
+ (void) fprintf(fp, pctl->nvprt_nmfmt, name); \
+ (void) fprintf(fp, vfmt, (ptype)value); \
+ return (1); \
+}
+
+NVLIST_PRTFUNC(boolean, int, int, "%d")
+NVLIST_PRTFUNC(boolean_value, boolean_t, int, "%d")
+NVLIST_PRTFUNC(byte, uchar_t, uchar_t, "0x%2.2x")
+NVLIST_PRTFUNC(int8, int8_t, int, "%d")
+NVLIST_PRTFUNC(uint8, uint8_t, uint8_t, "0x%x")
+NVLIST_PRTFUNC(int16, int16_t, int16_t, "%d")
+NVLIST_PRTFUNC(uint16, uint16_t, uint16_t, "0x%x")
+NVLIST_PRTFUNC(int32, int32_t, int32_t, "%d")
+NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x")
+NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld")
+NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx")
+NVLIST_PRTFUNC(double, double, double, "0x%f")
+NVLIST_PRTFUNC(string, char *, char *, "%s")
+NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx")
+
+/*
+ * Generate functions to print array-valued nvlist members.
+ */
+
+#define NVLIST_ARRPRTFUNC(type_and_variant, vtype, ptype, vfmt) \
+static int \
+nvaprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
+ nvlist_t *nvl, const char *name, vtype *valuep, uint_t count) \
+{ \
+ FILE *fp = pctl->nvprt_fp; \
+ uint_t i; \
+ NOTE(ARGUNUSED(private)) \
+ NOTE(ARGUNUSED(nvl)) \
+ for (i = 0; i < count; i++) { \
+ if (i == 0 || pctl->nvprt_btwnarrfmt_nl) { \
+ indent(pctl, 1); \
+ (void) fprintf(fp, pctl->nvprt_nmfmt, name); \
+ if (pctl->nvprt_btwnarrfmt_nl) \
+ (void) fprintf(fp, "[%d]: ", i); \
+ } \
+ if (i != 0) \
+ (void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
+ (void) fprintf(fp, vfmt, (ptype)valuep[i]); \
+ } \
+ return (1); \
+}
+
+NVLIST_ARRPRTFUNC(boolean_array, boolean_t, boolean_t, "%d")
+NVLIST_ARRPRTFUNC(byte_array, uchar_t, uchar_t, "0x%2.2x")
+NVLIST_ARRPRTFUNC(int8_array, int8_t, int8_t, "%d")
+NVLIST_ARRPRTFUNC(uint8_array, uint8_t, uint8_t, "0x%x")
+NVLIST_ARRPRTFUNC(int16_array, int16_t, int16_t, "%d")
+NVLIST_ARRPRTFUNC(uint16_array, uint16_t, uint16_t, "0x%x")
+NVLIST_ARRPRTFUNC(int32_array, int32_t, int32_t, "%d")
+NVLIST_ARRPRTFUNC(uint32_array, uint32_t, uint32_t, "0x%x")
+NVLIST_ARRPRTFUNC(int64_array, int64_t, longlong_t, "%lld")
+NVLIST_ARRPRTFUNC(uint64_array, uint64_t, u_longlong_t, "0x%llx")
+NVLIST_ARRPRTFUNC(string_array, char *, char *, "%s")
+
+/*ARGSUSED*/
+static int
+nvprint_nvlist(nvlist_prtctl_t pctl, void *private,
+ nvlist_t *nvl, const char *name, nvlist_t *value)
+{
+ FILE *fp = pctl->nvprt_fp;
+
+ indent(pctl, 1);
+ (void) fprintf(fp, "%s = (embedded nvlist)\n", name);
+
+ pctl->nvprt_indent += pctl->nvprt_indentinc;
+ nvlist_print_with_indent(value, pctl);
+ pctl->nvprt_indent -= pctl->nvprt_indentinc;
+
+ indent(pctl, 1);
+ (void) fprintf(fp, "(end %s)\n", name);
+
+ return (1);
+}
+
+/*ARGSUSED*/
+static int
+nvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private,
+ nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count)
+{
+ FILE *fp = pctl->nvprt_fp;
+ uint_t i;
+
+ indent(pctl, 1);
+ (void) fprintf(fp, "%s = (array of embedded nvlists)\n", name);
+
+ for (i = 0; i < count; i++) {
+ indent(pctl, 1);
+ (void) fprintf(fp, "(start %s[%d])\n", name, i);
+
+ pctl->nvprt_indent += pctl->nvprt_indentinc;
+ nvlist_print_with_indent(valuep[i], pctl);
+ pctl->nvprt_indent -= pctl->nvprt_indentinc;
+
+ indent(pctl, 1);
+ (void) fprintf(fp, "(end %s[%d])\n", name, i);
+ }
+
+ return (1);
+}
+
+/*
+ * ======================================================================
+ * | |
+ * | Interfaces that allow control over formatting. |
+ * | |
+ * ======================================================================
+ */
+
+void
+nvlist_prtctl_setdest(nvlist_prtctl_t pctl, FILE *fp)
+{
+ pctl->nvprt_fp = fp;
+}
+
+FILE *
+nvlist_prtctl_getdest(nvlist_prtctl_t pctl)
+{
+ return (pctl->nvprt_fp);
+}
+
+
+void
+nvlist_prtctl_setindent(nvlist_prtctl_t pctl, enum nvlist_indent_mode mode,
+ int start, int inc)
+{
+ if (mode < NVLIST_INDENT_ABS || mode > NVLIST_INDENT_TABBED)
+ mode = NVLIST_INDENT_TABBED;
+
+ if (start < 0)
+ start = 0;
+
+ if (inc < 0)
+ inc = 1;
+
+ pctl->nvprt_indent_mode = mode;
+ pctl->nvprt_indent = start;
+ pctl->nvprt_indentinc = inc;
+}
+
+void
+nvlist_prtctl_doindent(nvlist_prtctl_t pctl, int onemore)
+{
+ indent(pctl, onemore);
+}
+
+
+void
+nvlist_prtctl_setfmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which,
+ const char *fmt)
+{
+ switch (which) {
+ case NVLIST_FMT_MEMBER_NAME:
+ if (fmt == NULL)
+ fmt = "%s = ";
+ pctl->nvprt_nmfmt = fmt;
+ break;
+
+ case NVLIST_FMT_MEMBER_POSTAMBLE:
+ if (fmt == NULL)
+ fmt = "\n";
+ pctl->nvprt_eomfmt = fmt;
+ break;
+
+ case NVLIST_FMT_BTWN_ARRAY:
+ if (fmt == NULL) {
+ pctl->nvprt_btwnarrfmt = " ";
+ pctl->nvprt_btwnarrfmt_nl = 0;
+ } else {
+ pctl->nvprt_btwnarrfmt = fmt;
+ pctl->nvprt_btwnarrfmt_nl = (strstr(fmt, "\n") != NULL);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void
+nvlist_prtctl_dofmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, ...)
+{
+ FILE *fp = pctl->nvprt_fp;
+ va_list ap;
+ char *name;
+
+ va_start(ap, which);
+
+ switch (which) {
+ case NVLIST_FMT_MEMBER_NAME:
+ name = va_arg(ap, char *);
+ (void) fprintf(fp, pctl->nvprt_nmfmt, name);
+ break;
+
+ case NVLIST_FMT_MEMBER_POSTAMBLE:
+ (void) fprintf(fp, pctl->nvprt_eomfmt);
+ break;
+
+ case NVLIST_FMT_BTWN_ARRAY:
+ (void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
+ break;
+
+ default:
+ break;
+ }
+
+ va_end(ap);
+}
+
+/*
+ * ======================================================================
+ * | |
+ * | Interfaces to allow appointment of replacement rendering functions.|
+ * | |
+ * ======================================================================
+ */
+
+#define NVLIST_PRINTCTL_REPLACE(type, vtype) \
+void \
+nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
+ int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype), \
+ void *private) \
+{ \
+ CUSTPRTOP(pctl, type) = func; \
+ CUSTPRTOPARG(pctl, type) = private; \
+}
+
+NVLIST_PRINTCTL_REPLACE(boolean, int)
+NVLIST_PRINTCTL_REPLACE(boolean_value, boolean_t)
+NVLIST_PRINTCTL_REPLACE(byte, uchar_t)
+NVLIST_PRINTCTL_REPLACE(int8, int8_t)
+NVLIST_PRINTCTL_REPLACE(uint8, uint8_t)
+NVLIST_PRINTCTL_REPLACE(int16, int16_t)
+NVLIST_PRINTCTL_REPLACE(uint16, uint16_t)
+NVLIST_PRINTCTL_REPLACE(int32, int32_t)
+NVLIST_PRINTCTL_REPLACE(uint32, uint32_t)
+NVLIST_PRINTCTL_REPLACE(int64, int64_t)
+NVLIST_PRINTCTL_REPLACE(uint64, uint64_t)
+NVLIST_PRINTCTL_REPLACE(double, double)
+NVLIST_PRINTCTL_REPLACE(string, char *)
+NVLIST_PRINTCTL_REPLACE(hrtime, hrtime_t)
+NVLIST_PRINTCTL_REPLACE(nvlist, nvlist_t *)
+
+#define NVLIST_PRINTCTL_AREPLACE(type, vtype) \
+void \
+nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
+ int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, \
+ uint_t), void *private) \
+{ \
+ CUSTPRTOP(pctl, type) = func; \
+ CUSTPRTOPARG(pctl, type) = private; \
+}
+
+NVLIST_PRINTCTL_AREPLACE(boolean_array, boolean_t *)
+NVLIST_PRINTCTL_AREPLACE(byte_array, uchar_t *)
+NVLIST_PRINTCTL_AREPLACE(int8_array, int8_t *)
+NVLIST_PRINTCTL_AREPLACE(uint8_array, uint8_t *)
+NVLIST_PRINTCTL_AREPLACE(int16_array, int16_t *)
+NVLIST_PRINTCTL_AREPLACE(uint16_array, uint16_t *)
+NVLIST_PRINTCTL_AREPLACE(int32_array, int32_t *)
+NVLIST_PRINTCTL_AREPLACE(uint32_array, uint32_t *)
+NVLIST_PRINTCTL_AREPLACE(int64_array, int64_t *)
+NVLIST_PRINTCTL_AREPLACE(uint64_array, uint64_t *)
+NVLIST_PRINTCTL_AREPLACE(string_array, char **)
+NVLIST_PRINTCTL_AREPLACE(nvlist_array, nvlist_t **)
+
+/*
+ * ======================================================================
+ * | |
+ * | Interfaces to manage nvlist_prtctl_t cookies. |
+ * | |
+ * ======================================================================
+ */
+
+
+static const struct nvlist_printops defprtops = {
+ { nvprint_boolean, NULL },
+ { nvprint_boolean_value, NULL },
+ { nvprint_byte, NULL },
+ { nvprint_int8, NULL },
+ { nvprint_uint8, NULL },
+ { nvprint_int16, NULL },
+ { nvprint_uint16, NULL },
+ { nvprint_int32, NULL },
+ { nvprint_uint32, NULL },
+ { nvprint_int64, NULL },
+ { nvprint_uint64, NULL },
+ { nvprint_double, NULL },
+ { nvprint_string, NULL },
+ { nvprint_hrtime, NULL },
+ { nvprint_nvlist, NULL },
+ { nvaprint_boolean_array, NULL },
+ { nvaprint_byte_array, NULL },
+ { nvaprint_int8_array, NULL },
+ { nvaprint_uint8_array, NULL },
+ { nvaprint_int16_array, NULL },
+ { nvaprint_uint16_array, NULL },
+ { nvaprint_int32_array, NULL },
+ { nvaprint_uint32_array, NULL },
+ { nvaprint_int64_array, NULL },
+ { nvaprint_uint64_array, NULL },
+ { nvaprint_string_array, NULL },
+ { nvaprint_nvlist_array, NULL },
+};
+
+static void
+prtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl,
+ struct nvlist_printops *ops)
+{
+ pctl->nvprt_fp = fp;
+ pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED;
+ pctl->nvprt_indent = 0;
+ pctl->nvprt_indentinc = 1;
+ pctl->nvprt_nmfmt = "%s = ";
+ pctl->nvprt_eomfmt = "\n";
+ pctl->nvprt_btwnarrfmt = " ";
+ pctl->nvprt_btwnarrfmt_nl = 0;
+
+ pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops;
+ pctl->nvprt_custops = ops;
+}
+
+nvlist_prtctl_t
+nvlist_prtctl_alloc(void)
+{
+ struct nvlist_prtctl *pctl;
+ struct nvlist_printops *ops;
+
+ if ((pctl = malloc(sizeof (*pctl))) == NULL)
+ return (NULL);
+
+ if ((ops = calloc(1, sizeof (*ops))) == NULL) {
+ free(pctl);
+ return (NULL);
+ }
+
+ prtctl_defaults(stdout, pctl, ops);
+
+ return (pctl);
+}
+
+void
+nvlist_prtctl_free(nvlist_prtctl_t pctl)
+{
+ if (pctl != NULL) {
+ free(pctl->nvprt_custops);
+ free(pctl);
+ }
+}
+
+/*
+ * ======================================================================
+ * | |
+ * | Top-level print request interfaces. |
+ * | |
+ * ======================================================================
+ */
+
+/*
+ * nvlist_print - Prints elements in an event buffer
+ */
+static void
+nvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl)
+{
+ FILE *fp = pctl->nvprt_fp;
+ char *name;
+ uint_t nelem;
+ nvpair_t *nvp;
+
+ if (nvl == NULL)
+ return;
+
+ indent(pctl, 0);
+ (void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));
+
+ nvp = nvlist_next_nvpair(nvl, NULL);
+
+ while (nvp) {
+ data_type_t type = nvpair_type(nvp);
+
+ name = nvpair_name(nvp);
+ nelem = 0;
+
+ switch (type) {
+ case DATA_TYPE_BOOLEAN: {
+ RENDER(pctl, boolean, nvl, name, 1);
+ break;
+ }
+ case DATA_TYPE_BOOLEAN_VALUE: {
+ boolean_t val;
+ (void) nvpair_value_boolean_value(nvp, &val);
+ RENDER(pctl, boolean_value, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_BYTE: {
+ uchar_t val;
+ (void) nvpair_value_byte(nvp, &val);
+ RENDER(pctl, byte, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_INT8: {
+ int8_t val;
+ (void) nvpair_value_int8(nvp, &val);
+ RENDER(pctl, int8, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_UINT8: {
+ uint8_t val;
+ (void) nvpair_value_uint8(nvp, &val);
+ RENDER(pctl, uint8, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_INT16: {
+ int16_t val;
+ (void) nvpair_value_int16(nvp, &val);
+ RENDER(pctl, int16, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_UINT16: {
+ uint16_t val;
+ (void) nvpair_value_uint16(nvp, &val);
+ RENDER(pctl, uint16, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_INT32: {
+ int32_t val;
+ (void) nvpair_value_int32(nvp, &val);
+ RENDER(pctl, int32, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_UINT32: {
+ uint32_t val;
+ (void) nvpair_value_uint32(nvp, &val);
+ RENDER(pctl, uint32, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_INT64: {
+ int64_t val;
+ (void) nvpair_value_int64(nvp, &val);
+ RENDER(pctl, int64, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_UINT64: {
+ uint64_t val;
+ (void) nvpair_value_uint64(nvp, &val);
+ RENDER(pctl, uint64, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_DOUBLE: {
+ double val;
+ (void) nvpair_value_double(nvp, &val);
+ RENDER(pctl, double, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_STRING: {
+ char *val;
+ (void) nvpair_value_string(nvp, &val);
+ RENDER(pctl, string, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_BOOLEAN_ARRAY: {
+ boolean_t *val;
+ (void) nvpair_value_boolean_array(nvp, &val, &nelem);
+ ARENDER(pctl, boolean_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_BYTE_ARRAY: {
+ uchar_t *val;
+ (void) nvpair_value_byte_array(nvp, &val, &nelem);
+ ARENDER(pctl, byte_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_INT8_ARRAY: {
+ int8_t *val;
+ (void) nvpair_value_int8_array(nvp, &val, &nelem);
+ ARENDER(pctl, int8_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_UINT8_ARRAY: {
+ uint8_t *val;
+ (void) nvpair_value_uint8_array(nvp, &val, &nelem);
+ ARENDER(pctl, uint8_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_INT16_ARRAY: {
+ int16_t *val;
+ (void) nvpair_value_int16_array(nvp, &val, &nelem);
+ ARENDER(pctl, int16_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_UINT16_ARRAY: {
+ uint16_t *val;
+ (void) nvpair_value_uint16_array(nvp, &val, &nelem);
+ ARENDER(pctl, uint16_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_INT32_ARRAY: {
+ int32_t *val;
+ (void) nvpair_value_int32_array(nvp, &val, &nelem);
+ ARENDER(pctl, int32_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_UINT32_ARRAY: {
+ uint32_t *val;
+ (void) nvpair_value_uint32_array(nvp, &val, &nelem);
+ ARENDER(pctl, uint32_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_INT64_ARRAY: {
+ int64_t *val;
+ (void) nvpair_value_int64_array(nvp, &val, &nelem);
+ ARENDER(pctl, int64_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_UINT64_ARRAY: {
+ uint64_t *val;
+ (void) nvpair_value_uint64_array(nvp, &val, &nelem);
+ ARENDER(pctl, uint64_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_STRING_ARRAY: {
+ char **val;
+ (void) nvpair_value_string_array(nvp, &val, &nelem);
+ ARENDER(pctl, string_array, nvl, name, val, nelem);
+ break;
+ }
+ case DATA_TYPE_HRTIME: {
+ hrtime_t val;
+ (void) nvpair_value_hrtime(nvp, &val);
+ RENDER(pctl, hrtime, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_NVLIST: {
+ nvlist_t *val;
+ (void) nvpair_value_nvlist(nvp, &val);
+ RENDER(pctl, nvlist, nvl, name, val);
+ break;
+ }
+ case DATA_TYPE_NVLIST_ARRAY: {
+ nvlist_t **val;
+ (void) nvpair_value_nvlist_array(nvp, &val, &nelem);
+ ARENDER(pctl, nvlist_array, nvl, name, val, nelem);
+ break;
+ }
+ default:
+ (void) fprintf(fp, " unknown data type (%d)", type);
+ break;
+ }
+ nvp = nvlist_next_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_print(FILE *fp, nvlist_t *nvl)
+{
+ struct nvlist_prtctl pc;
+
+ prtctl_defaults(fp, &pc, NULL);
+ nvlist_print_with_indent(nvl, &pc);
+}
+
+void
+nvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl)
+{
+ nvlist_print_with_indent(nvl, pctl);
+}
+
+#define NVP(elem, type, vtype, ptype, format) { \
+ vtype value; \
+\
+ (void) nvpair_value_##type(elem, &value); \
+ (void) printf("%*s%s: " format "\n", indent, "", \
+ nvpair_name(elem), (ptype)value); \
+}
+
+#define NVPA(elem, type, vtype, ptype, format) { \
+ uint_t i, count; \
+ vtype *value; \
+\
+ (void) nvpair_value_##type(elem, &value, &count); \
+ for (i = 0; i < count; i++) { \
+ (void) printf("%*s%s[%d]: " format "\n", indent, "", \
+ nvpair_name(elem), i, (ptype)value[i]); \
+ } \
+}
+
+/*
+ * Similar to nvlist_print() but handles arrays slightly differently.
+ */
+void
+dump_nvlist(nvlist_t *list, int indent)
+{
+ nvpair_t *elem = NULL;
+ boolean_t bool_value;
+ boolean_t *bool_array_value;
+ nvlist_t *nvlist_value;
+ nvlist_t **nvlist_array_value;
+ uint_t i, count;
+
+ if (list == NULL) {
+ return;
+ }
+
+ while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
+ switch (nvpair_type(elem)) {
+ case DATA_TYPE_BOOLEAN:
+ (void) printf("%*s%s\n", indent, "", nvpair_name(elem));
+ break;
+
+ case DATA_TYPE_BOOLEAN_VALUE:
+ (void) nvpair_value_boolean_value(elem, &bool_value);
+ (void) printf("%*s%s: %s\n", indent, "",
+ nvpair_name(elem), bool_value ? "true" : "false");
+ break;
+
+ case DATA_TYPE_BYTE:
+ NVP(elem, byte, uchar_t, int, "%u");
+ break;
+
+ case DATA_TYPE_INT8:
+ NVP(elem, int8, int8_t, int, "%d");
+ break;
+
+ case DATA_TYPE_UINT8:
+ NVP(elem, uint8, uint8_t, int, "%u");
+ break;
+
+ case DATA_TYPE_INT16:
+ NVP(elem, int16, int16_t, int, "%d");
+ break;
+
+ case DATA_TYPE_UINT16:
+ NVP(elem, uint16, uint16_t, int, "%u");
+ break;
+
+ case DATA_TYPE_INT32:
+ NVP(elem, int32, int32_t, long, "%ld");
+ break;
+
+ case DATA_TYPE_UINT32:
+ NVP(elem, uint32, uint32_t, ulong_t, "%lu");
+ break;
+
+ case DATA_TYPE_INT64:
+ NVP(elem, int64, int64_t, longlong_t, "%lld");
+ break;
+
+ case DATA_TYPE_UINT64:
+ NVP(elem, uint64, uint64_t, u_longlong_t, "%llu");
+ break;
+
+ case DATA_TYPE_STRING:
+ NVP(elem, string, char *, char *, "'%s'");
+ break;
+
+ case DATA_TYPE_BOOLEAN_ARRAY:
+ (void) nvpair_value_boolean_array(elem,
+ &bool_array_value, &count);
+ for (i = 0; i < count; i++) {
+ (void) printf("%*s%s[%d]: %s\n", indent, "",
+ nvpair_name(elem), i,
+ bool_array_value[i] ? "true" : "false");
+ }
+ break;
+
+ case DATA_TYPE_BYTE_ARRAY:
+ NVPA(elem, byte_array, uchar_t, int, "%u");
+ break;
+
+ case DATA_TYPE_INT8_ARRAY:
+ NVPA(elem, int8_array, int8_t, int, "%d");
+ break;
+
+ case DATA_TYPE_UINT8_ARRAY:
+ NVPA(elem, uint8_array, uint8_t, int, "%u");
+ break;
+
+ case DATA_TYPE_INT16_ARRAY:
+ NVPA(elem, int16_array, int16_t, int, "%d");
+ break;
+
+ case DATA_TYPE_UINT16_ARRAY:
+ NVPA(elem, uint16_array, uint16_t, int, "%u");
+ break;
+
+ case DATA_TYPE_INT32_ARRAY:
+ NVPA(elem, int32_array, int32_t, long, "%ld");
+ break;
+
+ case DATA_TYPE_UINT32_ARRAY:
+ NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu");
+ break;
+
+ case DATA_TYPE_INT64_ARRAY:
+ NVPA(elem, int64_array, int64_t, longlong_t, "%lld");
+ break;
+
+ case DATA_TYPE_UINT64_ARRAY:
+ NVPA(elem, uint64_array, uint64_t, u_longlong_t,
+ "%llu");
+ break;
+
+ case DATA_TYPE_STRING_ARRAY:
+ NVPA(elem, string_array, char *, char *, "'%s'");
+ break;
+
+ case DATA_TYPE_NVLIST:
+ (void) nvpair_value_nvlist(elem, &nvlist_value);
+ (void) printf("%*s%s:\n", indent, "",
+ nvpair_name(elem));
+ dump_nvlist(nvlist_value, indent + 4);
+ break;
+
+ case DATA_TYPE_NVLIST_ARRAY:
+ (void) nvpair_value_nvlist_array(elem,
+ &nvlist_array_value, &count);
+ for (i = 0; i < count; i++) {
+ (void) printf("%*s%s[%u]:\n", indent, "",
+ nvpair_name(elem), i);
+ dump_nvlist(nvlist_array_value[i], indent + 4);
+ }
+ break;
+
+ default:
+ (void) printf(dgettext(TEXT_DOMAIN, "bad config type "
+ "%d for %s\n"), nvpair_type(elem),
+ nvpair_name(elem));
+ }
+ }
+}
+
+/*
+ * ======================================================================
+ * | |
+ * | Misc private interface. |
+ * | |
+ * ======================================================================
+ */
+
+/*
+ * Determine if string 'value' matches 'nvp' value. The 'value' string is
+ * converted, depending on the type of 'nvp', prior to match. For numeric
+ * types, a radix independent sscanf conversion of 'value' is used. If 'nvp'
+ * is an array type, 'ai' is the index into the array against which we are
+ * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass
+ * in a regex_t compilation of value in 'value_regex' to trigger regular
+ * expression string match instead of simple strcmp().
+ *
+ * Return 1 on match, 0 on no-match, and -1 on error. If the error is
+ * related to value syntax error and 'ep' is non-NULL, *ep will point into
+ * the 'value' string at the location where the error exists.
+ *
+ * NOTE: It may be possible to move the non-regex_t version of this into
+ * common code used by library/kernel/boot.
+ */
+int
+nvpair_value_match_regex(nvpair_t *nvp, int ai,
+ char *value, regex_t *value_regex, char **ep)
+{
+ char *evalue;
+ uint_t a_len;
+ int sr;
+
+ if (ep)
+ *ep = NULL;
+
+ if ((nvp == NULL) || (value == NULL))
+ return (-1); /* error fail match - invalid args */
+
+ /* make sure array and index combination make sense */
+ if ((nvpair_type_is_array(nvp) && (ai < 0)) ||
+ (!nvpair_type_is_array(nvp) && (ai >= 0)))
+ return (-1); /* error fail match - bad index */
+
+ /* non-string values should be single 'chunk' */
+ if ((nvpair_type(nvp) != DATA_TYPE_STRING) &&
+ (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) {
+ value += strspn(value, " \t");
+ evalue = value + strcspn(value, " \t");
+ if (*evalue) {
+ if (ep)
+ *ep = evalue;
+ return (-1); /* error fail match - syntax */
+ }
+ }
+
+ sr = EOF;
+ switch (nvpair_type(nvp)) {
+ case DATA_TYPE_STRING: {
+ char *val;
+
+ /* check string value for match */
+ if (nvpair_value_string(nvp, &val) == 0) {
+ if (value_regex) {
+ if (regexec(value_regex, val,
+ (size_t)0, NULL, 0) == 0)
+ return (1); /* match */
+ } else {
+ if (strcmp(value, val) == 0)
+ return (1); /* match */
+ }
+ }
+ break;
+ }
+ case DATA_TYPE_STRING_ARRAY: {
+ char **val_array;
+
+ /* check indexed string value of array for match */
+ if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len)) {
+ if (value_regex) {
+ if (regexec(value_regex, val_array[ai],
+ (size_t)0, NULL, 0) == 0)
+ return (1);
+ } else {
+ if (strcmp(value, val_array[ai]) == 0)
+ return (1);
+ }
+ }
+ break;
+ }
+ case DATA_TYPE_BYTE: {
+ uchar_t val, val_arg;
+
+ /* scanf uchar_t from value and check for match */
+ sr = sscanf(value, "%c", &val_arg);
+ if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_BYTE_ARRAY: {
+ uchar_t *val_array, val_arg;
+
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%c", &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT8: {
+ int8_t val, val_arg;
+
+ /* scanf int8_t from value and check for match */
+ sr = sscanf(value, "%"SCNi8, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int8(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT8_ARRAY: {
+ int8_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi8, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT8: {
+ uint8_t val, val_arg;
+
+ /* scanf uint8_t from value and check for match */
+ sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint8(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT8_ARRAY: {
+ uint8_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT16: {
+ int16_t val, val_arg;
+
+ /* scanf int16_t from value and check for match */
+ sr = sscanf(value, "%"SCNi16, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int16(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT16_ARRAY: {
+ int16_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi16, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT16: {
+ uint16_t val, val_arg;
+
+ /* scanf uint16_t from value and check for match */
+ sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint16(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT16_ARRAY: {
+ uint16_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT32: {
+ int32_t val, val_arg;
+
+ /* scanf int32_t from value and check for match */
+ sr = sscanf(value, "%"SCNi32, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int32(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT32_ARRAY: {
+ int32_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi32, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT32: {
+ uint32_t val, val_arg;
+
+ /* scanf uint32_t from value and check for match */
+ sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint32(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT32_ARRAY: {
+ uint32_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT64: {
+ int64_t val, val_arg;
+
+ /* scanf int64_t from value and check for match */
+ sr = sscanf(value, "%"SCNi64, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int64(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_INT64_ARRAY: {
+ int64_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi64, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT64: {
+ uint64_t val_arg, val;
+
+ /* scanf uint64_t from value and check for match */
+ sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint64(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_UINT64_ARRAY: {
+ uint64_t *val_array, val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_BOOLEAN_VALUE: {
+ int32_t val_arg;
+ boolean_t val;
+
+ /* scanf boolean_t from value and check for match */
+ sr = sscanf(value, "%"SCNi32, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_boolean_value(nvp, &val) == 0) &&
+ (val == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_BOOLEAN_ARRAY: {
+ boolean_t *val_array;
+ int32_t val_arg;
+
+ /* check indexed value of array for match */
+ sr = sscanf(value, "%"SCNi32, &val_arg);
+ if ((sr == 1) &&
+ (nvpair_value_boolean_array(nvp,
+ &val_array, &a_len) == 0) &&
+ (ai < a_len) &&
+ (val_array[ai] == val_arg))
+ return (1);
+ break;
+ }
+ case DATA_TYPE_HRTIME:
+ case DATA_TYPE_NVLIST:
+ case DATA_TYPE_NVLIST_ARRAY:
+ case DATA_TYPE_BOOLEAN:
+ case DATA_TYPE_DOUBLE:
+ case DATA_TYPE_UNKNOWN:
+ default:
+ /*
+ * unknown/unsupported data type
+ */
+ return (-1); /* error fail match */
+ }
+
+ /*
+ * check to see if sscanf failed conversion, return approximate
+ * pointer to problem
+ */
+ if (sr != 1) {
+ if (ep)
+ *ep = value;
+ return (-1); /* error fail match - syntax */
+ }
+
+ return (0); /* fail match */
+}
+
+int
+nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep)
+{
+ return (nvpair_value_match_regex(nvp, ai, value, NULL, ep));
+}
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h
new file mode 100644
index 000000000000..b05669e506ba
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h
@@ -0,0 +1,196 @@
+/*
+ * 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 (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _LIBNVPAIR_H
+#define _LIBNVPAIR_H
+
+#include <sys/nvpair.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <regex.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * All interfaces described in this file are private to Solaris, and
+ * are subject to change at any time and without notice. The public
+ * nvlist/nvpair interfaces, as documented in manpage sections 3NVPAIR,
+ * are all imported from <sys/nvpair.h> included above.
+ */
+
+extern int nvpair_value_match(nvpair_t *, int, char *, char **);
+extern int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *,
+ char **);
+
+extern void nvlist_print(FILE *, nvlist_t *);
+extern int nvlist_print_json(FILE *, nvlist_t *);
+extern void dump_nvlist(nvlist_t *, int);
+
+/*
+ * Private nvlist printing interface that allows the caller some control
+ * over output rendering (as opposed to nvlist_print and dump_nvlist).
+ *
+ * Obtain an opaque nvlist_prtctl_t cookie using nvlist_prtctl_alloc
+ * (NULL on failure); on return the cookie is set up for default formatting
+ * and rendering. Quote the cookie in subsequent customisation functions and
+ * then pass the cookie to nvlist_prt to render the nvlist. Finally,
+ * use nvlist_prtctl_free to release the cookie.
+ *
+ * For all nvlist_lookup_xxx and nvlist_lookup_xxx_array functions
+ * we have a corresponding brace of functions that appoint replacement
+ * rendering functions:
+ *
+ * extern void nvlist_prtctl_xxx(nvlist_prtctl_t,
+ * void (*)(nvlist_prtctl_t ctl, void *private, const char *name,
+ * xxxtype value))
+ *
+ * and
+ *
+ * extern void nvlist_prtctl_xxx_array(nvlist_prtctl_t,
+ * void (*)(nvlist_prtctl_t ctl, void *private, const char *name,
+ * xxxtype value, uint_t count))
+ *
+ * where xxxtype is the C datatype corresponding to xxx, eg int8_t for "int8"
+ * and char * for "string". The function that is appointed to render the
+ * specified datatype receives as arguments the cookie, the nvlist
+ * member name, the value of that member (or a pointer for array function),
+ * and (for array rendering functions) a count of the number of elements.
+ */
+
+typedef struct nvlist_prtctl *nvlist_prtctl_t; /* opaque */
+
+enum nvlist_indent_mode {
+ NVLIST_INDENT_ABS, /* Absolute indentation */
+ NVLIST_INDENT_TABBED /* Indent with tabstops */
+};
+
+extern nvlist_prtctl_t nvlist_prtctl_alloc(void);
+extern void nvlist_prtctl_free(nvlist_prtctl_t);
+extern void nvlist_prt(nvlist_t *, nvlist_prtctl_t);
+
+/* Output stream */
+extern void nvlist_prtctl_setdest(nvlist_prtctl_t, FILE *);
+extern FILE *nvlist_prtctl_getdest(nvlist_prtctl_t);
+
+/* Indentation mode, start indent, indent increment; default tabbed/0/1 */
+extern void nvlist_prtctl_setindent(nvlist_prtctl_t, enum nvlist_indent_mode,
+ int, int);
+extern void nvlist_prtctl_doindent(nvlist_prtctl_t, int);
+
+enum nvlist_prtctl_fmt {
+ NVLIST_FMT_MEMBER_NAME, /* name fmt; default "%s = " */
+ NVLIST_FMT_MEMBER_POSTAMBLE, /* after nvlist member; default "\n" */
+ NVLIST_FMT_BTWN_ARRAY /* between array members; default " " */
+};
+
+extern void nvlist_prtctl_setfmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt,
+ const char *);
+extern void nvlist_prtctl_dofmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt, ...);
+
+/*
+ * Function prototypes for interfaces that appoint a new rendering function
+ * for single-valued nvlist members.
+ *
+ * A replacement function receives arguments as follows:
+ *
+ * nvlist_prtctl_t Print control structure; do not change preferences
+ * for this object from a print callback function.
+ *
+ * void * The function-private cookie argument registered
+ * when the replacement function was appointed.
+ *
+ * nvlist_t * The full nvlist that is being processed. The
+ * rendering function is called to render a single
+ * member (name and value passed as below) but it may
+ * want to reference or incorporate other aspects of
+ * the full nvlist.
+ *
+ * const char * Member name to render
+ *
+ * valtype Value of the member to render
+ *
+ * The function must return non-zero if it has rendered output for this
+ * member, or 0 if it wants to default to standard rendering for this
+ * one member.
+ */
+
+#define NVLIST_PRINTCTL_SVDECL(funcname, valtype) \
+ extern void funcname(nvlist_prtctl_t, \
+ int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, valtype), \
+ void *)
+
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean, int);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean_value, boolean_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_byte, uchar_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int8, int8_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint8, uint8_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int16, int16_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint16, uint16_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int32, int32_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint32, uint32_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int64, int64_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint64, uint64_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_double, double);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_string, char *);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_hrtime, hrtime_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_nvlist, nvlist_t *);
+
+#undef NVLIST_PRINTCTL_SVDECL /* was just for "clarity" above */
+
+/*
+ * Function prototypes for interfaces that appoint a new rendering function
+ * for array-valued nvlist members.
+ *
+ * One additional argument is taken: uint_t for the number of array elements
+ *
+ * Return values as above.
+ */
+#define NVLIST_PRINTCTL_AVDECL(funcname, vtype) \
+ extern void funcname(nvlist_prtctl_t, \
+ int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, uint_t), \
+ void *)
+
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_boolean_array, boolean_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_byte_array, uchar_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int8_array, int8_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint8_array, uint8_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int16_array, int16_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint16_array, uint16_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int32_array, int32_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint32_array, uint32_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int64_array, int64_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint64_array, uint64_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_string_array, char **);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_nvlist_array, nvlist_t **);
+
+#undef NVLIST_PRINTCTL_AVDECL /* was just for "clarity" above */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBNVPAIR_H */
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c b/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c
new file mode 100644
index 000000000000..1aefc1004daf
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/nvpair.h>
+#include <stdlib.h>
+
+/*ARGSUSED*/
+static void *
+nv_alloc_sys(nv_alloc_t *nva, size_t size)
+{
+ return (malloc(size));
+}
+
+/*ARGSUSED*/
+static void
+nv_free_sys(nv_alloc_t *nva, void *buf, size_t size)
+{
+ free(buf);
+}
+
+const nv_alloc_ops_t system_ops_def = {
+ NULL, /* nv_ao_init() */
+ NULL, /* nv_ao_fini() */
+ nv_alloc_sys, /* nv_ao_alloc() */
+ nv_free_sys, /* nv_ao_free() */
+ NULL /* nv_ao_reset() */
+};
+
+nv_alloc_t nv_alloc_nosleep_def = {
+ &system_ops_def,
+ NULL
+};
+
+nv_alloc_t *nv_alloc_nosleep = &nv_alloc_nosleep_def;
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c b/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c
new file mode 100644
index 000000000000..b687a2f5761a
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c
@@ -0,0 +1,406 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright (c) 2014, Joyent, Inc.
+ * Copyright (c) 2017 by Delphix. All rights reserved.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <wchar.h>
+#include <sys/debug.h>
+
+#include "libnvpair.h"
+
+#define FPRINTF(fp, ...) \
+ do { \
+ if (fprintf(fp, __VA_ARGS__) < 0) \
+ return (-1); \
+ } while (0)
+
+/*
+ * When formatting a string for JSON output we must escape certain characters,
+ * as described in RFC4627. This applies to both member names and
+ * DATA_TYPE_STRING values.
+ *
+ * This function will only operate correctly if the following conditions are
+ * met:
+ *
+ * 1. The input String is encoded in the current locale.
+ *
+ * 2. The current locale includes the Basic Multilingual Plane (plane 0)
+ * as defined in the Unicode standard.
+ *
+ * The output will be entirely 7-bit ASCII (as a subset of UTF-8) with all
+ * representable Unicode characters included in their escaped numeric form.
+ */
+static int
+nvlist_print_json_string(FILE *fp, const char *input)
+{
+ mbstate_t mbr;
+ wchar_t c;
+ size_t sz;
+
+ bzero(&mbr, sizeof (mbr));
+
+ FPRINTF(fp, "\"");
+ while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) {
+ switch (c) {
+ case '"':
+ FPRINTF(fp, "\\\"");
+ break;
+ case '\n':
+ FPRINTF(fp, "\\n");
+ break;
+ case '\r':
+ FPRINTF(fp, "\\r");
+ break;
+ case '\\':
+ FPRINTF(fp, "\\\\");
+ break;
+ case '\f':
+ FPRINTF(fp, "\\f");
+ break;
+ case '\t':
+ FPRINTF(fp, "\\t");
+ break;
+ case '\b':
+ FPRINTF(fp, "\\b");
+ break;
+ default:
+ if ((c >= 0x00 && c <= 0x1f) ||
+ (c > 0x7f && c <= 0xffff)) {
+ /*
+ * Render both Control Characters and Unicode
+ * characters in the Basic Multilingual Plane
+ * as JSON-escaped multibyte characters.
+ */
+ FPRINTF(fp, "\\u%04x", (int)(0xffff & c));
+ } else if (c >= 0x20 && c <= 0x7f) {
+ /*
+ * Render other 7-bit ASCII characters directly
+ * and drop other, unrepresentable characters.
+ */
+ FPRINTF(fp, "%c", (int)(0xff & c));
+ }
+ break;
+ }
+ input += sz;
+ }
+
+ if (sz == (size_t)-1 || sz == (size_t)-2) {
+ /*
+ * We last read an invalid multibyte character sequence,
+ * so return an error.
+ */
+ return (-1);
+ }
+
+ FPRINTF(fp, "\"");
+ return (0);
+}
+
+/*
+ * Dump a JSON-formatted representation of an nvlist to the provided FILE *.
+ * This routine does not output any new-lines or additional whitespace other
+ * than that contained in strings, nor does it call fflush(3C).
+ */
+int
+nvlist_print_json(FILE *fp, nvlist_t *nvl)
+{
+ nvpair_t *curr;
+ boolean_t first = B_TRUE;
+
+ FPRINTF(fp, "{");
+
+ for (curr = nvlist_next_nvpair(nvl, NULL); curr;
+ curr = nvlist_next_nvpair(nvl, curr)) {
+ data_type_t type = nvpair_type(curr);
+
+ if (!first)
+ FPRINTF(fp, ",");
+ else
+ first = B_FALSE;
+
+ if (nvlist_print_json_string(fp, nvpair_name(curr)) == -1)
+ return (-1);
+ FPRINTF(fp, ":");
+
+ switch (type) {
+ case DATA_TYPE_STRING: {
+ char *string = fnvpair_value_string(curr);
+ if (nvlist_print_json_string(fp, string) == -1)
+ return (-1);
+ break;
+ }
+
+ case DATA_TYPE_BOOLEAN: {
+ FPRINTF(fp, "true");
+ break;
+ }
+
+ case DATA_TYPE_BOOLEAN_VALUE: {
+ FPRINTF(fp, "%s", fnvpair_value_boolean_value(curr) ==
+ B_TRUE ? "true" : "false");
+ break;
+ }
+
+ case DATA_TYPE_BYTE: {
+ FPRINTF(fp, "%hhu", fnvpair_value_byte(curr));
+ break;
+ }
+
+ case DATA_TYPE_INT8: {
+ FPRINTF(fp, "%hhd", fnvpair_value_int8(curr));
+ break;
+ }
+
+ case DATA_TYPE_UINT8: {
+ FPRINTF(fp, "%hhu", fnvpair_value_uint8_t(curr));
+ break;
+ }
+
+ case DATA_TYPE_INT16: {
+ FPRINTF(fp, "%hd", fnvpair_value_int16(curr));
+ break;
+ }
+
+ case DATA_TYPE_UINT16: {
+ FPRINTF(fp, "%hu", fnvpair_value_uint16(curr));
+ break;
+ }
+
+ case DATA_TYPE_INT32: {
+ FPRINTF(fp, "%d", fnvpair_value_int32(curr));
+ break;
+ }
+
+ case DATA_TYPE_UINT32: {
+ FPRINTF(fp, "%u", fnvpair_value_uint32(curr));
+ break;
+ }
+
+ case DATA_TYPE_INT64: {
+ FPRINTF(fp, "%lld",
+ (long long)fnvpair_value_int64(curr));
+ break;
+ }
+
+ case DATA_TYPE_UINT64: {
+ FPRINTF(fp, "%llu",
+ (unsigned long long)fnvpair_value_uint64(curr));
+ break;
+ }
+
+ case DATA_TYPE_HRTIME: {
+ hrtime_t val;
+ VERIFY0(nvpair_value_hrtime(curr, &val));
+ FPRINTF(fp, "%llu", (unsigned long long)val);
+ break;
+ }
+
+ case DATA_TYPE_DOUBLE: {
+ double val;
+ VERIFY0(nvpair_value_double(curr, &val));
+ FPRINTF(fp, "%f", val);
+ break;
+ }
+
+ case DATA_TYPE_NVLIST: {
+ if (nvlist_print_json(fp,
+ fnvpair_value_nvlist(curr)) == -1)
+ return (-1);
+ break;
+ }
+
+ case DATA_TYPE_STRING_ARRAY: {
+ char **val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_string_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ if (nvlist_print_json_string(fp, val[i]) == -1)
+ return (-1);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_NVLIST_ARRAY: {
+ nvlist_t **val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ if (nvlist_print_json(fp, val[i]) == -1)
+ return (-1);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_BOOLEAN_ARRAY: {
+ boolean_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, val[i] == B_TRUE ?
+ "true" : "false");
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_BYTE_ARRAY: {
+ uchar_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_byte_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, "%hhu", val[i]);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_UINT8_ARRAY: {
+ uint8_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, "%hhu", val[i]);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_INT8_ARRAY: {
+ int8_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_int8_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, "%hhd", val[i]);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_UINT16_ARRAY: {
+ uint16_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, "%hu", val[i]);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_INT16_ARRAY: {
+ int16_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_int16_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, "%hd", val[i]);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_UINT32_ARRAY: {
+ uint32_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, "%u", val[i]);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_INT32_ARRAY: {
+ int32_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_int32_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, "%d", val[i]);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_UINT64_ARRAY: {
+ uint64_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, "%llu",
+ (unsigned long long)val[i]);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_INT64_ARRAY: {
+ int64_t *val;
+ uint_t valsz, i;
+ VERIFY0(nvpair_value_int64_array(curr, &val, &valsz));
+ FPRINTF(fp, "[");
+ for (i = 0; i < valsz; i++) {
+ if (i > 0)
+ FPRINTF(fp, ",");
+ FPRINTF(fp, "%lld", (long long)val[i]);
+ }
+ FPRINTF(fp, "]");
+ break;
+ }
+
+ case DATA_TYPE_UNKNOWN:
+ case DATA_TYPE_DONTCARE:
+ return (-1);
+ }
+
+ }
+
+ FPRINTF(fp, "}");
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h b/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h
new file mode 100644
index 000000000000..7a5f8a8570c6
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h
@@ -0,0 +1,391 @@
+/*
+ * 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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _LIBUUTIL_H
+#define _LIBUUTIL_H
+
+#include <solaris.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Standard flags codes.
+ */
+#define UU_DEFAULT 0
+
+/*
+ * Standard error codes.
+ */
+#define UU_ERROR_NONE 0 /* no error */
+#define UU_ERROR_INVALID_ARGUMENT 1 /* invalid argument */
+#define UU_ERROR_UNKNOWN_FLAG 2 /* passed flag invalid */
+#define UU_ERROR_NO_MEMORY 3 /* out of memory */
+#define UU_ERROR_CALLBACK_FAILED 4 /* callback-initiated error */
+#define UU_ERROR_NOT_SUPPORTED 5 /* operation not supported */
+#define UU_ERROR_EMPTY 6 /* no value provided */
+#define UU_ERROR_UNDERFLOW 7 /* value is too small */
+#define UU_ERROR_OVERFLOW 8 /* value is too value */
+#define UU_ERROR_INVALID_CHAR 9 /* value contains unexpected char */
+#define UU_ERROR_INVALID_DIGIT 10 /* value contains digit not in base */
+
+#define UU_ERROR_SYSTEM 99 /* underlying system error */
+#define UU_ERROR_UNKNOWN 100 /* error status not known */
+
+/*
+ * Standard program exit codes.
+ */
+#define UU_EXIT_OK (*(uu_exit_ok()))
+#define UU_EXIT_FATAL (*(uu_exit_fatal()))
+#define UU_EXIT_USAGE (*(uu_exit_usage()))
+
+/*
+ * Exit status profiles.
+ */
+#define UU_PROFILE_DEFAULT 0
+#define UU_PROFILE_LAUNCHER 1
+
+/*
+ * Error reporting functions.
+ */
+uint32_t uu_error(void);
+const char *uu_strerror(uint32_t);
+
+/*
+ * Program notification functions.
+ */
+extern void uu_alt_exit(int);
+extern const char *uu_setpname(char *);
+extern const char *uu_getpname(void);
+/*PRINTFLIKE1*/
+extern void uu_warn(const char *, ...);
+extern void uu_vwarn(const char *, va_list);
+/*PRINTFLIKE1*/
+extern void uu_die(const char *, ...) __NORETURN;
+extern void uu_vdie(const char *, va_list) __NORETURN;
+/*PRINTFLIKE2*/
+extern void uu_xdie(int, const char *, ...) __NORETURN;
+extern void uu_vxdie(int, const char *, va_list) __NORETURN;
+
+/*
+ * Exit status functions (not to be used directly)
+ */
+extern int *uu_exit_ok(void);
+extern int *uu_exit_fatal(void);
+extern int *uu_exit_usage(void);
+
+/*
+ * string->number conversions
+ */
+extern int uu_strtoint(const char *, void *, size_t, int, int64_t, int64_t);
+extern int uu_strtouint(const char *, void *, size_t, int, uint64_t, uint64_t);
+
+/*
+ * Debug print facility functions.
+ */
+typedef struct uu_dprintf uu_dprintf_t;
+
+typedef enum {
+ UU_DPRINTF_SILENT,
+ UU_DPRINTF_FATAL,
+ UU_DPRINTF_WARNING,
+ UU_DPRINTF_NOTICE,
+ UU_DPRINTF_INFO,
+ UU_DPRINTF_DEBUG
+} uu_dprintf_severity_t;
+
+extern uu_dprintf_t *uu_dprintf_create(const char *, uu_dprintf_severity_t,
+ uint_t);
+/*PRINTFLIKE3*/
+extern void uu_dprintf(uu_dprintf_t *, uu_dprintf_severity_t,
+ const char *, ...);
+extern void uu_dprintf_destroy(uu_dprintf_t *);
+extern const char *uu_dprintf_getname(uu_dprintf_t *);
+
+/*
+ * Identifier test flags and function.
+ */
+#define UU_NAME_DOMAIN 0x1 /* allow SUNW, or com.sun, prefix */
+#define UU_NAME_PATH 0x2 /* allow '/'-delimited paths */
+
+int uu_check_name(const char *, uint_t);
+
+/*
+ * File creation functions.
+ */
+extern int uu_open_tmp(const char *dir, uint_t uflags);
+
+/*
+ * Convenience functions.
+ */
+#define UU_NELEM(a) (sizeof (a) / sizeof ((a)[0]))
+
+/*PRINTFLIKE1*/
+extern char *uu_msprintf(const char *format, ...);
+extern void *uu_zalloc(size_t);
+extern char *uu_strdup(const char *);
+extern void uu_free(void *);
+
+extern boolean_t uu_strcaseeq(const char *a, const char *b);
+extern boolean_t uu_streq(const char *a, const char *b);
+extern char *uu_strndup(const char *s, size_t n);
+extern boolean_t uu_strbw(const char *a, const char *b);
+extern void *uu_memdup(const void *buf, size_t sz);
+extern void uu_dump(FILE *out, const char *prefix, const void *buf, size_t len);
+
+/*
+ * Comparison function type definition.
+ * Developers should be careful in their use of the _private argument. If you
+ * break interface guarantees, you get undefined behavior.
+ */
+typedef int uu_compare_fn_t(const void *__left, const void *__right,
+ void *__private);
+
+/*
+ * Walk variant flags.
+ * A data structure need not provide support for all variants and
+ * combinations. Refer to the appropriate documentation.
+ */
+#define UU_WALK_ROBUST 0x00000001 /* walk can survive removes */
+#define UU_WALK_REVERSE 0x00000002 /* reverse walk order */
+
+#define UU_WALK_PREORDER 0x00000010 /* walk tree in pre-order */
+#define UU_WALK_POSTORDER 0x00000020 /* walk tree in post-order */
+
+/*
+ * Walk callback function return codes.
+ */
+#define UU_WALK_ERROR -1
+#define UU_WALK_NEXT 0
+#define UU_WALK_DONE 1
+
+/*
+ * Walk callback function type definition.
+ */
+typedef int uu_walk_fn_t(void *_elem, void *_private);
+
+/*
+ * lists: opaque structures
+ */
+typedef struct uu_list_pool uu_list_pool_t;
+typedef struct uu_list uu_list_t;
+
+typedef struct uu_list_node {
+ uintptr_t uln_opaque[2];
+} uu_list_node_t;
+
+typedef struct uu_list_walk uu_list_walk_t;
+
+typedef uintptr_t uu_list_index_t;
+
+/*
+ * lists: interface
+ *
+ * basic usage:
+ * typedef struct foo {
+ * ...
+ * uu_list_node_t foo_node;
+ * ...
+ * } foo_t;
+ *
+ * static int
+ * foo_compare(void *l_arg, void *r_arg, void *private)
+ * {
+ * foo_t *l = l_arg;
+ * foo_t *r = r_arg;
+ *
+ * if (... l greater than r ...)
+ * return (1);
+ * if (... l less than r ...)
+ * return (-1);
+ * return (0);
+ * }
+ *
+ * ...
+ * // at initialization time
+ * foo_pool = uu_list_pool_create("foo_pool",
+ * sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
+ * debugging? 0 : UU_AVL_POOL_DEBUG);
+ * ...
+ */
+uu_list_pool_t *uu_list_pool_create(const char *, size_t, size_t,
+ uu_compare_fn_t *, uint32_t);
+#define UU_LIST_POOL_DEBUG 0x00000001
+
+void uu_list_pool_destroy(uu_list_pool_t *);
+
+/*
+ * usage:
+ *
+ * foo_t *a;
+ * a = malloc(sizeof(*a));
+ * uu_list_node_init(a, &a->foo_list, pool);
+ * ...
+ * uu_list_node_fini(a, &a->foo_list, pool);
+ * free(a);
+ */
+void uu_list_node_init(void *, uu_list_node_t *, uu_list_pool_t *);
+void uu_list_node_fini(void *, uu_list_node_t *, uu_list_pool_t *);
+
+uu_list_t *uu_list_create(uu_list_pool_t *, void *_parent, uint32_t);
+#define UU_LIST_DEBUG 0x00000001
+#define UU_LIST_SORTED 0x00000002 /* list is sorted */
+
+void uu_list_destroy(uu_list_t *); /* list must be empty */
+
+size_t uu_list_numnodes(uu_list_t *);
+
+void *uu_list_first(uu_list_t *);
+void *uu_list_last(uu_list_t *);
+
+void *uu_list_next(uu_list_t *, void *);
+void *uu_list_prev(uu_list_t *, void *);
+
+int uu_list_walk(uu_list_t *, uu_walk_fn_t *, void *, uint32_t);
+
+uu_list_walk_t *uu_list_walk_start(uu_list_t *, uint32_t);
+void *uu_list_walk_next(uu_list_walk_t *);
+void uu_list_walk_end(uu_list_walk_t *);
+
+void *uu_list_find(uu_list_t *, void *, void *, uu_list_index_t *);
+void uu_list_insert(uu_list_t *, void *, uu_list_index_t);
+
+void *uu_list_nearest_next(uu_list_t *, uu_list_index_t);
+void *uu_list_nearest_prev(uu_list_t *, uu_list_index_t);
+
+void *uu_list_teardown(uu_list_t *, void **);
+
+void uu_list_remove(uu_list_t *, void *);
+
+/*
+ * lists: interfaces for non-sorted lists only
+ */
+int uu_list_insert_before(uu_list_t *, void *_target, void *_elem);
+int uu_list_insert_after(uu_list_t *, void *_target, void *_elem);
+
+/*
+ * avl trees: opaque structures
+ */
+typedef struct uu_avl_pool uu_avl_pool_t;
+typedef struct uu_avl uu_avl_t;
+
+typedef struct uu_avl_node {
+#ifdef _LP64
+ uintptr_t uan_opaque[3];
+#else
+ uintptr_t uan_opaque[4];
+#endif
+} uu_avl_node_t;
+
+typedef struct uu_avl_walk uu_avl_walk_t;
+
+typedef uintptr_t uu_avl_index_t;
+
+/*
+ * avl trees: interface
+ *
+ * basic usage:
+ * typedef struct foo {
+ * ...
+ * uu_avl_node_t foo_node;
+ * ...
+ * } foo_t;
+ *
+ * static int
+ * foo_compare(void *l_arg, void *r_arg, void *private)
+ * {
+ * foo_t *l = l_arg;
+ * foo_t *r = r_arg;
+ *
+ * if (... l greater than r ...)
+ * return (1);
+ * if (... l less than r ...)
+ * return (-1);
+ * return (0);
+ * }
+ *
+ * ...
+ * // at initialization time
+ * foo_pool = uu_avl_pool_create("foo_pool",
+ * sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
+ * debugging? 0 : UU_AVL_POOL_DEBUG);
+ * ...
+ */
+uu_avl_pool_t *uu_avl_pool_create(const char *, size_t, size_t,
+ uu_compare_fn_t *, uint32_t);
+#define UU_AVL_POOL_DEBUG 0x00000001
+
+void uu_avl_pool_destroy(uu_avl_pool_t *);
+
+/*
+ * usage:
+ *
+ * foo_t *a;
+ * a = malloc(sizeof(*a));
+ * uu_avl_node_init(a, &a->foo_avl, pool);
+ * ...
+ * uu_avl_node_fini(a, &a->foo_avl, pool);
+ * free(a);
+ */
+void uu_avl_node_init(void *, uu_avl_node_t *, uu_avl_pool_t *);
+void uu_avl_node_fini(void *, uu_avl_node_t *, uu_avl_pool_t *);
+
+uu_avl_t *uu_avl_create(uu_avl_pool_t *, void *_parent, uint32_t);
+#define UU_AVL_DEBUG 0x00000001
+
+void uu_avl_destroy(uu_avl_t *); /* list must be empty */
+
+size_t uu_avl_numnodes(uu_avl_t *);
+
+void *uu_avl_first(uu_avl_t *);
+void *uu_avl_last(uu_avl_t *);
+
+void *uu_avl_next(uu_avl_t *, void *);
+void *uu_avl_prev(uu_avl_t *, void *);
+
+int uu_avl_walk(uu_avl_t *, uu_walk_fn_t *, void *, uint32_t);
+
+uu_avl_walk_t *uu_avl_walk_start(uu_avl_t *, uint32_t);
+void *uu_avl_walk_next(uu_avl_walk_t *);
+void uu_avl_walk_end(uu_avl_walk_t *);
+
+void *uu_avl_find(uu_avl_t *, void *, void *, uu_avl_index_t *);
+void uu_avl_insert(uu_avl_t *, void *, uu_avl_index_t);
+
+void *uu_avl_nearest_next(uu_avl_t *, uu_avl_index_t);
+void *uu_avl_nearest_prev(uu_avl_t *, uu_avl_index_t);
+
+void *uu_avl_teardown(uu_avl_t *, void **);
+
+void uu_avl_remove(uu_avl_t *, void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBUUTIL_H */
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h b/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h
new file mode 100644
index 000000000000..9ebaaedfd237
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h
@@ -0,0 +1,35 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBUUTIL_COMMON_H
+#define _LIBUUTIL_COMMON_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libuutil.h>
+#include <libuutil_impl.h>
+
+#endif /* _LIBUUTIL_COMMON_H */
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h b/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h
new file mode 100644
index 000000000000..9466e5974581
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBUUTIL_IMPL_H
+#define _LIBUUTIL_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libuutil.h>
+#include <pthread.h>
+
+#include <sys/avl_impl.h>
+#include <sys/byteorder.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void uu_set_error(uint_t);
+#pragma rarely_called(uu_set_error)
+
+/*PRINTFLIKE1*/
+void uu_panic(const char *format, ...);
+#pragma rarely_called(uu_panic)
+
+struct uu_dprintf {
+ char *uud_name;
+ uu_dprintf_severity_t uud_severity;
+ uint_t uud_flags;
+};
+
+/*
+ * For debugging purposes, libuutil keeps around linked lists of all uu_lists
+ * and uu_avls, along with pointers to their parents. These can cause false
+ * negatives when looking for memory leaks, so we encode the pointers by
+ * storing them with swapped endianness; this is not perfect, but it's about
+ * the best we can do without wasting a lot of space.
+ */
+#ifdef _LP64
+#define UU_PTR_ENCODE(ptr) BSWAP_64((uintptr_t)(void *)(ptr))
+#else
+#define UU_PTR_ENCODE(ptr) BSWAP_32((uintptr_t)(void *)(ptr))
+#endif
+
+#define UU_PTR_DECODE(ptr) ((void *)UU_PTR_ENCODE(ptr))
+
+/*
+ * uu_list structures
+ */
+typedef struct uu_list_node_impl {
+ struct uu_list_node_impl *uln_next;
+ struct uu_list_node_impl *uln_prev;
+} uu_list_node_impl_t;
+
+struct uu_list_walk {
+ uu_list_walk_t *ulw_next;
+ uu_list_walk_t *ulw_prev;
+
+ uu_list_t *ulw_list;
+ int8_t ulw_dir;
+ uint8_t ulw_robust;
+ uu_list_node_impl_t *ulw_next_result;
+};
+
+struct uu_list {
+ uintptr_t ul_next_enc;
+ uintptr_t ul_prev_enc;
+
+ uu_list_pool_t *ul_pool;
+ uintptr_t ul_parent_enc; /* encoded parent pointer */
+ size_t ul_offset;
+ size_t ul_numnodes;
+ uint8_t ul_debug;
+ uint8_t ul_sorted;
+ uint8_t ul_index; /* mark for uu_list_index_ts */
+
+ uu_list_node_impl_t ul_null_node;
+ uu_list_walk_t ul_null_walk; /* for robust walkers */
+};
+
+#define UU_LIST_PTR(ptr) ((uu_list_t *)UU_PTR_DECODE(ptr))
+
+#define UU_LIST_POOL_MAXNAME 64
+
+struct uu_list_pool {
+ uu_list_pool_t *ulp_next;
+ uu_list_pool_t *ulp_prev;
+
+ char ulp_name[UU_LIST_POOL_MAXNAME];
+ size_t ulp_nodeoffset;
+ size_t ulp_objsize;
+ uu_compare_fn_t *ulp_cmp;
+ uint8_t ulp_debug;
+ uint8_t ulp_last_index;
+ pthread_mutex_t ulp_lock; /* protects null_list */
+ uu_list_t ulp_null_list;
+};
+
+/*
+ * uu_avl structures
+ */
+typedef struct avl_node uu_avl_node_impl_t;
+
+struct uu_avl_walk {
+ uu_avl_walk_t *uaw_next;
+ uu_avl_walk_t *uaw_prev;
+
+ uu_avl_t *uaw_avl;
+ void *uaw_next_result;
+ int8_t uaw_dir;
+ uint8_t uaw_robust;
+};
+
+struct uu_avl {
+ uintptr_t ua_next_enc;
+ uintptr_t ua_prev_enc;
+
+ uu_avl_pool_t *ua_pool;
+ uintptr_t ua_parent_enc;
+ uint8_t ua_debug;
+ uint8_t ua_index; /* mark for uu_avl_index_ts */
+
+ struct avl_tree ua_tree;
+ uu_avl_walk_t ua_null_walk;
+};
+
+#define UU_AVL_PTR(x) ((uu_avl_t *)UU_PTR_DECODE(x))
+
+#define UU_AVL_POOL_MAXNAME 64
+
+struct uu_avl_pool {
+ uu_avl_pool_t *uap_next;
+ uu_avl_pool_t *uap_prev;
+
+ char uap_name[UU_AVL_POOL_MAXNAME];
+ size_t uap_nodeoffset;
+ size_t uap_objsize;
+ uu_compare_fn_t *uap_cmp;
+ uint8_t uap_debug;
+ uint8_t uap_last_index;
+ pthread_mutex_t uap_lock; /* protects null_avl */
+ uu_avl_t uap_null_avl;
+};
+
+/*
+ * atfork() handlers
+ */
+void uu_avl_lockup(void);
+void uu_avl_release(void);
+
+void uu_list_lockup(void);
+void uu_list_release(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBUUTIL_IMPL_H */
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c
new file mode 100644
index 000000000000..2bef759d525e
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c
@@ -0,0 +1,135 @@
+/*
+ * 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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "libuutil_common.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void *
+uu_zalloc(size_t n)
+{
+ void *p = malloc(n);
+
+ if (p == NULL) {
+ uu_set_error(UU_ERROR_SYSTEM);
+ return (NULL);
+ }
+
+ (void) memset(p, 0, n);
+
+ return (p);
+}
+
+void
+uu_free(void *p)
+{
+ free(p);
+}
+
+char *
+uu_strdup(const char *str)
+{
+ char *buf = NULL;
+
+ if (str != NULL) {
+ size_t sz;
+
+ sz = strlen(str) + 1;
+ buf = uu_zalloc(sz);
+ if (buf != NULL)
+ (void) memcpy(buf, str, sz);
+ }
+ return (buf);
+}
+
+/*
+ * Duplicate up to n bytes of a string. Kind of sort of like
+ * strdup(strlcpy(s, n)).
+ */
+char *
+uu_strndup(const char *s, size_t n)
+{
+ size_t len;
+ char *p;
+
+ len = strnlen(s, n);
+ p = uu_zalloc(len + 1);
+ if (p == NULL)
+ return (NULL);
+
+ if (len > 0)
+ (void) memcpy(p, s, len);
+ p[len] = '\0';
+
+ return (p);
+}
+
+/*
+ * Duplicate a block of memory. Combines malloc with memcpy, much as
+ * strdup combines malloc, strlen, and strcpy.
+ */
+void *
+uu_memdup(const void *buf, size_t sz)
+{
+ void *p;
+
+ p = uu_zalloc(sz);
+ if (p == NULL)
+ return (NULL);
+ (void) memcpy(p, buf, sz);
+ return (p);
+}
+
+char *
+uu_msprintf(const char *format, ...)
+{
+ va_list args;
+ char attic[1];
+ uint_t M, m;
+ char *b;
+
+ va_start(args, format);
+ M = vsnprintf(attic, 1, format, args);
+ va_end(args);
+
+ for (;;) {
+ m = M;
+ if ((b = uu_zalloc(m + 1)) == NULL)
+ return (NULL);
+
+ va_start(args, format);
+ M = vsnprintf(b, m + 1, format, args);
+ va_end(args);
+
+ if (M == m)
+ break; /* sizes match */
+
+ uu_free(b);
+ }
+
+ return (b);
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c
new file mode 100644
index 000000000000..5e78ececeec9
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c
@@ -0,0 +1,570 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/avl.h>
+
+static uu_avl_pool_t uu_null_apool = { &uu_null_apool, &uu_null_apool };
+static pthread_mutex_t uu_apool_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * The index mark change on every insert and delete, to catch stale
+ * references.
+ *
+ * We leave the low bit alone, since the avl code uses it.
+ */
+#define INDEX_MAX (sizeof (uintptr_t) - 2)
+#define INDEX_NEXT(m) (((m) == INDEX_MAX)? 2 : ((m) + 2) & INDEX_MAX)
+
+#define INDEX_DECODE(i) ((i) & ~INDEX_MAX)
+#define INDEX_ENCODE(p, n) (((n) & ~INDEX_MAX) | (p)->ua_index)
+#define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ua_index)
+#define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0)
+
+/*
+ * When an element is inactive (not in a tree), we keep a marked pointer to
+ * its containing pool in its first word, and a NULL pointer in its second.
+ *
+ * On insert, we use these to verify that it comes from the correct pool.
+ */
+#define NODE_ARRAY(p, n) ((uintptr_t *)((uintptr_t)(n) + \
+ (pp)->uap_nodeoffset))
+
+#define POOL_TO_MARKER(pp) (((uintptr_t)(pp) | 1))
+
+#define DEAD_MARKER 0xc4
+
+uu_avl_pool_t *
+uu_avl_pool_create(const char *name, size_t objsize, size_t nodeoffset,
+ uu_compare_fn_t *compare_func, uint32_t flags)
+{
+ uu_avl_pool_t *pp, *next, *prev;
+
+ if (name == NULL ||
+ uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
+ nodeoffset + sizeof (uu_avl_node_t) > objsize ||
+ compare_func == NULL) {
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (NULL);
+ }
+
+ if (flags & ~UU_AVL_POOL_DEBUG) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ pp = uu_zalloc(sizeof (uu_avl_pool_t));
+ if (pp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ (void) strlcpy(pp->uap_name, name, sizeof (pp->uap_name));
+ pp->uap_nodeoffset = nodeoffset;
+ pp->uap_objsize = objsize;
+ pp->uap_cmp = compare_func;
+ if (flags & UU_AVL_POOL_DEBUG)
+ pp->uap_debug = 1;
+ pp->uap_last_index = 0;
+
+ (void) pthread_mutex_init(&pp->uap_lock, NULL);
+
+ pp->uap_null_avl.ua_next_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
+ pp->uap_null_avl.ua_prev_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
+
+ (void) pthread_mutex_lock(&uu_apool_list_lock);
+ pp->uap_next = next = &uu_null_apool;
+ pp->uap_prev = prev = next->uap_prev;
+ next->uap_prev = pp;
+ prev->uap_next = pp;
+ (void) pthread_mutex_unlock(&uu_apool_list_lock);
+
+ return (pp);
+}
+
+void
+uu_avl_pool_destroy(uu_avl_pool_t *pp)
+{
+ if (pp->uap_debug) {
+ if (pp->uap_null_avl.ua_next_enc !=
+ UU_PTR_ENCODE(&pp->uap_null_avl) ||
+ pp->uap_null_avl.ua_prev_enc !=
+ UU_PTR_ENCODE(&pp->uap_null_avl)) {
+ uu_panic("uu_avl_pool_destroy: Pool \"%.*s\" (%p) has "
+ "outstanding avls, or is corrupt.\n",
+ (int)sizeof (pp->uap_name), pp->uap_name,
+ (void *)pp);
+ }
+ }
+ (void) pthread_mutex_lock(&uu_apool_list_lock);
+ pp->uap_next->uap_prev = pp->uap_prev;
+ pp->uap_prev->uap_next = pp->uap_next;
+ (void) pthread_mutex_unlock(&uu_apool_list_lock);
+ (void) pthread_mutex_destroy(&pp->uap_lock);
+ pp->uap_prev = NULL;
+ pp->uap_next = NULL;
+ uu_free(pp);
+}
+
+void
+uu_avl_node_init(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
+{
+ uintptr_t *na = (uintptr_t *)np;
+
+ if (pp->uap_debug) {
+ uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
+ if (offset + sizeof (*np) > pp->uap_objsize) {
+ uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
+ "offset %ld doesn't fit in object (size %ld)\n",
+ base, (void *)np, (void *)pp, pp->uap_name,
+ (long)offset, (long)pp->uap_objsize);
+ }
+ if (offset != pp->uap_nodeoffset) {
+ uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
+ "offset %ld doesn't match pool's offset (%ld)\n",
+ base, (void *)np, (void *)pp, pp->uap_name,
+ (long)offset, (long)pp->uap_objsize);
+ }
+ }
+
+ na[0] = POOL_TO_MARKER(pp);
+ na[1] = 0;
+}
+
+void
+uu_avl_node_fini(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
+{
+ uintptr_t *na = (uintptr_t *)np;
+
+ if (pp->uap_debug) {
+ if (na[0] == DEAD_MARKER && na[1] == DEAD_MARKER) {
+ uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
+ "node already finied\n",
+ base, (void *)np, (void *)pp, pp->uap_name);
+ }
+ if (na[0] != POOL_TO_MARKER(pp) || na[1] != 0) {
+ uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
+ "node corrupt, in tree, or in different pool\n",
+ base, (void *)np, (void *)pp, pp->uap_name);
+ }
+ }
+
+ na[0] = DEAD_MARKER;
+ na[1] = DEAD_MARKER;
+ na[2] = DEAD_MARKER;
+}
+
+struct uu_avl_node_compare_info {
+ uu_compare_fn_t *ac_compare;
+ void *ac_private;
+ void *ac_right;
+ void *ac_found;
+};
+
+static int
+uu_avl_node_compare(const void *l, const void *r)
+{
+ struct uu_avl_node_compare_info *info =
+ (struct uu_avl_node_compare_info *)l;
+
+ int res = info->ac_compare(r, info->ac_right, info->ac_private);
+
+ if (res == 0) {
+ if (info->ac_found == NULL)
+ info->ac_found = (void *)r;
+ return (-1);
+ }
+ if (res < 0)
+ return (1);
+ return (-1);
+}
+
+uu_avl_t *
+uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags)
+{
+ uu_avl_t *ap, *next, *prev;
+
+ if (flags & ~UU_AVL_DEBUG) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ ap = uu_zalloc(sizeof (*ap));
+ if (ap == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ ap->ua_pool = pp;
+ ap->ua_parent_enc = UU_PTR_ENCODE(parent);
+ ap->ua_debug = pp->uap_debug || (flags & UU_AVL_DEBUG);
+ ap->ua_index = (pp->uap_last_index = INDEX_NEXT(pp->uap_last_index));
+
+ avl_create(&ap->ua_tree, &uu_avl_node_compare, pp->uap_objsize,
+ pp->uap_nodeoffset);
+
+ ap->ua_null_walk.uaw_next = &ap->ua_null_walk;
+ ap->ua_null_walk.uaw_prev = &ap->ua_null_walk;
+
+ (void) pthread_mutex_lock(&pp->uap_lock);
+ next = &pp->uap_null_avl;
+ prev = UU_PTR_DECODE(next->ua_prev_enc);
+ ap->ua_next_enc = UU_PTR_ENCODE(next);
+ ap->ua_prev_enc = UU_PTR_ENCODE(prev);
+ next->ua_prev_enc = UU_PTR_ENCODE(ap);
+ prev->ua_next_enc = UU_PTR_ENCODE(ap);
+ (void) pthread_mutex_unlock(&pp->uap_lock);
+
+ return (ap);
+}
+
+void
+uu_avl_destroy(uu_avl_t *ap)
+{
+ uu_avl_pool_t *pp = ap->ua_pool;
+
+ if (ap->ua_debug) {
+ if (avl_numnodes(&ap->ua_tree) != 0) {
+ uu_panic("uu_avl_destroy(%p): tree not empty\n",
+ (void *)ap);
+ }
+ if (ap->ua_null_walk.uaw_next != &ap->ua_null_walk ||
+ ap->ua_null_walk.uaw_prev != &ap->ua_null_walk) {
+ uu_panic("uu_avl_destroy(%p): outstanding walkers\n",
+ (void *)ap);
+ }
+ }
+ (void) pthread_mutex_lock(&pp->uap_lock);
+ UU_AVL_PTR(ap->ua_next_enc)->ua_prev_enc = ap->ua_prev_enc;
+ UU_AVL_PTR(ap->ua_prev_enc)->ua_next_enc = ap->ua_next_enc;
+ (void) pthread_mutex_unlock(&pp->uap_lock);
+ ap->ua_prev_enc = UU_PTR_ENCODE(NULL);
+ ap->ua_next_enc = UU_PTR_ENCODE(NULL);
+
+ ap->ua_pool = NULL;
+ avl_destroy(&ap->ua_tree);
+
+ uu_free(ap);
+}
+
+size_t
+uu_avl_numnodes(uu_avl_t *ap)
+{
+ return (avl_numnodes(&ap->ua_tree));
+}
+
+void *
+uu_avl_first(uu_avl_t *ap)
+{
+ return (avl_first(&ap->ua_tree));
+}
+
+void *
+uu_avl_last(uu_avl_t *ap)
+{
+ return (avl_last(&ap->ua_tree));
+}
+
+void *
+uu_avl_next(uu_avl_t *ap, void *node)
+{
+ return (AVL_NEXT(&ap->ua_tree, node));
+}
+
+void *
+uu_avl_prev(uu_avl_t *ap, void *node)
+{
+ return (AVL_PREV(&ap->ua_tree, node));
+}
+
+static void
+_avl_walk_init(uu_avl_walk_t *wp, uu_avl_t *ap, uint32_t flags)
+{
+ uu_avl_walk_t *next, *prev;
+
+ int robust = (flags & UU_WALK_ROBUST);
+ int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
+
+ (void) memset(wp, 0, sizeof (*wp));
+ wp->uaw_avl = ap;
+ wp->uaw_robust = robust;
+ wp->uaw_dir = direction;
+
+ if (direction > 0)
+ wp->uaw_next_result = avl_first(&ap->ua_tree);
+ else
+ wp->uaw_next_result = avl_last(&ap->ua_tree);
+
+ if (ap->ua_debug || robust) {
+ wp->uaw_next = next = &ap->ua_null_walk;
+ wp->uaw_prev = prev = next->uaw_prev;
+ next->uaw_prev = wp;
+ prev->uaw_next = wp;
+ }
+}
+
+static void *
+_avl_walk_advance(uu_avl_walk_t *wp, uu_avl_t *ap)
+{
+ void *np = wp->uaw_next_result;
+
+ avl_tree_t *t = &ap->ua_tree;
+
+ if (np == NULL)
+ return (NULL);
+
+ wp->uaw_next_result = (wp->uaw_dir > 0)? AVL_NEXT(t, np) :
+ AVL_PREV(t, np);
+
+ return (np);
+}
+
+static void
+_avl_walk_fini(uu_avl_walk_t *wp)
+{
+ if (wp->uaw_next != NULL) {
+ wp->uaw_next->uaw_prev = wp->uaw_prev;
+ wp->uaw_prev->uaw_next = wp->uaw_next;
+ wp->uaw_next = NULL;
+ wp->uaw_prev = NULL;
+ }
+ wp->uaw_avl = NULL;
+ wp->uaw_next_result = NULL;
+}
+
+uu_avl_walk_t *
+uu_avl_walk_start(uu_avl_t *ap, uint32_t flags)
+{
+ uu_avl_walk_t *wp;
+
+ if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ wp = uu_zalloc(sizeof (*wp));
+ if (wp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ _avl_walk_init(wp, ap, flags);
+ return (wp);
+}
+
+void *
+uu_avl_walk_next(uu_avl_walk_t *wp)
+{
+ return (_avl_walk_advance(wp, wp->uaw_avl));
+}
+
+void
+uu_avl_walk_end(uu_avl_walk_t *wp)
+{
+ _avl_walk_fini(wp);
+ uu_free(wp);
+}
+
+int
+uu_avl_walk(uu_avl_t *ap, uu_walk_fn_t *func, void *private, uint32_t flags)
+{
+ void *e;
+ uu_avl_walk_t my_walk;
+
+ int status = UU_WALK_NEXT;
+
+ if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (-1);
+ }
+
+ _avl_walk_init(&my_walk, ap, flags);
+ while (status == UU_WALK_NEXT &&
+ (e = _avl_walk_advance(&my_walk, ap)) != NULL)
+ status = (*func)(e, private);
+ _avl_walk_fini(&my_walk);
+
+ if (status >= 0)
+ return (0);
+ uu_set_error(UU_ERROR_CALLBACK_FAILED);
+ return (-1);
+}
+
+void
+uu_avl_remove(uu_avl_t *ap, void *elem)
+{
+ uu_avl_walk_t *wp;
+ uu_avl_pool_t *pp = ap->ua_pool;
+ uintptr_t *na = NODE_ARRAY(pp, elem);
+
+ if (ap->ua_debug) {
+ /*
+ * invalidate outstanding uu_avl_index_ts.
+ */
+ ap->ua_index = INDEX_NEXT(ap->ua_index);
+ }
+
+ /*
+ * Robust walkers most be advanced, if we are removing the node
+ * they are currently using. In debug mode, non-robust walkers
+ * are also on the walker list.
+ */
+ for (wp = ap->ua_null_walk.uaw_next; wp != &ap->ua_null_walk;
+ wp = wp->uaw_next) {
+ if (wp->uaw_robust) {
+ if (elem == wp->uaw_next_result)
+ (void) _avl_walk_advance(wp, ap);
+ } else if (wp->uaw_next_result != NULL) {
+ uu_panic("uu_avl_remove(%p, %p): active non-robust "
+ "walker\n", (void *)ap, elem);
+ }
+ }
+
+ avl_remove(&ap->ua_tree, elem);
+
+ na[0] = POOL_TO_MARKER(pp);
+ na[1] = 0;
+}
+
+void *
+uu_avl_teardown(uu_avl_t *ap, void **cookie)
+{
+ void *elem = avl_destroy_nodes(&ap->ua_tree, cookie);
+
+ if (elem != NULL) {
+ uu_avl_pool_t *pp = ap->ua_pool;
+ uintptr_t *na = NODE_ARRAY(pp, elem);
+
+ na[0] = POOL_TO_MARKER(pp);
+ na[1] = 0;
+ }
+ return (elem);
+}
+
+void *
+uu_avl_find(uu_avl_t *ap, void *elem, void *private, uu_avl_index_t *out)
+{
+ struct uu_avl_node_compare_info info;
+ void *result;
+
+ info.ac_compare = ap->ua_pool->uap_cmp;
+ info.ac_private = private;
+ info.ac_right = elem;
+ info.ac_found = NULL;
+
+ result = avl_find(&ap->ua_tree, &info, out);
+ if (out != NULL)
+ *out = INDEX_ENCODE(ap, *out);
+
+ if (ap->ua_debug && result != NULL)
+ uu_panic("uu_avl_find: internal error: avl_find succeeded\n");
+
+ return (info.ac_found);
+}
+
+void
+uu_avl_insert(uu_avl_t *ap, void *elem, uu_avl_index_t idx)
+{
+ if (ap->ua_debug) {
+ uu_avl_pool_t *pp = ap->ua_pool;
+ uintptr_t *na = NODE_ARRAY(pp, elem);
+
+ if (na[1] != 0)
+ uu_panic("uu_avl_insert(%p, %p, %p): node already "
+ "in tree, or corrupt\n",
+ (void *)ap, elem, (void *)idx);
+ if (na[0] == 0)
+ uu_panic("uu_avl_insert(%p, %p, %p): node not "
+ "initialized\n",
+ (void *)ap, elem, (void *)idx);
+ if (na[0] != POOL_TO_MARKER(pp))
+ uu_panic("uu_avl_insert(%p, %p, %p): node from "
+ "other pool, or corrupt\n",
+ (void *)ap, elem, (void *)idx);
+
+ if (!INDEX_VALID(ap, idx))
+ uu_panic("uu_avl_insert(%p, %p, %p): %s\n",
+ (void *)ap, elem, (void *)idx,
+ INDEX_CHECK(idx)? "outdated index" :
+ "invalid index");
+
+ /*
+ * invalidate outstanding uu_avl_index_ts.
+ */
+ ap->ua_index = INDEX_NEXT(ap->ua_index);
+ }
+ avl_insert(&ap->ua_tree, elem, INDEX_DECODE(idx));
+}
+
+void *
+uu_avl_nearest_next(uu_avl_t *ap, uu_avl_index_t idx)
+{
+ if (ap->ua_debug && !INDEX_VALID(ap, idx))
+ uu_panic("uu_avl_nearest_next(%p, %p): %s\n",
+ (void *)ap, (void *)idx, INDEX_CHECK(idx)?
+ "outdated index" : "invalid index");
+ return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_AFTER));
+}
+
+void *
+uu_avl_nearest_prev(uu_avl_t *ap, uu_avl_index_t idx)
+{
+ if (ap->ua_debug && !INDEX_VALID(ap, idx))
+ uu_panic("uu_avl_nearest_prev(%p, %p): %s\n",
+ (void *)ap, (void *)idx, INDEX_CHECK(idx)?
+ "outdated index" : "invalid index");
+ return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_BEFORE));
+}
+
+/*
+ * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
+ */
+void
+uu_avl_lockup(void)
+{
+ uu_avl_pool_t *pp;
+
+ (void) pthread_mutex_lock(&uu_apool_list_lock);
+ for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
+ pp = pp->uap_next)
+ (void) pthread_mutex_lock(&pp->uap_lock);
+}
+
+void
+uu_avl_release(void)
+{
+ uu_avl_pool_t *pp;
+
+ for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
+ pp = pp->uap_next)
+ (void) pthread_mutex_unlock(&pp->uap_lock);
+ (void) pthread_mutex_unlock(&uu_apool_list_lock);
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c
new file mode 100644
index 000000000000..528c3e7f6d25
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <errno.h>
+#include <libintl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define FACILITY_FMT "%s (%s): "
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+static const char *
+strseverity(uu_dprintf_severity_t severity)
+{
+ switch (severity) {
+ case UU_DPRINTF_SILENT:
+ return (dgettext(TEXT_DOMAIN, "silent"));
+ case UU_DPRINTF_FATAL:
+ return (dgettext(TEXT_DOMAIN, "FATAL"));
+ case UU_DPRINTF_WARNING:
+ return (dgettext(TEXT_DOMAIN, "WARNING"));
+ case UU_DPRINTF_NOTICE:
+ return (dgettext(TEXT_DOMAIN, "note"));
+ case UU_DPRINTF_INFO:
+ return (dgettext(TEXT_DOMAIN, "info"));
+ case UU_DPRINTF_DEBUG:
+ return (dgettext(TEXT_DOMAIN, "debug"));
+ default:
+ return (dgettext(TEXT_DOMAIN, "unspecified"));
+ }
+}
+
+uu_dprintf_t *
+uu_dprintf_create(const char *name, uu_dprintf_severity_t severity,
+ uint_t flags)
+{
+ uu_dprintf_t *D;
+
+ if (uu_check_name(name, UU_NAME_DOMAIN) == -1) {
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (NULL);
+ }
+
+ if ((D = uu_zalloc(sizeof (uu_dprintf_t))) == NULL)
+ return (NULL);
+
+ if (name != NULL) {
+ D->uud_name = strdup(name);
+ if (D->uud_name == NULL) {
+ uu_free(D);
+ return (NULL);
+ }
+ } else {
+ D->uud_name = NULL;
+ }
+
+ D->uud_severity = severity;
+ D->uud_flags = flags;
+
+ return (D);
+}
+
+/*PRINTFLIKE3*/
+void
+uu_dprintf(uu_dprintf_t *D, uu_dprintf_severity_t severity,
+ const char *format, ...)
+{
+ va_list alist;
+
+ /* XXX Assert that severity is not UU_DPRINTF_SILENT. */
+
+ if (severity > D->uud_severity)
+ return;
+
+ (void) fprintf(stderr, FACILITY_FMT, D->uud_name,
+ strseverity(severity));
+
+ va_start(alist, format);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+}
+
+void
+uu_dprintf_destroy(uu_dprintf_t *D)
+{
+ if (D->uud_name)
+ free(D->uud_name);
+
+ uu_free(D);
+}
+
+const char *
+uu_dprintf_getname(uu_dprintf_t *D)
+{
+ return (D->uud_name);
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c
new file mode 100644
index 000000000000..9a643845f8c2
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <string.h>
+
+/*
+ * We require names of the form:
+ * [provider,]identifier[/[provider,]identifier]...
+ *
+ * Where provider is either a stock symbol (SUNW) or a java-style reversed
+ * domain name (com.sun).
+ *
+ * Both providers and identifiers must start with a letter, and may
+ * only contain alphanumerics, dashes, and underlines. Providers
+ * may also contain periods.
+ *
+ * Note that we do _not_ use the macros in <ctype.h>, since they are affected
+ * by the current locale settings.
+ */
+
+#define IS_ALPHA(c) \
+ (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
+
+#define IS_DIGIT(c) \
+ ((c) >= '0' && (c) <= '9')
+
+static int
+is_valid_ident(const char *s, const char *e, int allowdot)
+{
+ char c;
+
+ if (s >= e)
+ return (0); /* name is empty */
+
+ c = *s++;
+ if (!IS_ALPHA(c))
+ return (0); /* does not start with letter */
+
+ while (s < e && (c = *s++) != 0) {
+ if (IS_ALPHA(c) || IS_DIGIT(c) || c == '-' || c == '_' ||
+ (allowdot && c == '.'))
+ continue;
+ return (0); /* invalid character */
+ }
+ return (1);
+}
+
+static int
+is_valid_component(const char *b, const char *e, uint_t flags)
+{
+ char *sp;
+
+ if (flags & UU_NAME_DOMAIN) {
+ sp = strchr(b, ',');
+ if (sp != NULL && sp < e) {
+ if (!is_valid_ident(b, sp, 1))
+ return (0);
+ b = sp + 1;
+ }
+ }
+
+ return (is_valid_ident(b, e, 0));
+}
+
+int
+uu_check_name(const char *name, uint_t flags)
+{
+ const char *end = name + strlen(name);
+ const char *p;
+
+ if (flags & ~(UU_NAME_DOMAIN | UU_NAME_PATH)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (-1);
+ }
+
+ if (!(flags & UU_NAME_PATH)) {
+ if (!is_valid_component(name, end, flags))
+ goto bad;
+ return (0);
+ }
+
+ while ((p = strchr(name, '/')) != NULL) {
+ if (!is_valid_component(name, p - 1, flags))
+ goto bad;
+ name = p + 1;
+ }
+ if (!is_valid_component(name, end, flags))
+ goto bad;
+
+ return (0);
+
+bad:
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (-1);
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c
new file mode 100644
index 000000000000..35c7ba800103
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c
@@ -0,0 +1,718 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#define ELEM_TO_NODE(lp, e) \
+ ((uu_list_node_impl_t *)((uintptr_t)(e) + (lp)->ul_offset))
+
+#define NODE_TO_ELEM(lp, n) \
+ ((void *)((uintptr_t)(n) - (lp)->ul_offset))
+
+/*
+ * uu_list_index_ts define a location for insertion. They are simply a
+ * pointer to the object after the insertion point. We store a mark
+ * in the low-bits of the index, to help prevent mistakes.
+ *
+ * When debugging, the index mark changes on every insert and delete, to
+ * catch stale references.
+ */
+#define INDEX_MAX (sizeof (uintptr_t) - 1)
+#define INDEX_NEXT(m) (((m) == INDEX_MAX)? 1 : ((m) + 1) & INDEX_MAX)
+
+#define INDEX_TO_NODE(i) ((uu_list_node_impl_t *)((i) & ~INDEX_MAX))
+#define NODE_TO_INDEX(p, n) (((uintptr_t)(n) & ~INDEX_MAX) | (p)->ul_index)
+#define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ul_index)
+#define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0)
+
+#define POOL_TO_MARKER(pp) ((void *)((uintptr_t)(pp) | 1))
+
+static uu_list_pool_t uu_null_lpool = { &uu_null_lpool, &uu_null_lpool };
+static pthread_mutex_t uu_lpool_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+uu_list_pool_t *
+uu_list_pool_create(const char *name, size_t objsize,
+ size_t nodeoffset, uu_compare_fn_t *compare_func, uint32_t flags)
+{
+ uu_list_pool_t *pp, *next, *prev;
+
+ if (name == NULL ||
+ uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
+ nodeoffset + sizeof (uu_list_node_t) > objsize) {
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (NULL);
+ }
+
+ if (flags & ~UU_LIST_POOL_DEBUG) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ pp = uu_zalloc(sizeof (uu_list_pool_t));
+ if (pp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ (void) strlcpy(pp->ulp_name, name, sizeof (pp->ulp_name));
+ pp->ulp_nodeoffset = nodeoffset;
+ pp->ulp_objsize = objsize;
+ pp->ulp_cmp = compare_func;
+ if (flags & UU_LIST_POOL_DEBUG)
+ pp->ulp_debug = 1;
+ pp->ulp_last_index = 0;
+
+ (void) pthread_mutex_init(&pp->ulp_lock, NULL);
+
+ pp->ulp_null_list.ul_next_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
+ pp->ulp_null_list.ul_prev_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
+
+ (void) pthread_mutex_lock(&uu_lpool_list_lock);
+ pp->ulp_next = next = &uu_null_lpool;
+ pp->ulp_prev = prev = next->ulp_prev;
+ next->ulp_prev = pp;
+ prev->ulp_next = pp;
+ (void) pthread_mutex_unlock(&uu_lpool_list_lock);
+
+ return (pp);
+}
+
+void
+uu_list_pool_destroy(uu_list_pool_t *pp)
+{
+ if (pp->ulp_debug) {
+ if (pp->ulp_null_list.ul_next_enc !=
+ UU_PTR_ENCODE(&pp->ulp_null_list) ||
+ pp->ulp_null_list.ul_prev_enc !=
+ UU_PTR_ENCODE(&pp->ulp_null_list)) {
+ uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has "
+ "outstanding lists, or is corrupt.\n",
+ (int)sizeof (pp->ulp_name), pp->ulp_name,
+ (void *)pp);
+ }
+ }
+ (void) pthread_mutex_lock(&uu_lpool_list_lock);
+ pp->ulp_next->ulp_prev = pp->ulp_prev;
+ pp->ulp_prev->ulp_next = pp->ulp_next;
+ (void) pthread_mutex_unlock(&uu_lpool_list_lock);
+ pp->ulp_prev = NULL;
+ pp->ulp_next = NULL;
+ uu_free(pp);
+}
+
+void
+uu_list_node_init(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
+{
+ uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
+
+ if (pp->ulp_debug) {
+ uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
+ if (offset + sizeof (*np) > pp->ulp_objsize) {
+ uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
+ "offset %ld doesn't fit in object (size %ld)\n",
+ base, (void *)np, (void *)pp, pp->ulp_name,
+ (long)offset, (long)pp->ulp_objsize);
+ }
+ if (offset != pp->ulp_nodeoffset) {
+ uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
+ "offset %ld doesn't match pool's offset (%ld)\n",
+ base, (void *)np, (void *)pp, pp->ulp_name,
+ (long)offset, (long)pp->ulp_objsize);
+ }
+ }
+ np->uln_next = POOL_TO_MARKER(pp);
+ np->uln_prev = NULL;
+}
+
+void
+uu_list_node_fini(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
+{
+ uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
+
+ if (pp->ulp_debug) {
+ if (np->uln_next == NULL &&
+ np->uln_prev == NULL) {
+ uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
+ "node already finied\n",
+ base, (void *)np_arg, (void *)pp, pp->ulp_name);
+ }
+ if (np->uln_next != POOL_TO_MARKER(pp) ||
+ np->uln_prev != NULL) {
+ uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
+ "node corrupt or on list\n",
+ base, (void *)np_arg, (void *)pp, pp->ulp_name);
+ }
+ }
+ np->uln_next = NULL;
+ np->uln_prev = NULL;
+}
+
+uu_list_t *
+uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
+{
+ uu_list_t *lp, *next, *prev;
+
+ if (flags & ~(UU_LIST_DEBUG | UU_LIST_SORTED)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ if ((flags & UU_LIST_SORTED) && pp->ulp_cmp == NULL) {
+ if (pp->ulp_debug)
+ uu_panic("uu_list_create(%p, ...): requested "
+ "UU_LIST_SORTED, but pool has no comparison func\n",
+ (void *)pp);
+ uu_set_error(UU_ERROR_NOT_SUPPORTED);
+ return (NULL);
+ }
+
+ lp = uu_zalloc(sizeof (*lp));
+ if (lp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ lp->ul_pool = pp;
+ lp->ul_parent_enc = UU_PTR_ENCODE(parent);
+ lp->ul_offset = pp->ulp_nodeoffset;
+ lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG);
+ lp->ul_sorted = (flags & UU_LIST_SORTED);
+ lp->ul_numnodes = 0;
+ lp->ul_index = (pp->ulp_last_index = INDEX_NEXT(pp->ulp_last_index));
+
+ lp->ul_null_node.uln_next = &lp->ul_null_node;
+ lp->ul_null_node.uln_prev = &lp->ul_null_node;
+
+ lp->ul_null_walk.ulw_next = &lp->ul_null_walk;
+ lp->ul_null_walk.ulw_prev = &lp->ul_null_walk;
+
+ (void) pthread_mutex_lock(&pp->ulp_lock);
+ next = &pp->ulp_null_list;
+ prev = UU_PTR_DECODE(next->ul_prev_enc);
+ lp->ul_next_enc = UU_PTR_ENCODE(next);
+ lp->ul_prev_enc = UU_PTR_ENCODE(prev);
+ next->ul_prev_enc = UU_PTR_ENCODE(lp);
+ prev->ul_next_enc = UU_PTR_ENCODE(lp);
+ (void) pthread_mutex_unlock(&pp->ulp_lock);
+
+ return (lp);
+}
+
+void
+uu_list_destroy(uu_list_t *lp)
+{
+ uu_list_pool_t *pp = lp->ul_pool;
+
+ if (lp->ul_debug) {
+ if (lp->ul_null_node.uln_next != &lp->ul_null_node ||
+ lp->ul_null_node.uln_prev != &lp->ul_null_node) {
+ uu_panic("uu_list_destroy(%p): list not empty\n",
+ (void *)lp);
+ }
+ if (lp->ul_numnodes != 0) {
+ uu_panic("uu_list_destroy(%p): numnodes is nonzero, "
+ "but list is empty\n", (void *)lp);
+ }
+ if (lp->ul_null_walk.ulw_next != &lp->ul_null_walk ||
+ lp->ul_null_walk.ulw_prev != &lp->ul_null_walk) {
+ uu_panic("uu_list_destroy(%p): outstanding walkers\n",
+ (void *)lp);
+ }
+ }
+
+ (void) pthread_mutex_lock(&pp->ulp_lock);
+ UU_LIST_PTR(lp->ul_next_enc)->ul_prev_enc = lp->ul_prev_enc;
+ UU_LIST_PTR(lp->ul_prev_enc)->ul_next_enc = lp->ul_next_enc;
+ (void) pthread_mutex_unlock(&pp->ulp_lock);
+ lp->ul_prev_enc = UU_PTR_ENCODE(NULL);
+ lp->ul_next_enc = UU_PTR_ENCODE(NULL);
+ lp->ul_pool = NULL;
+ uu_free(lp);
+}
+
+static void
+list_insert(uu_list_t *lp, uu_list_node_impl_t *np, uu_list_node_impl_t *prev,
+ uu_list_node_impl_t *next)
+{
+ if (lp->ul_debug) {
+ if (next->uln_prev != prev || prev->uln_next != next)
+ uu_panic("insert(%p): internal error: %p and %p not "
+ "neighbors\n", (void *)lp, (void *)next,
+ (void *)prev);
+
+ if (np->uln_next != POOL_TO_MARKER(lp->ul_pool) ||
+ np->uln_prev != NULL) {
+ uu_panic("insert(%p): elem %p node %p corrupt, "
+ "not initialized, or already in a list.\n",
+ (void *)lp, NODE_TO_ELEM(lp, np), (void *)np);
+ }
+ /*
+ * invalidate outstanding uu_list_index_ts.
+ */
+ lp->ul_index = INDEX_NEXT(lp->ul_index);
+ }
+ np->uln_next = next;
+ np->uln_prev = prev;
+ next->uln_prev = np;
+ prev->uln_next = np;
+
+ lp->ul_numnodes++;
+}
+
+void
+uu_list_insert(uu_list_t *lp, void *elem, uu_list_index_t idx)
+{
+ uu_list_node_impl_t *np;
+
+ np = INDEX_TO_NODE(idx);
+ if (np == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (!INDEX_VALID(lp, idx))
+ uu_panic("uu_list_insert(%p, %p, %p): %s\n",
+ (void *)lp, elem, (void *)idx,
+ INDEX_CHECK(idx)? "outdated index" :
+ "invalid index");
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_insert(%p, %p, %p): out-of-date "
+ "index\n", (void *)lp, elem, (void *)idx);
+ }
+
+ list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
+}
+
+void *
+uu_list_find(uu_list_t *lp, void *elem, void *private, uu_list_index_t *out)
+{
+ int sorted = lp->ul_sorted;
+ uu_compare_fn_t *func = lp->ul_pool->ulp_cmp;
+ uu_list_node_impl_t *np;
+
+ if (func == NULL) {
+ if (out != NULL)
+ *out = 0;
+ uu_set_error(UU_ERROR_NOT_SUPPORTED);
+ return (NULL);
+ }
+ for (np = lp->ul_null_node.uln_next; np != &lp->ul_null_node;
+ np = np->uln_next) {
+ void *ep = NODE_TO_ELEM(lp, np);
+ int cmp = func(ep, elem, private);
+ if (cmp == 0) {
+ if (out != NULL)
+ *out = NODE_TO_INDEX(lp, np);
+ return (ep);
+ }
+ if (sorted && cmp > 0) {
+ if (out != NULL)
+ *out = NODE_TO_INDEX(lp, np);
+ return (NULL);
+ }
+ }
+ if (out != NULL)
+ *out = NODE_TO_INDEX(lp, 0);
+ return (NULL);
+}
+
+void *
+uu_list_nearest_next(uu_list_t *lp, uu_list_index_t idx)
+{
+ uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
+
+ if (np == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (!INDEX_VALID(lp, idx))
+ uu_panic("uu_list_nearest_next(%p, %p): %s\n",
+ (void *)lp, (void *)idx,
+ INDEX_CHECK(idx)? "outdated index" :
+ "invalid index");
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_nearest_next(%p, %p): out-of-date "
+ "index\n", (void *)lp, (void *)idx);
+ }
+
+ if (np == &lp->ul_null_node)
+ return (NULL);
+ else
+ return (NODE_TO_ELEM(lp, np));
+}
+
+void *
+uu_list_nearest_prev(uu_list_t *lp, uu_list_index_t idx)
+{
+ uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
+
+ if (np == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (!INDEX_VALID(lp, idx))
+ uu_panic("uu_list_nearest_prev(%p, %p): %s\n",
+ (void *)lp, (void *)idx, INDEX_CHECK(idx)?
+ "outdated index" : "invalid index");
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_nearest_prev(%p, %p): out-of-date "
+ "index\n", (void *)lp, (void *)idx);
+ }
+
+ if ((np = np->uln_prev) == &lp->ul_null_node)
+ return (NULL);
+ else
+ return (NODE_TO_ELEM(lp, np));
+}
+
+static void
+list_walk_init(uu_list_walk_t *wp, uu_list_t *lp, uint32_t flags)
+{
+ uu_list_walk_t *next, *prev;
+
+ int robust = (flags & UU_WALK_ROBUST);
+ int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
+
+ (void) memset(wp, 0, sizeof (*wp));
+ wp->ulw_list = lp;
+ wp->ulw_robust = robust;
+ wp->ulw_dir = direction;
+ if (direction > 0)
+ wp->ulw_next_result = lp->ul_null_node.uln_next;
+ else
+ wp->ulw_next_result = lp->ul_null_node.uln_prev;
+
+ if (lp->ul_debug || robust) {
+ /*
+ * Add this walker to the list's list of walkers so
+ * uu_list_remove() can advance us if somebody tries to
+ * remove ulw_next_result.
+ */
+ wp->ulw_next = next = &lp->ul_null_walk;
+ wp->ulw_prev = prev = next->ulw_prev;
+ next->ulw_prev = wp;
+ prev->ulw_next = wp;
+ }
+}
+
+static uu_list_node_impl_t *
+list_walk_advance(uu_list_walk_t *wp, uu_list_t *lp)
+{
+ uu_list_node_impl_t *np = wp->ulw_next_result;
+ uu_list_node_impl_t *next;
+
+ if (np == &lp->ul_null_node)
+ return (NULL);
+
+ next = (wp->ulw_dir > 0)? np->uln_next : np->uln_prev;
+
+ wp->ulw_next_result = next;
+ return (np);
+}
+
+static void
+list_walk_fini(uu_list_walk_t *wp)
+{
+ /* GLXXX debugging? */
+ if (wp->ulw_next != NULL) {
+ wp->ulw_next->ulw_prev = wp->ulw_prev;
+ wp->ulw_prev->ulw_next = wp->ulw_next;
+ wp->ulw_next = NULL;
+ wp->ulw_prev = NULL;
+ }
+ wp->ulw_list = NULL;
+ wp->ulw_next_result = NULL;
+}
+
+uu_list_walk_t *
+uu_list_walk_start(uu_list_t *lp, uint32_t flags)
+{
+ uu_list_walk_t *wp;
+
+ if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ wp = uu_zalloc(sizeof (*wp));
+ if (wp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ list_walk_init(wp, lp, flags);
+ return (wp);
+}
+
+void *
+uu_list_walk_next(uu_list_walk_t *wp)
+{
+ uu_list_t *lp = wp->ulw_list;
+ uu_list_node_impl_t *np = list_walk_advance(wp, lp);
+
+ if (np == NULL)
+ return (NULL);
+
+ return (NODE_TO_ELEM(lp, np));
+}
+
+void
+uu_list_walk_end(uu_list_walk_t *wp)
+{
+ list_walk_fini(wp);
+ uu_free(wp);
+}
+
+int
+uu_list_walk(uu_list_t *lp, uu_walk_fn_t *func, void *private, uint32_t flags)
+{
+ uu_list_node_impl_t *np;
+
+ int status = UU_WALK_NEXT;
+
+ int robust = (flags & UU_WALK_ROBUST);
+ int reverse = (flags & UU_WALK_REVERSE);
+
+ if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (-1);
+ }
+
+ if (lp->ul_debug || robust) {
+ uu_list_walk_t my_walk;
+ void *e;
+
+ list_walk_init(&my_walk, lp, flags);
+ while (status == UU_WALK_NEXT &&
+ (e = uu_list_walk_next(&my_walk)) != NULL)
+ status = (*func)(e, private);
+ list_walk_fini(&my_walk);
+ } else {
+ if (!reverse) {
+ for (np = lp->ul_null_node.uln_next;
+ status == UU_WALK_NEXT && np != &lp->ul_null_node;
+ np = np->uln_next) {
+ status = (*func)(NODE_TO_ELEM(lp, np), private);
+ }
+ } else {
+ for (np = lp->ul_null_node.uln_prev;
+ status == UU_WALK_NEXT && np != &lp->ul_null_node;
+ np = np->uln_prev) {
+ status = (*func)(NODE_TO_ELEM(lp, np), private);
+ }
+ }
+ }
+ if (status >= 0)
+ return (0);
+ uu_set_error(UU_ERROR_CALLBACK_FAILED);
+ return (-1);
+}
+
+void
+uu_list_remove(uu_list_t *lp, void *elem)
+{
+ uu_list_node_impl_t *np = ELEM_TO_NODE(lp, elem);
+ uu_list_walk_t *wp;
+
+ if (lp->ul_debug) {
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_remove(%p, %p): elem not on list\n",
+ (void *)lp, elem);
+ /*
+ * invalidate outstanding uu_list_index_ts.
+ */
+ lp->ul_index = INDEX_NEXT(lp->ul_index);
+ }
+
+ /*
+ * robust walkers must be advanced. In debug mode, non-robust
+ * walkers are also on the list. If there are any, it's an error.
+ */
+ for (wp = lp->ul_null_walk.ulw_next; wp != &lp->ul_null_walk;
+ wp = wp->ulw_next) {
+ if (wp->ulw_robust) {
+ if (np == wp->ulw_next_result)
+ (void) list_walk_advance(wp, lp);
+ } else if (wp->ulw_next_result != NULL) {
+ uu_panic("uu_list_remove(%p, %p): active non-robust "
+ "walker\n", (void *)lp, elem);
+ }
+ }
+
+ np->uln_next->uln_prev = np->uln_prev;
+ np->uln_prev->uln_next = np->uln_next;
+
+ lp->ul_numnodes--;
+
+ np->uln_next = POOL_TO_MARKER(lp->ul_pool);
+ np->uln_prev = NULL;
+}
+
+void *
+uu_list_teardown(uu_list_t *lp, void **cookie)
+{
+ void *ep;
+
+ /*
+ * XXX: disable list modification until list is empty
+ */
+ if (lp->ul_debug && *cookie != NULL)
+ uu_panic("uu_list_teardown(%p, %p): unexpected cookie\n",
+ (void *)lp, (void *)cookie);
+
+ ep = uu_list_first(lp);
+ if (ep)
+ uu_list_remove(lp, ep);
+ return (ep);
+}
+
+int
+uu_list_insert_before(uu_list_t *lp, void *target, void *elem)
+{
+ uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
+
+ if (target == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_insert_before(%p, %p, %p): %p is "
+ "not currently on a list\n",
+ (void *)lp, target, elem, target);
+ }
+ if (lp->ul_sorted) {
+ if (lp->ul_debug)
+ uu_panic("uu_list_insert_before(%p, ...): list is "
+ "UU_LIST_SORTED\n", (void *)lp);
+ uu_set_error(UU_ERROR_NOT_SUPPORTED);
+ return (-1);
+ }
+
+ list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
+ return (0);
+}
+
+int
+uu_list_insert_after(uu_list_t *lp, void *target, void *elem)
+{
+ uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
+
+ if (target == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_insert_after(%p, %p, %p): %p is "
+ "not currently on a list\n",
+ (void *)lp, target, elem, target);
+ }
+ if (lp->ul_sorted) {
+ if (lp->ul_debug)
+ uu_panic("uu_list_insert_after(%p, ...): list is "
+ "UU_LIST_SORTED\n", (void *)lp);
+ uu_set_error(UU_ERROR_NOT_SUPPORTED);
+ return (-1);
+ }
+
+ list_insert(lp, ELEM_TO_NODE(lp, elem), np, np->uln_next);
+ return (0);
+}
+
+size_t
+uu_list_numnodes(uu_list_t *lp)
+{
+ return (lp->ul_numnodes);
+}
+
+void *
+uu_list_first(uu_list_t *lp)
+{
+ uu_list_node_impl_t *n = lp->ul_null_node.uln_next;
+ if (n == &lp->ul_null_node)
+ return (NULL);
+ return (NODE_TO_ELEM(lp, n));
+}
+
+void *
+uu_list_last(uu_list_t *lp)
+{
+ uu_list_node_impl_t *n = lp->ul_null_node.uln_prev;
+ if (n == &lp->ul_null_node)
+ return (NULL);
+ return (NODE_TO_ELEM(lp, n));
+}
+
+void *
+uu_list_next(uu_list_t *lp, void *elem)
+{
+ uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
+
+ n = n->uln_next;
+ if (n == &lp->ul_null_node)
+ return (NULL);
+ return (NODE_TO_ELEM(lp, n));
+}
+
+void *
+uu_list_prev(uu_list_t *lp, void *elem)
+{
+ uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
+
+ n = n->uln_prev;
+ if (n == &lp->ul_null_node)
+ return (NULL);
+ return (NODE_TO_ELEM(lp, n));
+}
+
+/*
+ * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
+ */
+void
+uu_list_lockup(void)
+{
+ uu_list_pool_t *pp;
+
+ (void) pthread_mutex_lock(&uu_lpool_list_lock);
+ for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
+ pp = pp->ulp_next)
+ (void) pthread_mutex_lock(&pp->ulp_lock);
+}
+
+void
+uu_list_release(void)
+{
+ uu_list_pool_t *pp;
+
+ for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
+ pp = pp->ulp_next)
+ (void) pthread_mutex_unlock(&pp->ulp_lock);
+ (void) pthread_mutex_unlock(&uu_lpool_list_lock);
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c
new file mode 100644
index 000000000000..b673834e4dcf
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c
@@ -0,0 +1,277 @@
+/*
+ * 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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "libuutil_common.h"
+
+#define HAVE_ASSFAIL 1
+
+#include <assert.h>
+#include <errno.h>
+#include <libintl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/debug.h>
+#include <thread.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/*
+ * All of the old code under !defined(PTHREAD_ONCE_KEY_NP)
+ * is here to enable the building of a native version of
+ * libuutil.so when the build machine has not yet been upgraded
+ * to a version of libc that provides pthread_key_create_once_np().
+ * It should all be deleted when solaris_nevada ships.
+ * The code is not MT-safe in a relaxed memory model.
+ */
+
+#if defined(PTHREAD_ONCE_KEY_NP)
+static pthread_key_t uu_error_key = PTHREAD_ONCE_KEY_NP;
+#else /* PTHREAD_ONCE_KEY_NP */
+static pthread_key_t uu_error_key = 0;
+static pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif /* PTHREAD_ONCE_KEY_NP */
+
+static int uu_error_key_setup = 0;
+
+static pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
+/* LINTED static unused */
+static const char *uu_panic_format;
+/* LINTED static unused */
+static va_list uu_panic_args;
+static pthread_t uu_panic_thread;
+
+static uint32_t _uu_main_error;
+
+void
+uu_set_error(uint_t code)
+{
+
+#if defined(PTHREAD_ONCE_KEY_NP)
+ if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
+ uu_error_key_setup = -1;
+ else
+ uu_error_key_setup = 1;
+#else /* PTHREAD_ONCE_KEY_NP */
+ if (uu_error_key_setup == 0) {
+ (void) pthread_mutex_lock(&uu_key_lock);
+ if (uu_error_key_setup == 0) {
+ if (pthread_key_create(&uu_error_key, NULL) != 0)
+ uu_error_key_setup = -1;
+ else
+ uu_error_key_setup = 1;
+ }
+ (void) pthread_mutex_unlock(&uu_key_lock);
+ }
+#endif /* PTHREAD_ONCE_KEY_NP */
+ if (uu_error_key_setup > 0)
+ (void) pthread_setspecific(uu_error_key,
+ (void *)(uintptr_t)code);
+}
+
+uint32_t
+uu_error(void)
+{
+
+ if (uu_error_key_setup < 0) /* can't happen? */
+ return (UU_ERROR_UNKNOWN);
+
+ /*
+ * Because UU_ERROR_NONE == 0, if uu_set_error() was
+ * never called, then this will return UU_ERROR_NONE:
+ */
+ return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
+}
+
+const char *
+uu_strerror(uint32_t code)
+{
+ const char *str;
+
+ switch (code) {
+ case UU_ERROR_NONE:
+ str = dgettext(TEXT_DOMAIN, "No error");
+ break;
+
+ case UU_ERROR_INVALID_ARGUMENT:
+ str = dgettext(TEXT_DOMAIN, "Invalid argument");
+ break;
+
+ case UU_ERROR_UNKNOWN_FLAG:
+ str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
+ break;
+
+ case UU_ERROR_NO_MEMORY:
+ str = dgettext(TEXT_DOMAIN, "Out of memory");
+ break;
+
+ case UU_ERROR_CALLBACK_FAILED:
+ str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
+ break;
+
+ case UU_ERROR_NOT_SUPPORTED:
+ str = dgettext(TEXT_DOMAIN, "Operation not supported");
+ break;
+
+ case UU_ERROR_EMPTY:
+ str = dgettext(TEXT_DOMAIN, "No value provided");
+ break;
+
+ case UU_ERROR_UNDERFLOW:
+ str = dgettext(TEXT_DOMAIN, "Value too small");
+ break;
+
+ case UU_ERROR_OVERFLOW:
+ str = dgettext(TEXT_DOMAIN, "Value too large");
+ break;
+
+ case UU_ERROR_INVALID_CHAR:
+ str = dgettext(TEXT_DOMAIN,
+ "Value contains unexpected character");
+ break;
+
+ case UU_ERROR_INVALID_DIGIT:
+ str = dgettext(TEXT_DOMAIN,
+ "Value contains digit not in base");
+ break;
+
+ case UU_ERROR_SYSTEM:
+ str = dgettext(TEXT_DOMAIN, "Underlying system error");
+ break;
+
+ case UU_ERROR_UNKNOWN:
+ str = dgettext(TEXT_DOMAIN, "Error status not known");
+ break;
+
+ default:
+ errno = ESRCH;
+ str = NULL;
+ break;
+ }
+ return (str);
+}
+
+void
+uu_panic(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+
+ (void) pthread_mutex_lock(&uu_panic_lock);
+ if (uu_panic_thread == 0) {
+ uu_panic_thread = pthread_self();
+ uu_panic_format = format;
+ va_copy(uu_panic_args, args);
+ }
+ (void) pthread_mutex_unlock(&uu_panic_lock);
+
+ (void) vfprintf(stderr, format, args);
+
+ if (uu_panic_thread == pthread_self())
+ abort();
+ else
+ for (;;)
+ (void) pause();
+}
+
+int
+assfail(const char *astring, const char *file, int line)
+{
+ __assert(astring, file, line);
+ /*NOTREACHED*/
+ return (0);
+}
+
+static void
+uu_lockup(void)
+{
+ (void) pthread_mutex_lock(&uu_panic_lock);
+#if !defined(PTHREAD_ONCE_KEY_NP)
+ (void) pthread_mutex_lock(&uu_key_lock);
+#endif
+ uu_avl_lockup();
+ uu_list_lockup();
+}
+
+static void
+uu_release(void)
+{
+ (void) pthread_mutex_unlock(&uu_panic_lock);
+#if !defined(PTHREAD_ONCE_KEY_NP)
+ (void) pthread_mutex_unlock(&uu_key_lock);
+#endif
+ uu_avl_release();
+ uu_list_release();
+}
+
+static void
+uu_release_child(void)
+{
+ uu_panic_format = NULL;
+ uu_panic_thread = 0;
+
+ uu_release();
+}
+
+#pragma init(uu_init)
+static void
+uu_init(void)
+{
+ (void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
+}
+
+/*
+ * Dump a block of memory in hex+ascii, for debugging
+ */
+void
+uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
+{
+ const unsigned char *p = buf;
+ int i;
+
+ for (i = 0; i < len; i += 16) {
+ int j;
+
+ (void) fprintf(out, "%s", prefix);
+ for (j = 0; j < 16 && i + j < len; j++) {
+ (void) fprintf(out, "%2.2x ", p[i + j]);
+ }
+ for (; j < 16; j++) {
+ (void) fprintf(out, " ");
+ }
+ for (j = 0; j < 16 && i + j < len; j++) {
+ (void) fprintf(out, "%c",
+ isprint(p[i + j]) ? p[i + j] : '.');
+ }
+ (void) fprintf(out, "\n");
+ }
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c
new file mode 100644
index 000000000000..7256662e38f6
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef _LP64
+#define TMPPATHFMT "%s/uu%ld"
+#else /* _LP64 */
+#define TMPPATHFMT "%s/uu%lld"
+#endif /* _LP64 */
+
+/*ARGSUSED*/
+int
+uu_open_tmp(const char *dir, uint_t uflags)
+{
+ int f;
+ char *fname = uu_zalloc(PATH_MAX);
+
+ if (fname == NULL)
+ return (-1);
+
+ for (;;) {
+ (void) snprintf(fname, PATH_MAX, "%s/uu%lld", dir, gethrtime());
+
+ f = open(fname, O_CREAT | O_EXCL | O_RDWR, 0600);
+
+ if (f >= 0 || errno != EEXIST)
+ break;
+ }
+
+ if (f >= 0)
+ (void) unlink(fname);
+
+ uu_free(fname);
+
+ return (f);
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c
new file mode 100644
index 000000000000..20626ace6b2f
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <libintl.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <wchar.h>
+#include <unistd.h>
+
+static const char PNAME_FMT[] = "%s: ";
+static const char ERRNO_FMT[] = ": %s\n";
+
+static const char *pname;
+
+static void
+uu_die_internal(int status, const char *format, va_list alist) __NORETURN;
+
+int uu_exit_ok_value = EXIT_SUCCESS;
+int uu_exit_fatal_value = EXIT_FAILURE;
+int uu_exit_usage_value = 2;
+
+int *
+uu_exit_ok(void)
+{
+ return (&uu_exit_ok_value);
+}
+
+int *
+uu_exit_fatal(void)
+{
+ return (&uu_exit_fatal_value);
+}
+
+int *
+uu_exit_usage(void)
+{
+ return (&uu_exit_usage_value);
+}
+
+void
+uu_alt_exit(int profile)
+{
+ switch (profile) {
+ case UU_PROFILE_DEFAULT:
+ uu_exit_ok_value = EXIT_SUCCESS;
+ uu_exit_fatal_value = EXIT_FAILURE;
+ uu_exit_usage_value = 2;
+ break;
+ case UU_PROFILE_LAUNCHER:
+ uu_exit_ok_value = EXIT_SUCCESS;
+ uu_exit_fatal_value = 124;
+ uu_exit_usage_value = 125;
+ break;
+ }
+}
+
+static void
+uu_warn_internal(int err, const char *format, va_list alist)
+{
+ if (pname != NULL)
+ (void) fprintf(stderr, PNAME_FMT, pname);
+
+ (void) vfprintf(stderr, format, alist);
+
+ if (strrchr(format, '\n') == NULL)
+ (void) fprintf(stderr, ERRNO_FMT, strerror(err));
+}
+
+void
+uu_vwarn(const char *format, va_list alist)
+{
+ uu_warn_internal(errno, format, alist);
+}
+
+/*PRINTFLIKE1*/
+void
+uu_warn(const char *format, ...)
+{
+ va_list alist;
+ va_start(alist, format);
+ uu_warn_internal(errno, format, alist);
+ va_end(alist);
+}
+
+static void
+uu_die_internal(int status, const char *format, va_list alist)
+{
+ uu_warn_internal(errno, format, alist);
+#ifdef DEBUG
+ {
+ char *cp;
+
+ if (!issetugid()) {
+ cp = getenv("UU_DIE_ABORTS");
+ if (cp != NULL && *cp != '\0')
+ abort();
+ }
+ }
+#endif
+ exit(status);
+}
+
+void
+uu_vdie(const char *format, va_list alist)
+{
+ uu_die_internal(UU_EXIT_FATAL, format, alist);
+}
+
+/*PRINTFLIKE1*/
+void
+uu_die(const char *format, ...)
+{
+ va_list alist;
+ va_start(alist, format);
+ uu_die_internal(UU_EXIT_FATAL, format, alist);
+ va_end(alist);
+}
+
+void
+uu_vxdie(int status, const char *format, va_list alist)
+{
+ uu_die_internal(status, format, alist);
+}
+
+/*PRINTFLIKE2*/
+void
+uu_xdie(int status, const char *format, ...)
+{
+ va_list alist;
+ va_start(alist, format);
+ uu_die_internal(status, format, alist);
+ va_end(alist);
+}
+
+const char *
+uu_setpname(char *arg0)
+{
+ /*
+ * Having a NULL argv[0], while uncommon, is possible. It
+ * makes more sense to handle this event in uu_setpname rather
+ * than in each of its consumers.
+ */
+ if (arg0 == NULL) {
+ pname = "unknown_command";
+ return (pname);
+ }
+
+ /*
+ * Guard against '/' at end of command invocation.
+ */
+ for (;;) {
+ char *p = strrchr(arg0, '/');
+ if (p == NULL) {
+ pname = arg0;
+ break;
+ } else {
+ if (*(p + 1) == '\0') {
+ *p = '\0';
+ continue;
+ }
+
+ pname = p + 1;
+ break;
+ }
+ }
+
+ return (pname);
+}
+
+const char *
+uu_getpname(void)
+{
+ return (pname);
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c
new file mode 100644
index 000000000000..66afba05e849
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c
@@ -0,0 +1,56 @@
+/*
+ * 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * String helper functions
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include "libuutil.h"
+
+/* Return true if strings are equal */
+boolean_t
+uu_streq(const char *a, const char *b)
+{
+ return (strcmp(a, b) == 0);
+}
+
+/* Return true if strings are equal, case-insensitively */
+boolean_t
+uu_strcaseeq(const char *a, const char *b)
+{
+ return (strcasecmp(a, b) == 0);
+}
+
+/* Return true if string a Begins With string b */
+boolean_t
+uu_strbw(const char *a, const char *b)
+{
+ return (strncmp(a, b, strlen(b)) == 0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c
new file mode 100644
index 000000000000..8fd1148365cb
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c
@@ -0,0 +1,300 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <limits.h>
+#include <ctype.h>
+
+#define MAX_BASE 36
+
+#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9')
+
+#define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \
+ ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A')
+
+static int
+strtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign)
+{
+ const unsigned char *s = (const unsigned char *)s_arg;
+
+ uint64_t val = 0;
+ uint64_t multmax;
+
+ unsigned c, i;
+
+ int neg = 0;
+
+ int bad_digit = 0;
+ int bad_char = 0;
+ int overflow = 0;
+
+ if (s == NULL || base == 1 || base > MAX_BASE) {
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (-1);
+ }
+
+ while ((c = *s) != 0 && isspace(c))
+ s++;
+
+ switch (c) {
+ case '-':
+ if (!sign)
+ overflow = 1; /* becomes underflow below */
+ neg = 1;
+ /*FALLTHRU*/
+ case '+':
+ c = *++s;
+ break;
+ default:
+ break;
+ }
+
+ if (c == '\0') {
+ uu_set_error(UU_ERROR_EMPTY);
+ return (-1);
+ }
+
+ if (base == 0) {
+ if (c != '0')
+ base = 10;
+ else if (s[1] == 'x' || s[1] == 'X')
+ base = 16;
+ else
+ base = 8;
+ }
+
+ if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X'))
+ c = *(s += 2);
+
+ if ((val = CTOI(c)) >= base) {
+ if (IS_DIGIT(c))
+ bad_digit = 1;
+ else
+ bad_char = 1;
+ val = 0;
+ }
+
+ multmax = (uint64_t)UINT64_MAX / (uint64_t)base;
+
+ for (c = *++s; c != '\0'; c = *++s) {
+ if ((i = CTOI(c)) >= base) {
+ if (isspace(c))
+ break;
+ if (IS_DIGIT(c))
+ bad_digit = 1;
+ else
+ bad_char = 1;
+ i = 0;
+ }
+
+ if (val > multmax)
+ overflow = 1;
+
+ val *= base;
+ if ((uint64_t)UINT64_MAX - val < (uint64_t)i)
+ overflow = 1;
+
+ val += i;
+ }
+
+ while ((c = *s) != 0) {
+ if (!isspace(c))
+ bad_char = 1;
+ s++;
+ }
+
+ if (sign) {
+ if (neg) {
+ if (val > -(uint64_t)INT64_MIN)
+ overflow = 1;
+ } else {
+ if (val > INT64_MAX)
+ overflow = 1;
+ }
+ }
+
+ if (neg)
+ val = -val;
+
+ if (bad_char | bad_digit | overflow) {
+ if (bad_char)
+ uu_set_error(UU_ERROR_INVALID_CHAR);
+ else if (bad_digit)
+ uu_set_error(UU_ERROR_INVALID_DIGIT);
+ else if (overflow) {
+ if (neg)
+ uu_set_error(UU_ERROR_UNDERFLOW);
+ else
+ uu_set_error(UU_ERROR_OVERFLOW);
+ }
+ return (-1);
+ }
+
+ *out = val;
+ return (0);
+}
+
+int
+uu_strtoint(const char *s, void *v, size_t sz, int base,
+ int64_t min, int64_t max)
+{
+ uint64_t val_u;
+ int64_t val;
+
+ if (min > max)
+ goto bad_argument;
+
+ switch (sz) {
+ case 1:
+ if (max > INT8_MAX || min < INT8_MIN)
+ goto bad_argument;
+ break;
+ case 2:
+ if (max > INT16_MAX || min < INT16_MIN)
+ goto bad_argument;
+ break;
+ case 4:
+ if (max > INT32_MAX || min < INT32_MIN)
+ goto bad_argument;
+ break;
+ case 8:
+ if (max > INT64_MAX || min < INT64_MIN)
+ goto bad_argument;
+ break;
+ default:
+ goto bad_argument;
+ }
+
+ if (min == 0 && max == 0) {
+ min = -(1ULL << (8 * sz - 1));
+ max = (1ULL << (8 * sz - 1)) - 1;
+ }
+
+ if (strtoint(s, &val_u, base, 1) == -1)
+ return (-1);
+
+ val = (int64_t)val_u;
+
+ if (val < min) {
+ uu_set_error(UU_ERROR_UNDERFLOW);
+ return (-1);
+ } else if (val > max) {
+ uu_set_error(UU_ERROR_OVERFLOW);
+ return (-1);
+ }
+
+ switch (sz) {
+ case 1:
+ *(int8_t *)v = val;
+ return (0);
+ case 2:
+ *(int16_t *)v = val;
+ return (0);
+ case 4:
+ *(int32_t *)v = val;
+ return (0);
+ case 8:
+ *(int64_t *)v = val;
+ return (0);
+ default:
+ break; /* fall through to bad_argument */
+ }
+
+bad_argument:
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (-1);
+}
+
+int
+uu_strtouint(const char *s, void *v, size_t sz, int base,
+ uint64_t min, uint64_t max)
+{
+ uint64_t val;
+
+ if (min > max)
+ goto bad_argument;
+
+ switch (sz) {
+ case 1:
+ if (max > UINT8_MAX)
+ goto bad_argument;
+ break;
+ case 2:
+ if (max > UINT16_MAX)
+ goto bad_argument;
+ break;
+ case 4:
+ if (max > UINT32_MAX)
+ goto bad_argument;
+ break;
+ case 8:
+ if (max > UINT64_MAX)
+ goto bad_argument;
+ break;
+ default:
+ goto bad_argument;
+ }
+
+ if (min == 0 && max == 0) {
+ /* we have to be careful, since << can overflow */
+ max = (1ULL << (8 * sz - 1)) * 2 - 1;
+ }
+
+ if (strtoint(s, &val, base, 0) == -1)
+ return (-1);
+
+ if (val < min) {
+ uu_set_error(UU_ERROR_UNDERFLOW);
+ return (-1);
+ } else if (val > max) {
+ uu_set_error(UU_ERROR_OVERFLOW);
+ return (-1);
+ }
+
+ switch (sz) {
+ case 1:
+ *(uint8_t *)v = val;
+ return (0);
+ case 2:
+ *(uint16_t *)v = val;
+ return (0);
+ case 4:
+ *(uint32_t *)v = val;
+ return (0);
+ case 8:
+ *(uint64_t *)v = val;
+ return (0);
+ default:
+ break; /* shouldn't happen, fall through */
+ }
+
+bad_argument:
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (-1);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
new file mode 100644
index 000000000000..a1344f324729
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
@@ -0,0 +1,885 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
+ * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright (c) 2019 Datto Inc.
+ */
+
+#ifndef _LIBZFS_H
+#define _LIBZFS_H
+
+#include <assert.h>
+#include <libnvpair.h>
+#include <sys/mnttab.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/varargs.h>
+#include <sys/fs/zfs.h>
+#include <sys/avl.h>
+#include <sys/zfs_ioctl.h>
+#include <libzfs_core.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Miscellaneous ZFS constants
+ */
+#define ZFS_MAXPROPLEN MAXPATHLEN
+#define ZPOOL_MAXPROPLEN MAXPATHLEN
+
+/*
+ * libzfs errors
+ */
+typedef enum zfs_error {
+ EZFS_SUCCESS = 0, /* no error -- success */
+ EZFS_NOMEM = 2000, /* out of memory */
+ EZFS_BADPROP, /* invalid property value */
+ EZFS_PROPREADONLY, /* cannot set readonly property */
+ EZFS_PROPTYPE, /* property does not apply to dataset type */
+ EZFS_PROPNONINHERIT, /* property is not inheritable */
+ EZFS_PROPSPACE, /* bad quota or reservation */
+ EZFS_BADTYPE, /* dataset is not of appropriate type */
+ EZFS_BUSY, /* pool or dataset is busy */
+ EZFS_EXISTS, /* pool or dataset already exists */
+ EZFS_NOENT, /* no such pool or dataset */
+ EZFS_BADSTREAM, /* bad backup stream */
+ EZFS_DSREADONLY, /* dataset is readonly */
+ EZFS_VOLTOOBIG, /* volume is too large for 32-bit system */
+ EZFS_INVALIDNAME, /* invalid dataset name */
+ EZFS_BADRESTORE, /* unable to restore to destination */
+ EZFS_BADBACKUP, /* backup failed */
+ EZFS_BADTARGET, /* bad attach/detach/replace target */
+ EZFS_NODEVICE, /* no such device in pool */
+ EZFS_BADDEV, /* invalid device to add */
+ EZFS_NOREPLICAS, /* no valid replicas */
+ EZFS_RESILVERING, /* currently resilvering */
+ EZFS_BADVERSION, /* unsupported version */
+ EZFS_POOLUNAVAIL, /* pool is currently unavailable */
+ EZFS_DEVOVERFLOW, /* too many devices in one vdev */
+ EZFS_BADPATH, /* must be an absolute path */
+ EZFS_CROSSTARGET, /* rename or clone across pool or dataset */
+ EZFS_ZONED, /* used improperly in local zone */
+ EZFS_MOUNTFAILED, /* failed to mount dataset */
+ EZFS_UMOUNTFAILED, /* failed to unmount dataset */
+ EZFS_UNSHARENFSFAILED, /* unshare(1M) failed */
+ EZFS_SHARENFSFAILED, /* share(1M) failed */
+ EZFS_PERM, /* permission denied */
+ EZFS_NOSPC, /* out of space */
+ EZFS_FAULT, /* bad address */
+ EZFS_IO, /* I/O error */
+ EZFS_INTR, /* signal received */
+ EZFS_ISSPARE, /* device is a hot spare */
+ EZFS_INVALCONFIG, /* invalid vdev configuration */
+ EZFS_RECURSIVE, /* recursive dependency */
+ EZFS_NOHISTORY, /* no history object */
+ EZFS_POOLPROPS, /* couldn't retrieve pool props */
+ EZFS_POOL_NOTSUP, /* ops not supported for this type of pool */
+ EZFS_POOL_INVALARG, /* invalid argument for this pool operation */
+ EZFS_NAMETOOLONG, /* dataset name is too long */
+ EZFS_OPENFAILED, /* open of device failed */
+ EZFS_NOCAP, /* couldn't get capacity */
+ EZFS_LABELFAILED, /* write of label failed */
+ EZFS_BADWHO, /* invalid permission who */
+ EZFS_BADPERM, /* invalid permission */
+ EZFS_BADPERMSET, /* invalid permission set name */
+ EZFS_NODELEGATION, /* delegated administration is disabled */
+ EZFS_UNSHARESMBFAILED, /* failed to unshare over smb */
+ EZFS_SHARESMBFAILED, /* failed to share over smb */
+ EZFS_BADCACHE, /* bad cache file */
+ EZFS_ISL2CACHE, /* device is for the level 2 ARC */
+ EZFS_VDEVNOTSUP, /* unsupported vdev type */
+ EZFS_NOTSUP, /* ops not supported on this dataset */
+ EZFS_ACTIVE_SPARE, /* pool has active shared spare devices */
+ EZFS_UNPLAYED_LOGS, /* log device has unplayed logs */
+ EZFS_REFTAG_RELE, /* snapshot release: tag not found */
+ EZFS_REFTAG_HOLD, /* snapshot hold: tag already exists */
+ EZFS_TAGTOOLONG, /* snapshot hold/rele: tag too long */
+ EZFS_PIPEFAILED, /* pipe create failed */
+ EZFS_THREADCREATEFAILED, /* thread create failed */
+ EZFS_POSTSPLIT_ONLINE, /* onlining a disk after splitting it */
+ EZFS_SCRUBBING, /* currently scrubbing */
+ EZFS_NO_SCRUB, /* no active scrub */
+ EZFS_DIFF, /* general failure of zfs diff */
+ EZFS_DIFFDATA, /* bad zfs diff data */
+ EZFS_POOLREADONLY, /* pool is in read-only mode */
+ EZFS_SCRUB_PAUSED, /* scrub currently paused */
+ EZFS_ACTIVE_POOL, /* pool is imported on a different system */
+ EZFS_NO_PENDING, /* cannot cancel, no operation is pending */
+ EZFS_CHECKPOINT_EXISTS, /* checkpoint exists */
+ EZFS_DISCARDING_CHECKPOINT, /* currently discarding a checkpoint */
+ EZFS_NO_CHECKPOINT, /* pool has no checkpoint */
+ EZFS_DEVRM_IN_PROGRESS, /* a device is currently being removed */
+ EZFS_VDEV_TOO_BIG, /* a device is too big to be used */
+ EZFS_TOOMANY, /* argument list too long */
+ EZFS_INITIALIZING, /* currently initializing */
+ EZFS_NO_INITIALIZE, /* no active initialize */
+ EZFS_UNKNOWN
+} zfs_error_t;
+
+/*
+ * UEFI boot support parameters. When creating whole disk boot pool,
+ * zpool create should allow to create EFI System partition for UEFI boot
+ * program. In case of BIOS, the EFI System partition is not used
+ * even if it does exist.
+ */
+typedef enum zpool_boot_label {
+ ZPOOL_NO_BOOT_LABEL = 0,
+ ZPOOL_CREATE_BOOT_LABEL,
+ ZPOOL_COPY_BOOT_LABEL
+} zpool_boot_label_t;
+
+/*
+ * The following data structures are all part
+ * of the zfs_allow_t data structure which is
+ * used for printing 'allow' permissions.
+ * It is a linked list of zfs_allow_t's which
+ * then contain avl tree's for user/group/sets/...
+ * and each one of the entries in those trees have
+ * avl tree's for the permissions they belong to and
+ * whether they are local,descendent or local+descendent
+ * permissions. The AVL trees are used primarily for
+ * sorting purposes, but also so that we can quickly find
+ * a given user and or permission.
+ */
+typedef struct zfs_perm_node {
+ avl_node_t z_node;
+ char z_pname[MAXPATHLEN];
+} zfs_perm_node_t;
+
+typedef struct zfs_allow_node {
+ avl_node_t z_node;
+ char z_key[MAXPATHLEN]; /* name, such as joe */
+ avl_tree_t z_localdescend; /* local+descendent perms */
+ avl_tree_t z_local; /* local permissions */
+ avl_tree_t z_descend; /* descendent permissions */
+} zfs_allow_node_t;
+
+typedef struct zfs_allow {
+ struct zfs_allow *z_next;
+ char z_setpoint[MAXPATHLEN];
+ avl_tree_t z_sets;
+ avl_tree_t z_crperms;
+ avl_tree_t z_user;
+ avl_tree_t z_group;
+ avl_tree_t z_everyone;
+} zfs_allow_t;
+
+/*
+ * Basic handle types
+ */
+typedef struct zfs_handle zfs_handle_t;
+typedef struct zpool_handle zpool_handle_t;
+typedef struct libzfs_handle libzfs_handle_t;
+
+/*
+ * Library initialization
+ */
+extern libzfs_handle_t *libzfs_init(void);
+extern void libzfs_fini(libzfs_handle_t *);
+
+extern libzfs_handle_t *zpool_get_handle(zpool_handle_t *);
+extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
+
+extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
+
+extern void zfs_save_arguments(int argc, char **, char *, int);
+extern int zpool_log_history(libzfs_handle_t *, const char *);
+
+extern int libzfs_errno(libzfs_handle_t *);
+extern const char *libzfs_error_action(libzfs_handle_t *);
+extern const char *libzfs_error_description(libzfs_handle_t *);
+extern int zfs_standard_error(libzfs_handle_t *, int, const char *);
+extern void libzfs_mnttab_init(libzfs_handle_t *);
+extern void libzfs_mnttab_fini(libzfs_handle_t *);
+extern void libzfs_mnttab_cache(libzfs_handle_t *, boolean_t);
+extern int libzfs_mnttab_find(libzfs_handle_t *, const char *,
+ struct mnttab *);
+extern void libzfs_mnttab_add(libzfs_handle_t *, const char *,
+ const char *, const char *);
+extern void libzfs_mnttab_remove(libzfs_handle_t *, const char *);
+
+/*
+ * Basic handle functions
+ */
+extern zpool_handle_t *zpool_open(libzfs_handle_t *, const char *);
+extern zpool_handle_t *zpool_open_canfail(libzfs_handle_t *, const char *);
+extern void zpool_close(zpool_handle_t *);
+extern const char *zpool_get_name(zpool_handle_t *);
+extern int zpool_get_state(zpool_handle_t *);
+extern const char *zpool_state_to_name(vdev_state_t, vdev_aux_t);
+extern const char *zpool_pool_state_to_name(pool_state_t);
+extern void zpool_free_handles(libzfs_handle_t *);
+extern int zpool_nextboot(libzfs_handle_t *, uint64_t, uint64_t, const char *);
+
+/*
+ * Iterate over all active pools in the system.
+ */
+typedef int (*zpool_iter_f)(zpool_handle_t *, void *);
+extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
+extern boolean_t zpool_skip_pool(const char *);
+
+/*
+ * Functions to create and destroy pools
+ */
+extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
+ nvlist_t *, nvlist_t *);
+extern int zpool_destroy(zpool_handle_t *, const char *);
+extern int zpool_add(zpool_handle_t *, nvlist_t *);
+
+typedef struct splitflags {
+ /* do not split, but return the config that would be split off */
+ int dryrun : 1;
+
+ /* after splitting, import the pool */
+ int import : 1;
+ int name_flags;
+} splitflags_t;
+
+/*
+ * Functions to manipulate pool and vdev state
+ */
+extern int zpool_scan(zpool_handle_t *, pool_scan_func_t, pool_scrub_cmd_t);
+extern int zpool_initialize(zpool_handle_t *, pool_initialize_func_t,
+ nvlist_t *);
+extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
+extern int zpool_reguid(zpool_handle_t *);
+extern int zpool_reopen(zpool_handle_t *);
+
+extern int zpool_sync_one(zpool_handle_t *, void *);
+
+extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
+ vdev_state_t *);
+extern int zpool_vdev_offline(zpool_handle_t *, const char *, boolean_t);
+extern int zpool_vdev_attach(zpool_handle_t *, const char *,
+ const char *, nvlist_t *, int);
+extern int zpool_vdev_detach(zpool_handle_t *, const char *);
+extern int zpool_vdev_remove(zpool_handle_t *, const char *);
+extern int zpool_vdev_remove_cancel(zpool_handle_t *);
+extern int zpool_vdev_indirect_size(zpool_handle_t *, const char *, uint64_t *);
+extern int zpool_vdev_split(zpool_handle_t *, char *, nvlist_t **, nvlist_t *,
+ splitflags_t);
+
+extern int zpool_vdev_fault(zpool_handle_t *, uint64_t, vdev_aux_t);
+extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t, vdev_aux_t);
+extern int zpool_vdev_clear(zpool_handle_t *, uint64_t);
+
+extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *,
+ boolean_t *, boolean_t *);
+extern nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
+ boolean_t *, boolean_t *, boolean_t *);
+extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, const char *,
+ zpool_boot_label_t, uint64_t, int *);
+
+/*
+ * Functions to manage pool properties
+ */
+extern int zpool_set_prop(zpool_handle_t *, const char *, const char *);
+extern int zpool_get_prop(zpool_handle_t *, zpool_prop_t, char *,
+ size_t proplen, zprop_source_t *, boolean_t);
+extern uint64_t zpool_get_prop_int(zpool_handle_t *, zpool_prop_t,
+ zprop_source_t *);
+
+extern const char *zpool_prop_to_name(zpool_prop_t);
+extern const char *zpool_prop_values(zpool_prop_t);
+
+/*
+ * Pool health statistics.
+ */
+typedef enum {
+ /*
+ * The following correspond to faults as defined in the (fault.fs.zfs.*)
+ * event namespace. Each is associated with a corresponding message ID.
+ * This must be kept in sync with the zfs_msgid_table in
+ * lib/libzfs/libzfs_status.c.
+ */
+ ZPOOL_STATUS_CORRUPT_CACHE, /* corrupt /kernel/drv/zpool.cache */
+ ZPOOL_STATUS_MISSING_DEV_R, /* missing device with replicas */
+ ZPOOL_STATUS_MISSING_DEV_NR, /* missing device with no replicas */
+ ZPOOL_STATUS_CORRUPT_LABEL_R, /* bad device label with replicas */
+ ZPOOL_STATUS_CORRUPT_LABEL_NR, /* bad device label with no replicas */
+ ZPOOL_STATUS_BAD_GUID_SUM, /* sum of device guids didn't match */
+ ZPOOL_STATUS_CORRUPT_POOL, /* pool metadata is corrupted */
+ ZPOOL_STATUS_CORRUPT_DATA, /* data errors in user (meta)data */
+ ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */
+ ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */
+ ZPOOL_STATUS_HOSTID_MISMATCH, /* last accessed by another system */
+ ZPOOL_STATUS_HOSTID_ACTIVE, /* currently active on another system */
+ ZPOOL_STATUS_HOSTID_REQUIRED, /* multihost=on and hostid=0 */
+ ZPOOL_STATUS_IO_FAILURE_WAIT, /* failed I/O, failmode 'wait' */
+ ZPOOL_STATUS_IO_FAILURE_CONTINUE, /* failed I/O, failmode 'continue' */
+ ZPOOL_STATUS_IO_FAILURE_MMP, /* failed MMP, failmode not 'panic' */
+ ZPOOL_STATUS_BAD_LOG, /* cannot read log chain(s) */
+
+ /*
+ * If the pool has unsupported features but can still be opened in
+ * read-only mode, its status is ZPOOL_STATUS_UNSUP_FEAT_WRITE. If the
+ * pool has unsupported features but cannot be opened at all, its
+ * status is ZPOOL_STATUS_UNSUP_FEAT_READ.
+ */
+ ZPOOL_STATUS_UNSUP_FEAT_READ, /* unsupported features for read */
+ ZPOOL_STATUS_UNSUP_FEAT_WRITE, /* unsupported features for write */
+
+ /*
+ * These faults have no corresponding message ID. At the time we are
+ * checking the status, the original reason for the FMA fault (I/O or
+ * checksum errors) has been lost.
+ */
+ ZPOOL_STATUS_FAULTED_DEV_R, /* faulted device with replicas */
+ ZPOOL_STATUS_FAULTED_DEV_NR, /* faulted device with no replicas */
+
+ /*
+ * The following are not faults per se, but still an error possibly
+ * requiring administrative attention. There is no corresponding
+ * message ID.
+ */
+ ZPOOL_STATUS_VERSION_OLDER, /* older legacy on-disk version */
+ ZPOOL_STATUS_FEAT_DISABLED, /* supported features are disabled */
+ ZPOOL_STATUS_RESILVERING, /* device being resilvered */
+ ZPOOL_STATUS_OFFLINE_DEV, /* device offline */
+ ZPOOL_STATUS_REMOVED_DEV, /* removed device */
+ ZPOOL_STATUS_NON_NATIVE_ASHIFT, /* (e.g. 512e dev with ashift of 9) */
+
+ /*
+ * Finally, the following indicates a healthy pool.
+ */
+ ZPOOL_STATUS_OK
+} zpool_status_t;
+
+extern zpool_status_t zpool_get_status(zpool_handle_t *, char **);
+extern zpool_status_t zpool_import_status(nvlist_t *, char **);
+extern void zpool_dump_ddt(const ddt_stat_t *dds, const ddt_histogram_t *ddh);
+
+/*
+ * Statistics and configuration functions.
+ */
+extern nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **);
+extern nvlist_t *zpool_get_features(zpool_handle_t *);
+extern int zpool_refresh_stats(zpool_handle_t *, boolean_t *);
+extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
+extern boolean_t zpool_is_bootable(zpool_handle_t *);
+
+/*
+ * Import and export functions
+ */
+extern int zpool_export(zpool_handle_t *, boolean_t, const char *);
+extern int zpool_export_force(zpool_handle_t *, const char *);
+extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
+ char *altroot);
+extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
+ nvlist_t *, int);
+extern void zpool_print_unsup_feat(nvlist_t *config);
+
+/*
+ * Search for pools to import
+ */
+
+typedef struct importargs {
+ char **path; /* a list of paths to search */
+ int paths; /* number of paths to search */
+ char *poolname; /* name of a pool to find */
+ uint64_t guid; /* guid of a pool to find */
+ char *cachefile; /* cachefile to use for import */
+ int can_be_active : 1; /* can the pool be active? */
+ int unique : 1; /* does 'poolname' already exist? */
+ int exists : 1; /* set on return if pool already exists */
+ nvlist_t *policy; /* load policy (max txg, rewind, etc.) */
+} importargs_t;
+
+extern nvlist_t *zpool_search_import(libzfs_handle_t *, importargs_t *);
+extern int zpool_tryimport(libzfs_handle_t *hdl, char *target,
+ nvlist_t **configp, importargs_t *args);
+
+/* legacy pool search routines */
+extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
+extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *,
+ char *, uint64_t);
+
+/*
+ * Miscellaneous pool functions
+ */
+struct zfs_cmd;
+
+extern const char *zfs_history_event_names[];
+
+typedef enum {
+ VDEV_NAME_PATH = 1 << 0,
+ VDEV_NAME_GUID = 1 << 1,
+ VDEV_NAME_FOLLOW_LINKS = 1 << 2,
+ VDEV_NAME_TYPE_ID = 1 << 3,
+} vdev_name_t;
+
+extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
+ int name_flags);
+extern int zpool_upgrade(zpool_handle_t *, uint64_t);
+extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
+extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
+ nvlist_t ***, uint_t *);
+extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
+ size_t len);
+extern int zfs_ioctl(libzfs_handle_t *, int request, struct zfs_cmd *);
+extern int zpool_get_physpath(zpool_handle_t *, char *, size_t);
+extern void zpool_explain_recover(libzfs_handle_t *, const char *, int,
+ nvlist_t *);
+extern int zpool_checkpoint(zpool_handle_t *);
+extern int zpool_discard_checkpoint(zpool_handle_t *);
+
+/*
+ * Basic handle manipulations. These functions do not create or destroy the
+ * underlying datasets, only the references to them.
+ */
+extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int);
+extern zfs_handle_t *zfs_handle_dup(zfs_handle_t *);
+extern void zfs_close(zfs_handle_t *);
+extern zfs_type_t zfs_get_type(const zfs_handle_t *);
+extern const char *zfs_get_name(const zfs_handle_t *);
+extern zpool_handle_t *zfs_get_pool_handle(const zfs_handle_t *);
+extern const char *zfs_get_pool_name(const zfs_handle_t *);
+
+/*
+ * Property management functions. Some functions are shared with the kernel,
+ * and are found in sys/fs/zfs.h.
+ */
+
+/*
+ * zfs dataset property management
+ */
+extern const char *zfs_prop_default_string(zfs_prop_t);
+extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
+extern const char *zfs_prop_column_name(zfs_prop_t);
+extern boolean_t zfs_prop_align_right(zfs_prop_t);
+
+extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t,
+ nvlist_t *, uint64_t, zfs_handle_t *, zpool_handle_t *, const char *);
+
+extern const char *zfs_prop_to_name(zfs_prop_t);
+extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
+extern int zfs_prop_set_list(zfs_handle_t *, nvlist_t *);
+extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
+ zprop_source_t *, char *, size_t, boolean_t);
+extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t,
+ boolean_t);
+extern int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *,
+ zprop_source_t *, char *, size_t);
+extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
+ uint64_t *propvalue);
+extern int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
+ char *propbuf, int proplen, boolean_t literal);
+extern int zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
+ uint64_t *propvalue);
+extern int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
+ char *propbuf, int proplen, boolean_t literal);
+extern int zfs_prop_get_feature(zfs_handle_t *zhp, const char *propname,
+ char *buf, size_t len);
+extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
+extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
+extern const char *zfs_prop_values(zfs_prop_t);
+extern int zfs_prop_is_string(zfs_prop_t prop);
+extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
+extern nvlist_t *zfs_get_recvd_props(zfs_handle_t *);
+extern nvlist_t *zfs_get_clones_nvl(zfs_handle_t *);
+
+
+typedef struct zprop_list {
+ int pl_prop;
+ char *pl_user_prop;
+ struct zprop_list *pl_next;
+ boolean_t pl_all;
+ size_t pl_width;
+ size_t pl_recvd_width;
+ boolean_t pl_fixed;
+} zprop_list_t;
+
+extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **, boolean_t,
+ boolean_t);
+extern void zfs_prune_proplist(zfs_handle_t *, uint8_t *);
+
+#define ZFS_MOUNTPOINT_NONE "none"
+#define ZFS_MOUNTPOINT_LEGACY "legacy"
+
+#define ZFS_FEATURE_DISABLED "disabled"
+#define ZFS_FEATURE_ENABLED "enabled"
+#define ZFS_FEATURE_ACTIVE "active"
+
+#define ZFS_UNSUPPORTED_INACTIVE "inactive"
+#define ZFS_UNSUPPORTED_READONLY "readonly"
+
+/*
+ * zpool property management
+ */
+extern int zpool_expand_proplist(zpool_handle_t *, zprop_list_t **);
+extern int zpool_prop_get_feature(zpool_handle_t *, const char *, char *,
+ size_t);
+extern const char *zpool_prop_default_string(zpool_prop_t);
+extern uint64_t zpool_prop_default_numeric(zpool_prop_t);
+extern const char *zpool_prop_column_name(zpool_prop_t);
+extern boolean_t zpool_prop_align_right(zpool_prop_t);
+
+/*
+ * Functions shared by zfs and zpool property management.
+ */
+extern int zprop_iter(zprop_func func, void *cb, boolean_t show_all,
+ boolean_t ordered, zfs_type_t type);
+extern int zprop_get_list(libzfs_handle_t *, char *, zprop_list_t **,
+ zfs_type_t);
+extern void zprop_free_list(zprop_list_t *);
+
+#define ZFS_GET_NCOLS 5
+
+typedef enum {
+ GET_COL_NONE,
+ GET_COL_NAME,
+ GET_COL_PROPERTY,
+ GET_COL_VALUE,
+ GET_COL_RECVD,
+ GET_COL_SOURCE
+} zfs_get_column_t;
+
+/*
+ * Functions for printing zfs or zpool properties
+ */
+typedef struct zprop_get_cbdata {
+ int cb_sources;
+ zfs_get_column_t cb_columns[ZFS_GET_NCOLS];
+ int cb_colwidths[ZFS_GET_NCOLS + 1];
+ boolean_t cb_scripted;
+ boolean_t cb_literal;
+ boolean_t cb_first;
+ zprop_list_t *cb_proplist;
+ zfs_type_t cb_type;
+} zprop_get_cbdata_t;
+
+void zprop_print_one_property(const char *, zprop_get_cbdata_t *,
+ const char *, const char *, zprop_source_t, const char *,
+ const char *);
+
+/*
+ * Iterator functions.
+ */
+typedef int (*zfs_iter_f)(zfs_handle_t *, void *);
+extern int zfs_iter_root(libzfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
+extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_snapshots(zfs_handle_t *, boolean_t, zfs_iter_f, void *,
+ uint64_t, uint64_t);
+extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *,
+ uint64_t, uint64_t);
+extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *);
+extern int zfs_iter_bookmarks(zfs_handle_t *, zfs_iter_f, void *);
+
+typedef struct get_all_cb {
+ zfs_handle_t **cb_handles;
+ size_t cb_alloc;
+ size_t cb_used;
+} get_all_cb_t;
+
+void zfs_foreach_mountpoint(libzfs_handle_t *, zfs_handle_t **, size_t,
+ zfs_iter_f, void*, boolean_t);
+
+void libzfs_add_handle(get_all_cb_t *, zfs_handle_t *);
+
+/*
+ * Functions to create and destroy datasets.
+ */
+extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
+ nvlist_t *);
+extern int zfs_create_ancestors(libzfs_handle_t *, const char *);
+extern int zfs_destroy(zfs_handle_t *, boolean_t);
+extern int zfs_destroy_snaps(zfs_handle_t *, char *, boolean_t);
+extern int zfs_destroy_snaps_nvl(libzfs_handle_t *, nvlist_t *, boolean_t);
+extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
+extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
+extern int zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps,
+ nvlist_t *props);
+extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
+
+typedef struct renameflags {
+ /* recursive rename */
+ int recurse : 1;
+
+ /* don't unmount file systems */
+ int nounmount : 1;
+
+ /* force unmount file systems */
+ int forceunmount : 1;
+} renameflags_t;
+
+extern int zfs_rename(zfs_handle_t *, const char *, const char *,
+ renameflags_t flags);
+
+typedef struct sendflags {
+ /* print informational messages (ie, -v was specified) */
+ boolean_t verbose;
+
+ /* recursive send (ie, -R) */
+ boolean_t replicate;
+
+ /* for incrementals, do all intermediate snapshots */
+ boolean_t doall;
+
+ /* if dataset is a clone, do incremental from its origin */
+ boolean_t fromorigin;
+
+ /* do deduplication */
+ boolean_t dedup;
+
+ /* send properties (ie, -p) */
+ boolean_t props;
+
+ /* do not send (no-op, ie. -n) */
+ boolean_t dryrun;
+
+ /* parsable verbose output (ie. -P) */
+ boolean_t parsable;
+
+ /* show progress (ie. -v) */
+ boolean_t progress;
+
+ /* large blocks (>128K) are permitted */
+ boolean_t largeblock;
+
+ /* WRITE_EMBEDDED records of type DATA are permitted */
+ boolean_t embed_data;
+
+ /* compressed WRITE records are permitted */
+ boolean_t compress;
+
+ /* show progress as process title(ie. -V) */
+ boolean_t progressastitle;
+} sendflags_t;
+
+typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
+
+extern int zfs_send(zfs_handle_t *, const char *, const char *,
+ sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
+extern int zfs_send_one(zfs_handle_t *, const char *, int, sendflags_t flags);
+extern int zfs_send_resume(libzfs_handle_t *, sendflags_t *, int outfd,
+ const char *);
+extern nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl,
+ const char *token);
+
+extern int zfs_promote(zfs_handle_t *);
+extern int zfs_hold(zfs_handle_t *, const char *, const char *,
+ boolean_t, int);
+extern int zfs_hold_nvl(zfs_handle_t *, int, nvlist_t *);
+extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t);
+extern int zfs_get_holds(zfs_handle_t *, nvlist_t **);
+extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *);
+
+typedef int (*zfs_userspace_cb_t)(void *arg, const char *domain,
+ uid_t rid, uint64_t space);
+
+extern int zfs_userspace(zfs_handle_t *, zfs_userquota_prop_t,
+ zfs_userspace_cb_t, void *);
+
+extern int zfs_get_fsacl(zfs_handle_t *, nvlist_t **);
+extern int zfs_set_fsacl(zfs_handle_t *, boolean_t, nvlist_t *);
+
+typedef struct recvflags {
+ /* print informational messages (ie, -v was specified) */
+ boolean_t verbose;
+
+ /* the destination is a prefix, not the exact fs (ie, -d) */
+ boolean_t isprefix;
+
+ /*
+ * Only the tail of the sent snapshot path is appended to the
+ * destination to determine the received snapshot name (ie, -e).
+ */
+ boolean_t istail;
+
+ /* do not actually do the recv, just check if it would work (ie, -n) */
+ boolean_t dryrun;
+
+ /* rollback/destroy filesystems as necessary (eg, -F) */
+ boolean_t force;
+
+ /* set "canmount=off" on all modified filesystems */
+ boolean_t canmountoff;
+
+ /*
+ * Mark the file systems as "resumable" and do not destroy them if the
+ * receive is interrupted
+ */
+ boolean_t resumable;
+
+ /* byteswap flag is used internally; callers need not specify */
+ boolean_t byteswap;
+
+ /* do not mount file systems as they are extracted (private) */
+ boolean_t nomount;
+} recvflags_t;
+
+extern int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *,
+ recvflags_t *, int, avl_tree_t *);
+
+typedef enum diff_flags {
+ ZFS_DIFF_PARSEABLE = 0x1,
+ ZFS_DIFF_TIMESTAMP = 0x2,
+ ZFS_DIFF_CLASSIFY = 0x4
+} diff_flags_t;
+
+extern int zfs_show_diffs(zfs_handle_t *, int, const char *, const char *,
+ int);
+
+/*
+ * Miscellaneous functions.
+ */
+extern const char *zfs_type_to_name(zfs_type_t);
+extern void zfs_refresh_properties(zfs_handle_t *);
+extern int zfs_name_valid(const char *, zfs_type_t);
+extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t);
+extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
+ zfs_type_t);
+extern int zfs_spa_version(zfs_handle_t *, int *);
+extern boolean_t zfs_bookmark_exists(const char *path);
+extern ulong_t get_system_hostid(void);
+
+/*
+ * Mount support functions.
+ */
+extern boolean_t is_mounted(libzfs_handle_t *, const char *special, char **);
+extern boolean_t zfs_is_mounted(zfs_handle_t *, char **);
+extern int zfs_mount(zfs_handle_t *, const char *, int);
+extern int zfs_unmount(zfs_handle_t *, const char *, int);
+extern int zfs_unmountall(zfs_handle_t *, int);
+
+/*
+ * Share support functions.
+ */
+extern boolean_t zfs_is_shared(zfs_handle_t *);
+extern int zfs_share(zfs_handle_t *);
+extern int zfs_unshare(zfs_handle_t *);
+
+/*
+ * Protocol-specific share support functions.
+ */
+extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **);
+extern boolean_t zfs_is_shared_smb(zfs_handle_t *, char **);
+extern int zfs_share_nfs(zfs_handle_t *);
+extern int zfs_share_smb(zfs_handle_t *);
+extern int zfs_shareall(zfs_handle_t *);
+extern int zfs_unshare_nfs(zfs_handle_t *, const char *);
+extern int zfs_unshare_smb(zfs_handle_t *, const char *);
+extern int zfs_unshareall_nfs(zfs_handle_t *);
+extern int zfs_unshareall_smb(zfs_handle_t *);
+extern int zfs_unshareall_bypath(zfs_handle_t *, const char *);
+extern int zfs_unshareall(zfs_handle_t *);
+extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *, char *,
+ void *, void *, int, zfs_share_op_t);
+
+/*
+ * FreeBSD-specific jail support function.
+ */
+extern int zfs_jail(zfs_handle_t *, int, int);
+
+/*
+ * When dealing with nvlists, verify() is extremely useful
+ */
+#ifndef verify
+#ifdef NDEBUG
+#define verify(EX) ((void)(EX))
+#else
+#define verify(EX) assert(EX)
+#endif
+#endif
+
+/*
+ * Utility function to convert a number to a human-readable form.
+ */
+extern void zfs_nicenum(uint64_t, char *, size_t);
+extern int zfs_nicestrtonum(libzfs_handle_t *, const char *, uint64_t *);
+
+/*
+ * Given a device or file, determine if it is part of a pool.
+ */
+extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
+ boolean_t *);
+
+/*
+ * Label manipulation.
+ */
+extern int zpool_read_label(int, nvlist_t **);
+extern int zpool_read_all_labels(int, nvlist_t **);
+extern int zpool_clear_label(int);
+
+/* is this zvol valid for use as a dump device? */
+extern int zvol_check_dump_config(char *);
+
+/*
+ * Management interfaces for SMB ACL files
+ */
+
+int zfs_smb_acl_add(libzfs_handle_t *, char *, char *, char *);
+int zfs_smb_acl_remove(libzfs_handle_t *, char *, char *, char *);
+int zfs_smb_acl_purge(libzfs_handle_t *, char *, char *);
+int zfs_smb_acl_rename(libzfs_handle_t *, char *, char *, char *, char *);
+
+/*
+ * Enable and disable datasets within a pool by mounting/unmounting and
+ * sharing/unsharing them.
+ */
+extern int zpool_enable_datasets(zpool_handle_t *, const char *, int);
+extern int zpool_disable_datasets(zpool_handle_t *, boolean_t);
+
+/*
+ * Mappings between vdev and FRU.
+ */
+extern void libzfs_fru_refresh(libzfs_handle_t *);
+extern const char *libzfs_fru_lookup(libzfs_handle_t *, const char *);
+extern const char *libzfs_fru_devpath(libzfs_handle_t *, const char *);
+extern boolean_t libzfs_fru_compare(libzfs_handle_t *, const char *,
+ const char *);
+extern boolean_t libzfs_fru_notself(libzfs_handle_t *, const char *);
+extern int zpool_fru_set(zpool_handle_t *, uint64_t, const char *);
+
+#ifndef illumos
+extern int zmount(const char *, const char *, int, char *, char *, int, char *,
+ int);
+#endif
+extern int zfs_remap_indirects(libzfs_handle_t *hdl, const char *);
+
+/* Allow consumers to initialize libshare externally for optimal performance */
+extern int zfs_init_libshare_arg(libzfs_handle_t *, int, void *);
+/*
+ * For most consumers, zfs_init_libshare_arg is sufficient on its own, and
+ * zfs_uninit_libshare is unnecessary. zfs_uninit_libshare should only be called
+ * if the caller has already initialized libshare for one set of zfs handles,
+ * and wishes to share or unshare filesystems outside of that set. In that case,
+ * the caller should uninitialize libshare, and then re-initialize it with the
+ * new handles being shared or unshared.
+ */
+extern void zfs_uninit_libshare(libzfs_handle_t *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBZFS_H */
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c
new file mode 100644
index 000000000000..7bbb68328f29
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c
@@ -0,0 +1,736 @@
+/*
+ * 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 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Portions Copyright 2007 Ramprakash Jelari
+ * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
+ * All rights reserved.
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
+ */
+
+#include <libintl.h>
+#include <libuutil.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <zone.h>
+
+#include <libzfs.h>
+
+#include "libzfs_impl.h"
+
+/*
+ * Structure to keep track of dataset state. Before changing the 'sharenfs' or
+ * 'mountpoint' property, we record whether the filesystem was previously
+ * mounted/shared. This prior state dictates whether we remount/reshare the
+ * dataset after the property has been changed.
+ *
+ * The interface consists of the following sequence of functions:
+ *
+ * changelist_gather()
+ * changelist_prefix()
+ * < change property >
+ * changelist_postfix()
+ * changelist_free()
+ *
+ * Other interfaces:
+ *
+ * changelist_remove() - remove a node from a gathered list
+ * changelist_rename() - renames all datasets appropriately when doing a rename
+ * changelist_unshare() - unshares all the nodes in a given changelist
+ * changelist_haszonedchild() - check if there is any child exported to
+ * a local zone
+ */
+typedef struct prop_changenode {
+ zfs_handle_t *cn_handle;
+ int cn_shared;
+ int cn_mounted;
+ int cn_zoned;
+ boolean_t cn_needpost; /* is postfix() needed? */
+ uu_list_node_t cn_listnode;
+} prop_changenode_t;
+
+struct prop_changelist {
+ zfs_prop_t cl_prop;
+ zfs_prop_t cl_realprop;
+ zfs_prop_t cl_shareprop; /* used with sharenfs/sharesmb */
+ uu_list_pool_t *cl_pool;
+ uu_list_t *cl_list;
+ boolean_t cl_waslegacy;
+ boolean_t cl_allchildren;
+ boolean_t cl_alldependents;
+ int cl_mflags; /* Mount flags */
+ int cl_gflags; /* Gather request flags */
+ boolean_t cl_haszonedchild;
+ boolean_t cl_sorted;
+};
+
+/*
+ * If the property is 'mountpoint', go through and unmount filesystems as
+ * necessary. We don't do the same for 'sharenfs', because we can just re-share
+ * with different options without interrupting service. We do handle 'sharesmb'
+ * since there may be old resource names that need to be removed.
+ */
+int
+changelist_prefix(prop_changelist_t *clp)
+{
+ prop_changenode_t *cn;
+ int ret = 0;
+
+ if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
+ clp->cl_prop != ZFS_PROP_SHARESMB)
+ return (0);
+
+ for (cn = uu_list_first(clp->cl_list); cn != NULL;
+ cn = uu_list_next(clp->cl_list, cn)) {
+
+ /* if a previous loop failed, set the remaining to false */
+ if (ret == -1) {
+ cn->cn_needpost = B_FALSE;
+ continue;
+ }
+
+ /*
+ * If we are in the global zone, but this dataset is exported
+ * to a local zone, do nothing.
+ */
+ if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
+ continue;
+
+ if (!ZFS_IS_VOLUME(cn->cn_handle)) {
+ /*
+ * Do the property specific processing.
+ */
+ switch (clp->cl_prop) {
+ case ZFS_PROP_MOUNTPOINT:
+ if (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT)
+ break;
+ if (zfs_unmount(cn->cn_handle, NULL,
+ clp->cl_mflags) != 0) {
+ ret = -1;
+ cn->cn_needpost = B_FALSE;
+ }
+ break;
+ case ZFS_PROP_SHARESMB:
+ (void) zfs_unshare_smb(cn->cn_handle, NULL);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (ret == -1)
+ (void) changelist_postfix(clp);
+
+ return (ret);
+}
+
+/*
+ * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
+ * reshare the filesystems as necessary. In changelist_gather() we recorded
+ * whether the filesystem was previously shared or mounted. The action we take
+ * depends on the previous state, and whether the value was previously 'legacy'.
+ * For non-legacy properties, we only remount/reshare the filesystem if it was
+ * previously mounted/shared. Otherwise, we always remount/reshare the
+ * filesystem.
+ */
+int
+changelist_postfix(prop_changelist_t *clp)
+{
+ prop_changenode_t *cn;
+ char shareopts[ZFS_MAXPROPLEN];
+ int errors = 0;
+ libzfs_handle_t *hdl;
+#ifdef illumos
+ size_t num_datasets = 0, i;
+ zfs_handle_t **zhandle_arr;
+ sa_init_selective_arg_t sharearg;
+#endif
+
+ /*
+ * If we're changing the mountpoint, attempt to destroy the underlying
+ * mountpoint. All other datasets will have inherited from this dataset
+ * (in which case their mountpoints exist in the filesystem in the new
+ * location), or have explicit mountpoints set (in which case they won't
+ * be in the changelist).
+ */
+ if ((cn = uu_list_last(clp->cl_list)) == NULL)
+ return (0);
+
+ if (clp->cl_prop == ZFS_PROP_MOUNTPOINT &&
+ !(clp->cl_gflags & CL_GATHER_DONT_UNMOUNT)) {
+ remove_mountpoint(cn->cn_handle);
+ }
+
+ /*
+ * It is possible that the changelist_prefix() used libshare
+ * to unshare some entries. Since libshare caches data, an
+ * attempt to reshare during postfix can fail unless libshare
+ * is uninitialized here so that it will reinitialize later.
+ */
+ if (cn->cn_handle != NULL) {
+ hdl = cn->cn_handle->zfs_hdl;
+ assert(hdl != NULL);
+ zfs_uninit_libshare(hdl);
+
+#ifdef illumos
+ /*
+ * For efficiencies sake, we initialize libshare for only a few
+ * shares (the ones affected here). Future initializations in
+ * this process should just use the cached initialization.
+ */
+ for (cn = uu_list_last(clp->cl_list); cn != NULL;
+ cn = uu_list_prev(clp->cl_list, cn)) {
+ num_datasets++;
+ }
+
+ zhandle_arr = zfs_alloc(hdl,
+ num_datasets * sizeof (zfs_handle_t *));
+ for (i = 0, cn = uu_list_last(clp->cl_list); cn != NULL;
+ cn = uu_list_prev(clp->cl_list, cn)) {
+ zhandle_arr[i++] = cn->cn_handle;
+ zfs_refresh_properties(cn->cn_handle);
+ }
+ assert(i == num_datasets);
+ sharearg.zhandle_arr = zhandle_arr;
+ sharearg.zhandle_len = num_datasets;
+ errors = zfs_init_libshare_arg(hdl, SA_INIT_SHARE_API_SELECTIVE,
+ &sharearg);
+ free(zhandle_arr);
+#endif
+ }
+ /*
+ * We walk the datasets in reverse, because we want to mount any parent
+ * datasets before mounting the children. We walk all datasets even if
+ * there are errors.
+ */
+ for (cn = uu_list_last(clp->cl_list); cn != NULL;
+ cn = uu_list_prev(clp->cl_list, cn)) {
+
+ boolean_t sharenfs;
+ boolean_t sharesmb;
+ boolean_t mounted;
+
+ /*
+ * If we are in the global zone, but this dataset is exported
+ * to a local zone, do nothing.
+ */
+ if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
+ continue;
+
+ /* Only do post-processing if it's required */
+ if (!cn->cn_needpost)
+ continue;
+ cn->cn_needpost = B_FALSE;
+
+#ifndef illumos
+ zfs_refresh_properties(cn->cn_handle);
+#endif
+
+ if (ZFS_IS_VOLUME(cn->cn_handle))
+ continue;
+
+ /*
+ * Remount if previously mounted or mountpoint was legacy,
+ * or sharenfs or sharesmb property is set.
+ */
+ sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
+ shareopts, sizeof (shareopts), NULL, NULL, 0,
+ B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
+
+ sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB,
+ shareopts, sizeof (shareopts), NULL, NULL, 0,
+ B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
+
+ mounted = (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT) ||
+ zfs_is_mounted(cn->cn_handle, NULL);
+
+ if (!mounted && (cn->cn_mounted ||
+ ((sharenfs || sharesmb || clp->cl_waslegacy) &&
+ (zfs_prop_get_int(cn->cn_handle,
+ ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) {
+
+ if (zfs_mount(cn->cn_handle, NULL, 0) != 0)
+ errors++;
+ else
+ mounted = TRUE;
+ }
+
+ /*
+ * If the file system is mounted we always re-share even
+ * if the filesystem is currently shared, so that we can
+ * adopt any new options.
+ */
+ if (sharenfs && mounted)
+ errors += zfs_share_nfs(cn->cn_handle);
+ else if (cn->cn_shared || clp->cl_waslegacy)
+ errors += zfs_unshare_nfs(cn->cn_handle, NULL);
+ if (sharesmb && mounted)
+ errors += zfs_share_smb(cn->cn_handle);
+ else if (cn->cn_shared || clp->cl_waslegacy)
+ errors += zfs_unshare_smb(cn->cn_handle, NULL);
+ }
+
+ return (errors ? -1 : 0);
+}
+
+/*
+ * Is this "dataset" a child of "parent"?
+ */
+boolean_t
+isa_child_of(const char *dataset, const char *parent)
+{
+ int len;
+
+ len = strlen(parent);
+
+ if (strncmp(dataset, parent, len) == 0 &&
+ (dataset[len] == '@' || dataset[len] == '/' ||
+ dataset[len] == '\0'))
+ return (B_TRUE);
+ else
+ return (B_FALSE);
+
+}
+
+/*
+ * If we rename a filesystem, child filesystem handles are no longer valid
+ * since we identify each dataset by its name in the ZFS namespace. As a
+ * result, we have to go through and fix up all the names appropriately. We
+ * could do this automatically if libzfs kept track of all open handles, but
+ * this is a lot less work.
+ */
+void
+changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
+{
+ prop_changenode_t *cn;
+ char newname[ZFS_MAX_DATASET_NAME_LEN];
+
+ for (cn = uu_list_first(clp->cl_list); cn != NULL;
+ cn = uu_list_next(clp->cl_list, cn)) {
+ /*
+ * Do not rename a clone that's not in the source hierarchy.
+ */
+ if (!isa_child_of(cn->cn_handle->zfs_name, src))
+ continue;
+
+ /*
+ * Destroy the previous mountpoint if needed.
+ */
+ remove_mountpoint(cn->cn_handle);
+
+ (void) strlcpy(newname, dst, sizeof (newname));
+ (void) strcat(newname, cn->cn_handle->zfs_name + strlen(src));
+
+ (void) strlcpy(cn->cn_handle->zfs_name, newname,
+ sizeof (cn->cn_handle->zfs_name));
+ }
+}
+
+/*
+ * Given a gathered changelist for the 'sharenfs' or 'sharesmb' property,
+ * unshare all the datasets in the list.
+ */
+int
+changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto)
+{
+ prop_changenode_t *cn;
+ int ret = 0;
+
+ if (clp->cl_prop != ZFS_PROP_SHARENFS &&
+ clp->cl_prop != ZFS_PROP_SHARESMB)
+ return (0);
+
+ for (cn = uu_list_first(clp->cl_list); cn != NULL;
+ cn = uu_list_next(clp->cl_list, cn)) {
+ if (zfs_unshare_proto(cn->cn_handle, NULL, proto) != 0)
+ ret = -1;
+ }
+
+ return (ret);
+}
+
+/*
+ * Check if there is any child exported to a local zone in a given changelist.
+ * This information has already been recorded while gathering the changelist
+ * via changelist_gather().
+ */
+int
+changelist_haszonedchild(prop_changelist_t *clp)
+{
+ return (clp->cl_haszonedchild);
+}
+
+/*
+ * Remove a node from a gathered list.
+ */
+void
+changelist_remove(prop_changelist_t *clp, const char *name)
+{
+ prop_changenode_t *cn;
+
+ for (cn = uu_list_first(clp->cl_list); cn != NULL;
+ cn = uu_list_next(clp->cl_list, cn)) {
+
+ if (strcmp(cn->cn_handle->zfs_name, name) == 0) {
+ uu_list_remove(clp->cl_list, cn);
+ zfs_close(cn->cn_handle);
+ free(cn);
+ return;
+ }
+ }
+}
+
+/*
+ * Release any memory associated with a changelist.
+ */
+void
+changelist_free(prop_changelist_t *clp)
+{
+ prop_changenode_t *cn;
+ void *cookie;
+
+ if (clp->cl_list) {
+ cookie = NULL;
+ while ((cn = uu_list_teardown(clp->cl_list, &cookie)) != NULL) {
+ zfs_close(cn->cn_handle);
+ free(cn);
+ }
+
+ uu_list_destroy(clp->cl_list);
+ }
+ if (clp->cl_pool)
+ uu_list_pool_destroy(clp->cl_pool);
+
+ free(clp);
+}
+
+static int
+change_one(zfs_handle_t *zhp, void *data)
+{
+ prop_changelist_t *clp = data;
+ char property[ZFS_MAXPROPLEN];
+ char where[64];
+ prop_changenode_t *cn;
+ zprop_source_t sourcetype;
+ zprop_source_t share_sourcetype;
+
+ /*
+ * We only want to unmount/unshare those filesystems that may inherit
+ * from the target filesystem. If we find any filesystem with a
+ * locally set mountpoint, we ignore any children since changing the
+ * property will not affect them. If this is a rename, we iterate
+ * over all children regardless, since we need them unmounted in
+ * order to do the rename. Also, if this is a volume and we're doing
+ * a rename, then always add it to the changelist.
+ */
+
+ if (!(ZFS_IS_VOLUME(zhp) && clp->cl_realprop == ZFS_PROP_NAME) &&
+ zfs_prop_get(zhp, clp->cl_prop, property,
+ sizeof (property), &sourcetype, where, sizeof (where),
+ B_FALSE) != 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ /*
+ * If we are "watching" sharenfs or sharesmb
+ * then check out the companion property which is tracked
+ * in cl_shareprop
+ */
+ if (clp->cl_shareprop != ZPROP_INVAL &&
+ zfs_prop_get(zhp, clp->cl_shareprop, property,
+ sizeof (property), &share_sourcetype, where, sizeof (where),
+ B_FALSE) != 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ if (clp->cl_alldependents || clp->cl_allchildren ||
+ sourcetype == ZPROP_SRC_DEFAULT ||
+ sourcetype == ZPROP_SRC_INHERITED ||
+ (clp->cl_shareprop != ZPROP_INVAL &&
+ (share_sourcetype == ZPROP_SRC_DEFAULT ||
+ share_sourcetype == ZPROP_SRC_INHERITED))) {
+ if ((cn = zfs_alloc(zfs_get_handle(zhp),
+ sizeof (prop_changenode_t))) == NULL) {
+ zfs_close(zhp);
+ return (-1);
+ }
+
+ cn->cn_handle = zhp;
+ cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
+ zfs_is_mounted(zhp, NULL);
+ cn->cn_shared = zfs_is_shared(zhp);
+ cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
+ cn->cn_needpost = B_TRUE;
+
+ /* Indicate if any child is exported to a local zone. */
+ if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
+ clp->cl_haszonedchild = B_TRUE;
+
+ uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
+
+ if (clp->cl_sorted) {
+ uu_list_index_t idx;
+
+ (void) uu_list_find(clp->cl_list, cn, NULL,
+ &idx);
+ uu_list_insert(clp->cl_list, cn, idx);
+ } else {
+ /*
+ * Add this child to beginning of the list. Children
+ * below this one in the hierarchy will get added above
+ * this one in the list. This produces a list in
+ * reverse dataset name order.
+ * This is necessary when the original mountpoint
+ * is legacy or none.
+ */
+ verify(uu_list_insert_before(clp->cl_list,
+ uu_list_first(clp->cl_list), cn) == 0);
+ }
+
+ if (!clp->cl_alldependents)
+ return (zfs_iter_children(zhp, change_one, data));
+ } else {
+ zfs_close(zhp);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+compare_mountpoints(const void *a, const void *b, void *unused)
+{
+ const prop_changenode_t *ca = a;
+ const prop_changenode_t *cb = b;
+
+ char mounta[MAXPATHLEN];
+ char mountb[MAXPATHLEN];
+
+ boolean_t hasmounta, hasmountb;
+
+ /*
+ * When unsharing or unmounting filesystems, we need to do it in
+ * mountpoint order. This allows the user to have a mountpoint
+ * hierarchy that is different from the dataset hierarchy, and still
+ * allow it to be changed. However, if either dataset doesn't have a
+ * mountpoint (because it is a volume or a snapshot), we place it at the
+ * end of the list, because it doesn't affect our change at all.
+ */
+ hasmounta = (zfs_prop_get(ca->cn_handle, ZFS_PROP_MOUNTPOINT, mounta,
+ sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
+ hasmountb = (zfs_prop_get(cb->cn_handle, ZFS_PROP_MOUNTPOINT, mountb,
+ sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
+
+ if (!hasmounta && hasmountb)
+ return (-1);
+ else if (hasmounta && !hasmountb)
+ return (1);
+ else if (!hasmounta && !hasmountb)
+ return (0);
+ else
+ return (strcmp(mountb, mounta));
+}
+
+/*
+ * Given a ZFS handle and a property, construct a complete list of datasets
+ * that need to be modified as part of this process. For anything but the
+ * 'mountpoint' and 'sharenfs' properties, this just returns an empty list.
+ * Otherwise, we iterate over all children and look for any datasets that
+ * inherit the property. For each such dataset, we add it to the list and
+ * mark whether it was shared beforehand.
+ */
+prop_changelist_t *
+changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
+ int mnt_flags)
+{
+ prop_changelist_t *clp;
+ prop_changenode_t *cn;
+ zfs_handle_t *temp;
+ char property[ZFS_MAXPROPLEN];
+ uu_compare_fn_t *compare = NULL;
+ boolean_t legacy = B_FALSE;
+
+ if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
+ return (NULL);
+
+ /*
+ * For mountpoint-related tasks, we want to sort everything by
+ * mountpoint, so that we mount and unmount them in the appropriate
+ * order, regardless of their position in the hierarchy.
+ */
+ if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
+ prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS ||
+ prop == ZFS_PROP_SHARESMB) {
+
+ if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
+ property, sizeof (property),
+ NULL, NULL, 0, B_FALSE) == 0 &&
+ (strcmp(property, "legacy") == 0 ||
+ strcmp(property, "none") == 0)) {
+
+ legacy = B_TRUE;
+ }
+ if (!legacy) {
+ compare = compare_mountpoints;
+ clp->cl_sorted = B_TRUE;
+ }
+ }
+
+ clp->cl_pool = uu_list_pool_create("changelist_pool",
+ sizeof (prop_changenode_t),
+ offsetof(prop_changenode_t, cn_listnode),
+ compare, 0);
+ if (clp->cl_pool == NULL) {
+ assert(uu_error() == UU_ERROR_NO_MEMORY);
+ (void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
+ changelist_free(clp);
+ return (NULL);
+ }
+
+ clp->cl_list = uu_list_create(clp->cl_pool, NULL,
+ clp->cl_sorted ? UU_LIST_SORTED : 0);
+ clp->cl_gflags = gather_flags;
+ clp->cl_mflags = mnt_flags;
+
+ if (clp->cl_list == NULL) {
+ assert(uu_error() == UU_ERROR_NO_MEMORY);
+ (void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
+ changelist_free(clp);
+ return (NULL);
+ }
+
+ /*
+ * If this is a rename or the 'zoned' property, we pretend we're
+ * changing the mountpoint and flag it so we can catch all children in
+ * change_one().
+ *
+ * Flag cl_alldependents to catch all children plus the dependents
+ * (clones) that are not in the hierarchy.
+ */
+ if (prop == ZFS_PROP_NAME) {
+ clp->cl_prop = ZFS_PROP_MOUNTPOINT;
+ clp->cl_alldependents = B_TRUE;
+ } else if (prop == ZFS_PROP_ZONED) {
+ clp->cl_prop = ZFS_PROP_MOUNTPOINT;
+ clp->cl_allchildren = B_TRUE;
+ } else if (prop == ZFS_PROP_CANMOUNT) {
+ clp->cl_prop = ZFS_PROP_MOUNTPOINT;
+ } else if (prop == ZFS_PROP_VOLSIZE) {
+ clp->cl_prop = ZFS_PROP_MOUNTPOINT;
+ } else {
+ clp->cl_prop = prop;
+ }
+ clp->cl_realprop = prop;
+
+ if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
+ clp->cl_prop != ZFS_PROP_SHARENFS &&
+ clp->cl_prop != ZFS_PROP_SHARESMB)
+ return (clp);
+
+ /*
+ * If watching SHARENFS or SHARESMB then
+ * also watch its companion property.
+ */
+ if (clp->cl_prop == ZFS_PROP_SHARENFS)
+ clp->cl_shareprop = ZFS_PROP_SHARESMB;
+ else if (clp->cl_prop == ZFS_PROP_SHARESMB)
+ clp->cl_shareprop = ZFS_PROP_SHARENFS;
+
+ if (clp->cl_alldependents) {
+ if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
+ changelist_free(clp);
+ return (NULL);
+ }
+ } else if (zfs_iter_children(zhp, change_one, clp) != 0) {
+ changelist_free(clp);
+ return (NULL);
+ }
+
+ /*
+ * We have to re-open ourselves because we auto-close all the handles
+ * and can't tell the difference.
+ */
+ if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp),
+ ZFS_TYPE_DATASET)) == NULL) {
+ changelist_free(clp);
+ return (NULL);
+ }
+
+ /*
+ * Always add ourself to the list. We add ourselves to the end so that
+ * we're the last to be unmounted.
+ */
+ if ((cn = zfs_alloc(zhp->zfs_hdl,
+ sizeof (prop_changenode_t))) == NULL) {
+ zfs_close(temp);
+ changelist_free(clp);
+ return (NULL);
+ }
+
+ cn->cn_handle = temp;
+ cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
+ zfs_is_mounted(temp, NULL);
+ cn->cn_shared = zfs_is_shared(temp);
+ cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
+ cn->cn_needpost = B_TRUE;
+
+ uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
+ if (clp->cl_sorted) {
+ uu_list_index_t idx;
+ (void) uu_list_find(clp->cl_list, cn, NULL, &idx);
+ uu_list_insert(clp->cl_list, cn, idx);
+ } else {
+ /*
+ * Add the target dataset to the end of the list.
+ * The list is not really unsorted. The list will be
+ * in reverse dataset name order. This is necessary
+ * when the original mountpoint is legacy or none.
+ */
+ verify(uu_list_insert_after(clp->cl_list,
+ uu_list_last(clp->cl_list), cn) == 0);
+ }
+
+ /*
+ * If the mountpoint property was previously 'legacy', or 'none',
+ * record it as the behavior of changelist_postfix() will be different.
+ */
+ if ((clp->cl_prop == ZFS_PROP_MOUNTPOINT) && legacy) {
+ /*
+ * do not automatically mount ex-legacy datasets if
+ * we specifically set canmount to noauto
+ */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) !=
+ ZFS_CANMOUNT_NOAUTO)
+ clp->cl_waslegacy = B_TRUE;
+ }
+
+ return (clp);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
new file mode 100644
index 000000000000..7545331b40b4
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
@@ -0,0 +1,121 @@
+/*
+ * CDDL HEADER SART
+ *
+ * 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 (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ */
+
+#include "libzfs_compat.h"
+
+int zfs_ioctl_version = ZFS_IOCVER_UNDEF;
+static int zfs_spa_version = -1;
+
+/*
+ * Get zfs_ioctl_version
+ */
+int
+get_zfs_ioctl_version(void)
+{
+ size_t ver_size;
+ int ver = ZFS_IOCVER_NONE;
+
+ ver_size = sizeof(ver);
+ sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0);
+
+ return (ver);
+}
+
+/*
+ * Get the SPA version
+ */
+static int
+get_zfs_spa_version(void)
+{
+ size_t ver_size;
+ int ver = 0;
+
+ ver_size = sizeof(ver);
+ sysctlbyname("vfs.zfs.version.spa", &ver, &ver_size, NULL, 0);
+
+ return (ver);
+}
+
+/*
+ * This is FreeBSD version of ioctl, because Solaris' ioctl() updates
+ * zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
+ * error is returned zc_nvlist_dst_size won't be updated.
+ */
+int
+zcmd_ioctl(int fd, int request, zfs_cmd_t *zc)
+{
+ size_t oldsize;
+ int ret, cflag = ZFS_CMD_COMPAT_NONE;
+
+ if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
+ zfs_ioctl_version = get_zfs_ioctl_version();
+
+ if (zfs_ioctl_version >= ZFS_IOCVER_DEADMAN) {
+ switch (zfs_ioctl_version) {
+ case ZFS_IOCVER_INLANES:
+ cflag = ZFS_CMD_COMPAT_INLANES;
+ break;
+ case ZFS_IOCVER_RESUME:
+ cflag = ZFS_CMD_COMPAT_RESUME;
+ break;
+ case ZFS_IOCVER_EDBP:
+ cflag = ZFS_CMD_COMPAT_EDBP;
+ break;
+ case ZFS_IOCVER_ZCMD:
+ cflag = ZFS_CMD_COMPAT_ZCMD;
+ break;
+ case ZFS_IOCVER_LZC:
+ cflag = ZFS_CMD_COMPAT_LZC;
+ break;
+ case ZFS_IOCVER_DEADMAN:
+ cflag = ZFS_CMD_COMPAT_DEADMAN;
+ break;
+ }
+ } else {
+ /*
+ * If vfs.zfs.version.ioctl is not defined, assume we have v28
+ * compatible binaries and use vfs.zfs.version.spa to test for v15
+ */
+ cflag = ZFS_CMD_COMPAT_V28;
+
+ if (zfs_spa_version < 0)
+ zfs_spa_version = get_zfs_spa_version();
+
+ if (zfs_spa_version == SPA_VERSION_15 ||
+ zfs_spa_version == SPA_VERSION_14 ||
+ zfs_spa_version == SPA_VERSION_13)
+ cflag = ZFS_CMD_COMPAT_V15;
+ }
+
+ oldsize = zc->zc_nvlist_dst_size;
+ ret = zcmd_ioctl_compat(fd, request, zc, cflag);
+
+ if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
+ ret = -1;
+ errno = ENOMEM;
+ }
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
new file mode 100644
index 000000000000..37616683330a
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
@@ -0,0 +1,44 @@
+/*
+ * CDDL HEADER SART
+ *
+ * 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 (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ */
+
+#ifndef _LIBZFS_COMPAT_H
+#define _LIBZFS_COMPAT_H
+
+#include <zfs_ioctl_compat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int get_zfs_ioctl_version(void);
+int zcmd_ioctl(int fd, int request, zfs_cmd_t *zc);
+
+#define ioctl(fd, ioc, zc) zcmd_ioctl((fd), (ioc), (zc))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBZFS_COMPAT_H */
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c
new file mode 100644
index 000000000000..b33d86432dc5
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c
@@ -0,0 +1,469 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2015 by Syneto S.R.L. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.
+ */
+
+/*
+ * The pool configuration repository is stored in /etc/zfs/zpool.cache as a
+ * single packed nvlist. While it would be nice to just read in this
+ * file from userland, this wouldn't work from a local zone. So we have to have
+ * a zpool ioctl to return the complete configuration for all pools. In the
+ * global zone, this will be identical to reading the file and unpacking it in
+ * userland.
+ */
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <libuutil.h>
+
+#include "libzfs_impl.h"
+
+typedef struct config_node {
+ char *cn_name;
+ nvlist_t *cn_config;
+ uu_avl_node_t cn_avl;
+} config_node_t;
+
+/* ARGSUSED */
+static int
+config_node_compare(const void *a, const void *b, void *unused)
+{
+ int ret;
+
+ const config_node_t *ca = (config_node_t *)a;
+ const config_node_t *cb = (config_node_t *)b;
+
+ ret = strcmp(ca->cn_name, cb->cn_name);
+
+ if (ret < 0)
+ return (-1);
+ else if (ret > 0)
+ return (1);
+ else
+ return (0);
+}
+
+void
+namespace_clear(libzfs_handle_t *hdl)
+{
+ if (hdl->libzfs_ns_avl) {
+ config_node_t *cn;
+ void *cookie = NULL;
+
+ while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl,
+ &cookie)) != NULL) {
+ nvlist_free(cn->cn_config);
+ free(cn->cn_name);
+ free(cn);
+ }
+
+ uu_avl_destroy(hdl->libzfs_ns_avl);
+ hdl->libzfs_ns_avl = NULL;
+ }
+
+ if (hdl->libzfs_ns_avlpool) {
+ uu_avl_pool_destroy(hdl->libzfs_ns_avlpool);
+ hdl->libzfs_ns_avlpool = NULL;
+ }
+}
+
+/*
+ * Loads the pool namespace, or re-loads it if the cache has changed.
+ */
+static int
+namespace_reload(libzfs_handle_t *hdl)
+{
+ nvlist_t *config;
+ config_node_t *cn;
+ nvpair_t *elem;
+ zfs_cmd_t zc = { 0 };
+ void *cookie;
+
+ if (hdl->libzfs_ns_gen == 0) {
+ /*
+ * This is the first time we've accessed the configuration
+ * cache. Initialize the AVL tree and then fall through to the
+ * common code.
+ */
+ if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
+ sizeof (config_node_t),
+ offsetof(config_node_t, cn_avl),
+ config_node_compare, UU_DEFAULT)) == NULL)
+ return (no_memory(hdl));
+
+ if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
+ NULL, UU_DEFAULT)) == NULL)
+ return (no_memory(hdl));
+ }
+
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
+ return (-1);
+
+ for (;;) {
+ zc.zc_cookie = hdl->libzfs_ns_gen;
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
+ switch (errno) {
+ case EEXIST:
+ /*
+ * The namespace hasn't changed.
+ */
+ zcmd_free_nvlists(&zc);
+ return (0);
+
+ case ENOMEM:
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ break;
+
+ default:
+ zcmd_free_nvlists(&zc);
+ return (zfs_standard_error(hdl, errno,
+ dgettext(TEXT_DOMAIN, "failed to read "
+ "pool configuration")));
+ }
+ } else {
+ hdl->libzfs_ns_gen = zc.zc_cookie;
+ break;
+ }
+ }
+
+ if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+
+ zcmd_free_nvlists(&zc);
+
+ /*
+ * Clear out any existing configuration information.
+ */
+ cookie = NULL;
+ while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {
+ nvlist_free(cn->cn_config);
+ free(cn->cn_name);
+ free(cn);
+ }
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
+ nvlist_t *child;
+ uu_avl_index_t where;
+
+ if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
+ nvlist_free(config);
+ return (-1);
+ }
+
+ if ((cn->cn_name = zfs_strdup(hdl,
+ nvpair_name(elem))) == NULL) {
+ free(cn);
+ nvlist_free(config);
+ return (-1);
+ }
+
+ verify(nvpair_value_nvlist(elem, &child) == 0);
+ if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
+ free(cn->cn_name);
+ free(cn);
+ nvlist_free(config);
+ return (no_memory(hdl));
+ }
+ verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
+ == NULL);
+
+ uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
+ }
+
+ nvlist_free(config);
+ return (0);
+}
+
+/*
+ * Retrieve the configuration for the given pool. The configuration is a nvlist
+ * describing the vdevs, as well as the statistics associated with each one.
+ */
+nvlist_t *
+zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)
+{
+ if (oldconfig)
+ *oldconfig = zhp->zpool_old_config;
+ return (zhp->zpool_config);
+}
+
+/*
+ * Retrieves a list of enabled features and their refcounts and caches it in
+ * the pool handle.
+ */
+nvlist_t *
+zpool_get_features(zpool_handle_t *zhp)
+{
+ nvlist_t *config, *features;
+
+ config = zpool_get_config(zhp, NULL);
+
+ if (config == NULL || !nvlist_exists(config,
+ ZPOOL_CONFIG_FEATURE_STATS)) {
+ int error;
+ boolean_t missing = B_FALSE;
+
+ error = zpool_refresh_stats(zhp, &missing);
+
+ if (error != 0 || missing)
+ return (NULL);
+
+ config = zpool_get_config(zhp, NULL);
+ }
+
+ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
+ &features) != 0)
+ return (NULL);
+
+ return (features);
+}
+
+/*
+ * Refresh the vdev statistics associated with the given pool. This is used in
+ * iostat to show configuration changes and determine the delta from the last
+ * time the function was called. This function can fail, in case the pool has
+ * been destroyed.
+ */
+int
+zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
+{
+ zfs_cmd_t zc = { 0 };
+ int error;
+ nvlist_t *config;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ *missing = B_FALSE;
+ (void) strcpy(zc.zc_name, zhp->zpool_name);
+
+ if (zhp->zpool_config_size == 0)
+ zhp->zpool_config_size = 1 << 16;
+
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0)
+ return (-1);
+
+ for (;;) {
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
+ &zc) == 0) {
+ /*
+ * The real error is returned in the zc_cookie field.
+ */
+ error = zc.zc_cookie;
+ break;
+ }
+
+ if (errno == ENOMEM) {
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ } else {
+ zcmd_free_nvlists(&zc);
+ if (errno == ENOENT || errno == EINVAL)
+ *missing = B_TRUE;
+ zhp->zpool_state = POOL_STATE_UNAVAIL;
+ return (0);
+ }
+ }
+
+ if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+
+ zcmd_free_nvlists(&zc);
+
+ zhp->zpool_config_size = zc.zc_nvlist_dst_size;
+
+ if (zhp->zpool_config != NULL) {
+ uint64_t oldtxg, newtxg;
+
+ verify(nvlist_lookup_uint64(zhp->zpool_config,
+ ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0);
+ verify(nvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0);
+
+ nvlist_free(zhp->zpool_old_config);
+
+ if (oldtxg != newtxg) {
+ nvlist_free(zhp->zpool_config);
+ zhp->zpool_old_config = NULL;
+ } else {
+ zhp->zpool_old_config = zhp->zpool_config;
+ }
+ }
+
+ zhp->zpool_config = config;
+ if (error)
+ zhp->zpool_state = POOL_STATE_UNAVAIL;
+ else
+ zhp->zpool_state = POOL_STATE_ACTIVE;
+
+ return (0);
+}
+
+/*
+ * The following environment variables are undocumented
+ * and should be used for testing purposes only:
+ *
+ * __ZFS_POOL_EXCLUDE - don't iterate over the pools it lists
+ * __ZFS_POOL_RESTRICT - iterate only over the pools it lists
+ *
+ * This function returns B_TRUE if the pool should be skipped
+ * during iteration.
+ */
+boolean_t
+zpool_skip_pool(const char *poolname)
+{
+ static boolean_t initialized = B_FALSE;
+ static const char *exclude = NULL;
+ static const char *restricted = NULL;
+
+ const char *cur, *end;
+ int len;
+ int namelen = strlen(poolname);
+
+ if (!initialized) {
+ initialized = B_TRUE;
+ exclude = getenv("__ZFS_POOL_EXCLUDE");
+ restricted = getenv("__ZFS_POOL_RESTRICT");
+ }
+
+ if (exclude != NULL) {
+ cur = exclude;
+ do {
+ end = strchr(cur, ' ');
+ len = (NULL == end) ? strlen(cur) : (end - cur);
+ if (len == namelen && 0 == strncmp(cur, poolname, len))
+ return (B_TRUE);
+ cur += (len + 1);
+ } while (NULL != end);
+ }
+
+ if (NULL == restricted)
+ return (B_FALSE);
+
+ cur = restricted;
+ do {
+ end = strchr(cur, ' ');
+ len = (NULL == end) ? strlen(cur) : (end - cur);
+
+ if (len == namelen && 0 == strncmp(cur, poolname, len)) {
+ return (B_FALSE);
+ }
+
+ cur += (len + 1);
+ } while (NULL != end);
+
+ return (B_TRUE);
+}
+
+/*
+ * Iterate over all pools in the system.
+ */
+int
+zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
+{
+ config_node_t *cn;
+ zpool_handle_t *zhp;
+ int ret;
+
+ /*
+ * If someone makes a recursive call to zpool_iter(), we want to avoid
+ * refreshing the namespace because that will invalidate the parent
+ * context. We allow recursive calls, but simply re-use the same
+ * namespace AVL tree.
+ */
+ if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0)
+ return (-1);
+
+ hdl->libzfs_pool_iter++;
+ for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
+ cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
+
+ if (zpool_skip_pool(cn->cn_name))
+ continue;
+
+ if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
+ hdl->libzfs_pool_iter--;
+ return (-1);
+ }
+
+ if (zhp == NULL)
+ continue;
+
+ if ((ret = func(zhp, data)) != 0) {
+ hdl->libzfs_pool_iter--;
+ return (ret);
+ }
+ }
+ hdl->libzfs_pool_iter--;
+
+ return (0);
+}
+
+/*
+ * Iterate over root datasets, calling the given function for each. The zfs
+ * handle passed each time must be explicitly closed by the callback.
+ */
+int
+zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
+{
+ config_node_t *cn;
+ zfs_handle_t *zhp;
+ int ret;
+
+ if (namespace_reload(hdl) != 0)
+ return (-1);
+
+ for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
+ cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
+
+ if (zpool_skip_pool(cn->cn_name))
+ continue;
+
+ if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
+ continue;
+
+ if ((ret = func(zhp, data)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
new file mode 100644
index 000000000000..e0728e3b6285
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
@@ -0,0 +1,5289 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
+ * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright (c) 2013 Martin Matuska. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2017 Nexenta Systems, Inc.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
+ * Copyright 2017-2018 RackTop Systems.
+ * Copyright (c) 2019 Datto Inc.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <libintl.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <zone.h>
+#include <fcntl.h>
+#include <sys/mntent.h>
+#include <sys/mount.h>
+#include <priv.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stddef.h>
+#ifdef illumos
+#include <idmap.h>
+#endif
+
+#include <sys/dnode.h>
+#include <sys/spa.h>
+#include <sys/zap.h>
+#include <sys/misc.h>
+#include <libzfs.h>
+
+#include "zfs_namecheck.h"
+#include "zfs_prop.h"
+#include "libzfs_impl.h"
+#include "zfs_deleg.h"
+
+static int userquota_propname_decode(const char *propname, boolean_t zoned,
+ zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
+
+/*
+ * Given a single type (not a mask of types), return the type in a human
+ * readable form.
+ */
+const char *
+zfs_type_to_name(zfs_type_t type)
+{
+ switch (type) {
+ case ZFS_TYPE_FILESYSTEM:
+ return (dgettext(TEXT_DOMAIN, "filesystem"));
+ case ZFS_TYPE_SNAPSHOT:
+ return (dgettext(TEXT_DOMAIN, "snapshot"));
+ case ZFS_TYPE_VOLUME:
+ return (dgettext(TEXT_DOMAIN, "volume"));
+ case ZFS_TYPE_POOL:
+ return (dgettext(TEXT_DOMAIN, "pool"));
+ case ZFS_TYPE_BOOKMARK:
+ return (dgettext(TEXT_DOMAIN, "bookmark"));
+ default:
+ assert(!"unhandled zfs_type_t");
+ }
+
+ return (NULL);
+}
+
+/*
+ * Validate a ZFS path. This is used even before trying to open the dataset, to
+ * provide a more meaningful error message. We call zfs_error_aux() to
+ * explain exactly why the name was not valid.
+ */
+int
+zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
+ boolean_t modifying)
+{
+ namecheck_err_t why;
+ char what;
+
+ if (entity_namecheck(path, &why, &what) != 0) {
+ if (hdl != NULL) {
+ switch (why) {
+ case NAME_ERR_TOOLONG:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "name is too long"));
+ break;
+
+ case NAME_ERR_LEADING_SLASH:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "leading slash in name"));
+ break;
+
+ case NAME_ERR_EMPTY_COMPONENT:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "empty component in name"));
+ break;
+
+ case NAME_ERR_TRAILING_SLASH:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "trailing slash in name"));
+ break;
+
+ case NAME_ERR_INVALCHAR:
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "invalid character "
+ "'%c' in name"), what);
+ break;
+
+ case NAME_ERR_MULTIPLE_DELIMITERS:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "multiple '@' and/or '#' delimiters in "
+ "name"));
+ break;
+
+ case NAME_ERR_NOLETTER:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool doesn't begin with a letter"));
+ break;
+
+ case NAME_ERR_RESERVED:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "name is reserved"));
+ break;
+
+ case NAME_ERR_DISKLIKE:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "reserved disk name"));
+ break;
+
+ default:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "(%d) not defined"), why);
+ break;
+ }
+ }
+
+ return (0);
+ }
+
+ if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
+ if (hdl != NULL)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "snapshot delimiter '@' is not expected here"));
+ return (0);
+ }
+
+ if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
+ if (hdl != NULL)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "missing '@' delimiter in snapshot name"));
+ return (0);
+ }
+
+ if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) {
+ if (hdl != NULL)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "bookmark delimiter '#' is not expected here"));
+ return (0);
+ }
+
+ if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) {
+ if (hdl != NULL)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "missing '#' delimiter in bookmark name"));
+ return (0);
+ }
+
+ if (modifying && strchr(path, '%') != NULL) {
+ if (hdl != NULL)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid character %c in name"), '%');
+ return (0);
+ }
+
+ return (-1);
+}
+
+int
+zfs_name_valid(const char *name, zfs_type_t type)
+{
+ if (type == ZFS_TYPE_POOL)
+ return (zpool_name_valid(NULL, B_FALSE, name));
+ return (zfs_validate_name(NULL, name, type, B_FALSE));
+}
+
+/*
+ * This function takes the raw DSL properties, and filters out the user-defined
+ * properties into a separate nvlist.
+ */
+static nvlist_t *
+process_user_props(zfs_handle_t *zhp, nvlist_t *props)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ nvpair_t *elem;
+ nvlist_t *propval;
+ nvlist_t *nvl;
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
+ (void) no_memory(hdl);
+ return (NULL);
+ }
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
+ if (!zfs_prop_user(nvpair_name(elem)))
+ continue;
+
+ verify(nvpair_value_nvlist(elem, &propval) == 0);
+ if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) {
+ nvlist_free(nvl);
+ (void) no_memory(hdl);
+ return (NULL);
+ }
+ }
+
+ return (nvl);
+}
+
+static zpool_handle_t *
+zpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ zpool_handle_t *zph;
+
+ if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
+ if (hdl->libzfs_pool_handles != NULL)
+ zph->zpool_next = hdl->libzfs_pool_handles;
+ hdl->libzfs_pool_handles = zph;
+ }
+ return (zph);
+}
+
+static zpool_handle_t *
+zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ zpool_handle_t *zph = hdl->libzfs_pool_handles;
+
+ while ((zph != NULL) &&
+ (strncmp(pool_name, zpool_get_name(zph), len) != 0))
+ zph = zph->zpool_next;
+ return (zph);
+}
+
+/*
+ * Returns a handle to the pool that contains the provided dataset.
+ * If a handle to that pool already exists then that handle is returned.
+ * Otherwise, a new handle is created and added to the list of handles.
+ */
+static zpool_handle_t *
+zpool_handle(zfs_handle_t *zhp)
+{
+ char *pool_name;
+ int len;
+ zpool_handle_t *zph;
+
+ len = strcspn(zhp->zfs_name, "/@#") + 1;
+ pool_name = zfs_alloc(zhp->zfs_hdl, len);
+ (void) strlcpy(pool_name, zhp->zfs_name, len);
+
+ zph = zpool_find_handle(zhp, pool_name, len);
+ if (zph == NULL)
+ zph = zpool_add_handle(zhp, pool_name);
+
+ free(pool_name);
+ return (zph);
+}
+
+void
+zpool_free_handles(libzfs_handle_t *hdl)
+{
+ zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
+
+ while (zph != NULL) {
+ next = zph->zpool_next;
+ zpool_close(zph);
+ zph = next;
+ }
+ hdl->libzfs_pool_handles = NULL;
+}
+
+/*
+ * Utility function to gather stats (objset and zpl) for the given object.
+ */
+static int
+get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+ (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
+
+ while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
+ if (errno == ENOMEM) {
+ if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
+ return (-1);
+ }
+ } else {
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Utility function to get the received properties of the given object.
+ */
+static int
+get_recvd_props_ioctl(zfs_handle_t *zhp)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ nvlist_t *recvdprops;
+ zfs_cmd_t zc = { 0 };
+ int err;
+
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
+ return (-1);
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+ while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) {
+ if (errno == ENOMEM) {
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ return (-1);
+ }
+ } else {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ }
+
+ err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops);
+ zcmd_free_nvlists(&zc);
+ if (err != 0)
+ return (-1);
+
+ nvlist_free(zhp->zfs_recvd_props);
+ zhp->zfs_recvd_props = recvdprops;
+
+ return (0);
+}
+
+static int
+put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
+{
+ nvlist_t *allprops, *userprops;
+
+ zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
+
+ if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
+ return (-1);
+ }
+
+ /*
+ * XXX Why do we store the user props separately, in addition to
+ * storing them in zfs_props?
+ */
+ if ((userprops = process_user_props(zhp, allprops)) == NULL) {
+ nvlist_free(allprops);
+ return (-1);
+ }
+
+ nvlist_free(zhp->zfs_props);
+ nvlist_free(zhp->zfs_user_props);
+
+ zhp->zfs_props = allprops;
+ zhp->zfs_user_props = userprops;
+
+ return (0);
+}
+
+static int
+get_stats(zfs_handle_t *zhp)
+{
+ int rc = 0;
+ zfs_cmd_t zc = { 0 };
+
+ if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+ return (-1);
+ if (get_stats_ioctl(zhp, &zc) != 0)
+ rc = -1;
+ else if (put_stats_zhdl(zhp, &zc) != 0)
+ rc = -1;
+ zcmd_free_nvlists(&zc);
+ return (rc);
+}
+
+/*
+ * Refresh the properties currently stored in the handle.
+ */
+void
+zfs_refresh_properties(zfs_handle_t *zhp)
+{
+ (void) get_stats(zhp);
+}
+
+/*
+ * Makes a handle from the given dataset name. Used by zfs_open() and
+ * zfs_iter_* to create child handles on the fly.
+ */
+static int
+make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
+{
+ if (put_stats_zhdl(zhp, zc) != 0)
+ return (-1);
+
+ /*
+ * We've managed to open the dataset and gather statistics. Determine
+ * the high-level type.
+ */
+ if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
+ zhp->zfs_head_type = ZFS_TYPE_VOLUME;
+ else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
+ zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
+ else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER)
+ return (-1);
+ else
+ abort();
+
+ if (zhp->zfs_dmustats.dds_is_snapshot)
+ zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
+ else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
+ zhp->zfs_type = ZFS_TYPE_VOLUME;
+ else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
+ zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
+ else
+ abort(); /* we should never see any other types */
+
+ if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL)
+ return (-1);
+
+ return (0);
+}
+
+zfs_handle_t *
+make_dataset_handle(libzfs_handle_t *hdl, const char *path)
+{
+ zfs_cmd_t zc = { 0 };
+
+ zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+ if (zhp == NULL)
+ return (NULL);
+
+ zhp->zfs_hdl = hdl;
+ (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
+ free(zhp);
+ return (NULL);
+ }
+ if (get_stats_ioctl(zhp, &zc) == -1) {
+ zcmd_free_nvlists(&zc);
+ free(zhp);
+ return (NULL);
+ }
+ if (make_dataset_handle_common(zhp, &zc) == -1) {
+ free(zhp);
+ zhp = NULL;
+ }
+ zcmd_free_nvlists(&zc);
+ return (zhp);
+}
+
+zfs_handle_t *
+make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
+{
+ zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+ if (zhp == NULL)
+ return (NULL);
+
+ zhp->zfs_hdl = hdl;
+ (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
+ if (make_dataset_handle_common(zhp, zc) == -1) {
+ free(zhp);
+ return (NULL);
+ }
+ return (zhp);
+}
+
+zfs_handle_t *
+make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc)
+{
+ zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+ if (zhp == NULL)
+ return (NULL);
+
+ zhp->zfs_hdl = pzhp->zfs_hdl;
+ (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
+ zhp->zfs_head_type = pzhp->zfs_type;
+ zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
+ zhp->zpool_hdl = zpool_handle(zhp);
+ return (zhp);
+}
+
+zfs_handle_t *
+zfs_handle_dup(zfs_handle_t *zhp_orig)
+{
+ zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+ if (zhp == NULL)
+ return (NULL);
+
+ zhp->zfs_hdl = zhp_orig->zfs_hdl;
+ zhp->zpool_hdl = zhp_orig->zpool_hdl;
+ (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
+ sizeof (zhp->zfs_name));
+ zhp->zfs_type = zhp_orig->zfs_type;
+ zhp->zfs_head_type = zhp_orig->zfs_head_type;
+ zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
+ if (zhp_orig->zfs_props != NULL) {
+ if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
+ (void) no_memory(zhp->zfs_hdl);
+ zfs_close(zhp);
+ return (NULL);
+ }
+ }
+ if (zhp_orig->zfs_user_props != NULL) {
+ if (nvlist_dup(zhp_orig->zfs_user_props,
+ &zhp->zfs_user_props, 0) != 0) {
+ (void) no_memory(zhp->zfs_hdl);
+ zfs_close(zhp);
+ return (NULL);
+ }
+ }
+ if (zhp_orig->zfs_recvd_props != NULL) {
+ if (nvlist_dup(zhp_orig->zfs_recvd_props,
+ &zhp->zfs_recvd_props, 0)) {
+ (void) no_memory(zhp->zfs_hdl);
+ zfs_close(zhp);
+ return (NULL);
+ }
+ }
+ zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
+ if (zhp_orig->zfs_mntopts != NULL) {
+ zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
+ zhp_orig->zfs_mntopts);
+ }
+ zhp->zfs_props_table = zhp_orig->zfs_props_table;
+ return (zhp);
+}
+
+boolean_t
+zfs_bookmark_exists(const char *path)
+{
+ nvlist_t *bmarks;
+ nvlist_t *props;
+ char fsname[ZFS_MAX_DATASET_NAME_LEN];
+ char *bmark_name;
+ char *pound;
+ int err;
+ boolean_t rv;
+
+
+ (void) strlcpy(fsname, path, sizeof (fsname));
+ pound = strchr(fsname, '#');
+ if (pound == NULL)
+ return (B_FALSE);
+
+ *pound = '\0';
+ bmark_name = pound + 1;
+ props = fnvlist_alloc();
+ err = lzc_get_bookmarks(fsname, props, &bmarks);
+ nvlist_free(props);
+ if (err != 0) {
+ nvlist_free(bmarks);
+ return (B_FALSE);
+ }
+
+ rv = nvlist_exists(bmarks, bmark_name);
+ nvlist_free(bmarks);
+ return (rv);
+}
+
+zfs_handle_t *
+make_bookmark_handle(zfs_handle_t *parent, const char *path,
+ nvlist_t *bmark_props)
+{
+ zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+ if (zhp == NULL)
+ return (NULL);
+
+ /* Fill in the name. */
+ zhp->zfs_hdl = parent->zfs_hdl;
+ (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
+
+ /* Set the property lists. */
+ if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) {
+ free(zhp);
+ return (NULL);
+ }
+
+ /* Set the types. */
+ zhp->zfs_head_type = parent->zfs_head_type;
+ zhp->zfs_type = ZFS_TYPE_BOOKMARK;
+
+ if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) {
+ nvlist_free(zhp->zfs_props);
+ free(zhp);
+ return (NULL);
+ }
+
+ return (zhp);
+}
+
+struct zfs_open_bookmarks_cb_data {
+ const char *path;
+ zfs_handle_t *zhp;
+};
+
+static int
+zfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data)
+{
+ struct zfs_open_bookmarks_cb_data *dp = data;
+
+ /*
+ * Is it the one we are looking for?
+ */
+ if (strcmp(dp->path, zfs_get_name(zhp)) == 0) {
+ /*
+ * We found it. Save it and let the caller know we are done.
+ */
+ dp->zhp = zhp;
+ return (EEXIST);
+ }
+
+ /*
+ * Not found. Close the handle and ask for another one.
+ */
+ zfs_close(zhp);
+ return (0);
+}
+
+/*
+ * Opens the given snapshot, bookmark, filesystem, or volume. The 'types'
+ * argument is a mask of acceptable types. The function will print an
+ * appropriate error message and return NULL if it can't be opened.
+ */
+zfs_handle_t *
+zfs_open(libzfs_handle_t *hdl, const char *path, int types)
+{
+ zfs_handle_t *zhp;
+ char errbuf[1024];
+ char *bookp;
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
+
+ /*
+ * Validate the name before we even try to open it.
+ */
+ if (!zfs_validate_name(hdl, path, types, B_FALSE)) {
+ (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
+ return (NULL);
+ }
+
+ /*
+ * Bookmarks needs to be handled separately.
+ */
+ bookp = strchr(path, '#');
+ if (bookp == NULL) {
+ /*
+ * Try to get stats for the dataset, which will tell us if it
+ * exists.
+ */
+ errno = 0;
+ if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
+ (void) zfs_standard_error(hdl, errno, errbuf);
+ return (NULL);
+ }
+ } else {
+ char dsname[ZFS_MAX_DATASET_NAME_LEN];
+ zfs_handle_t *pzhp;
+ struct zfs_open_bookmarks_cb_data cb_data = {path, NULL};
+
+ /*
+ * We need to cut out '#' and everything after '#'
+ * to get the parent dataset name only.
+ */
+ assert(bookp - path < sizeof (dsname));
+ (void) strncpy(dsname, path, bookp - path);
+ dsname[bookp - path] = '\0';
+
+ /*
+ * Create handle for the parent dataset.
+ */
+ errno = 0;
+ if ((pzhp = make_dataset_handle(hdl, dsname)) == NULL) {
+ (void) zfs_standard_error(hdl, errno, errbuf);
+ return (NULL);
+ }
+
+ /*
+ * Iterate bookmarks to find the right one.
+ */
+ errno = 0;
+ if ((zfs_iter_bookmarks(pzhp, zfs_open_bookmarks_cb,
+ &cb_data) == 0) && (cb_data.zhp == NULL)) {
+ (void) zfs_error(hdl, EZFS_NOENT, errbuf);
+ zfs_close(pzhp);
+ return (NULL);
+ }
+ if (cb_data.zhp == NULL) {
+ (void) zfs_standard_error(hdl, errno, errbuf);
+ zfs_close(pzhp);
+ return (NULL);
+ }
+ zhp = cb_data.zhp;
+
+ /*
+ * Cleanup.
+ */
+ zfs_close(pzhp);
+ }
+
+ if (zhp == NULL) {
+ char *at = strchr(path, '@');
+
+ if (at != NULL)
+ *at = '\0';
+ errno = 0;
+ if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
+ (void) zfs_standard_error(hdl, errno, errbuf);
+ return (NULL);
+ }
+ if (at != NULL)
+ *at = '@';
+ (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
+ zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
+ }
+
+ if (!(types & zhp->zfs_type)) {
+ (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+ zfs_close(zhp);
+ return (NULL);
+ }
+
+ return (zhp);
+}
+
+/*
+ * Release a ZFS handle. Nothing to do but free the associated memory.
+ */
+void
+zfs_close(zfs_handle_t *zhp)
+{
+ if (zhp->zfs_mntopts)
+ free(zhp->zfs_mntopts);
+ nvlist_free(zhp->zfs_props);
+ nvlist_free(zhp->zfs_user_props);
+ nvlist_free(zhp->zfs_recvd_props);
+ free(zhp);
+}
+
+typedef struct mnttab_node {
+ struct mnttab mtn_mt;
+ avl_node_t mtn_node;
+} mnttab_node_t;
+
+static int
+libzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
+{
+ const mnttab_node_t *mtn1 = (const mnttab_node_t *)arg1;
+ const mnttab_node_t *mtn2 = (const mnttab_node_t *)arg2;
+ int rv;
+
+ rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
+
+ return (AVL_ISIGN(rv));
+}
+
+void
+libzfs_mnttab_init(libzfs_handle_t *hdl)
+{
+ pthread_mutex_init(&hdl->libzfs_mnttab_cache_lock, NULL);
+ assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
+ avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
+ sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
+}
+
+void
+libzfs_mnttab_update(libzfs_handle_t *hdl)
+{
+ struct mnttab entry;
+
+ rewind(hdl->libzfs_mnttab);
+ while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
+ mnttab_node_t *mtn;
+
+ if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
+ continue;
+ mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
+ mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special);
+ mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp);
+ mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype);
+ mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts);
+ avl_add(&hdl->libzfs_mnttab_cache, mtn);
+ }
+}
+
+void
+libzfs_mnttab_fini(libzfs_handle_t *hdl)
+{
+ void *cookie = NULL;
+ mnttab_node_t *mtn;
+
+ while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie))
+ != NULL) {
+ free(mtn->mtn_mt.mnt_special);
+ free(mtn->mtn_mt.mnt_mountp);
+ free(mtn->mtn_mt.mnt_fstype);
+ free(mtn->mtn_mt.mnt_mntopts);
+ free(mtn);
+ }
+ avl_destroy(&hdl->libzfs_mnttab_cache);
+ (void) pthread_mutex_destroy(&hdl->libzfs_mnttab_cache_lock);
+}
+
+void
+libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
+{
+ hdl->libzfs_mnttab_enable = enable;
+}
+
+int
+libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
+ struct mnttab *entry)
+{
+ mnttab_node_t find;
+ mnttab_node_t *mtn;
+ int ret = ENOENT;
+
+ if (!hdl->libzfs_mnttab_enable) {
+ struct mnttab srch = { 0 };
+
+ if (avl_numnodes(&hdl->libzfs_mnttab_cache))
+ libzfs_mnttab_fini(hdl);
+ rewind(hdl->libzfs_mnttab);
+ srch.mnt_special = (char *)fsname;
+ srch.mnt_fstype = MNTTYPE_ZFS;
+ if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0)
+ return (0);
+ else
+ return (ENOENT);
+ }
+
+ pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock);
+ if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
+ libzfs_mnttab_update(hdl);
+
+ find.mtn_mt.mnt_special = (char *)fsname;
+ mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
+ if (mtn) {
+ *entry = mtn->mtn_mt;
+ ret = 0;
+ }
+ pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock);
+ return (ret);
+}
+
+void
+libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
+ const char *mountp, const char *mntopts)
+{
+ mnttab_node_t *mtn;
+
+ pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock);
+ if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) {
+ mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
+ mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
+ mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
+ mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
+ mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
+ avl_add(&hdl->libzfs_mnttab_cache, mtn);
+ }
+ pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock);
+}
+
+void
+libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
+{
+ mnttab_node_t find;
+ mnttab_node_t *ret;
+
+ pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock);
+ find.mtn_mt.mnt_special = (char *)fsname;
+ if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL))
+ != NULL) {
+ avl_remove(&hdl->libzfs_mnttab_cache, ret);
+ free(ret->mtn_mt.mnt_special);
+ free(ret->mtn_mt.mnt_mountp);
+ free(ret->mtn_mt.mnt_fstype);
+ free(ret->mtn_mt.mnt_mntopts);
+ free(ret);
+ }
+ pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock);
+}
+
+int
+zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
+{
+ zpool_handle_t *zpool_handle = zhp->zpool_hdl;
+
+ if (zpool_handle == NULL)
+ return (-1);
+
+ *spa_version = zpool_get_prop_int(zpool_handle,
+ ZPOOL_PROP_VERSION, NULL);
+ return (0);
+}
+
+/*
+ * The choice of reservation property depends on the SPA version.
+ */
+static int
+zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
+{
+ int spa_version;
+
+ if (zfs_spa_version(zhp, &spa_version) < 0)
+ return (-1);
+
+ if (spa_version >= SPA_VERSION_REFRESERVATION)
+ *resv_prop = ZFS_PROP_REFRESERVATION;
+ else
+ *resv_prop = ZFS_PROP_RESERVATION;
+
+ return (0);
+}
+
+/*
+ * Given an nvlist of properties to set, validates that they are correct, and
+ * parses any numeric properties (index, boolean, etc) if they are specified as
+ * strings.
+ */
+nvlist_t *
+zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
+ uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl,
+ const char *errbuf)
+{
+ nvpair_t *elem;
+ uint64_t intval;
+ char *strval;
+ zfs_prop_t prop;
+ nvlist_t *ret;
+ int chosen_normal = -1;
+ int chosen_utf = -1;
+
+ if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
+ (void) no_memory(hdl);
+ return (NULL);
+ }
+
+ /*
+ * Make sure this property is valid and applies to this type.
+ */
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
+ const char *propname = nvpair_name(elem);
+
+ prop = zfs_name_to_prop(propname);
+ if (prop == ZPROP_INVAL && zfs_prop_user(propname)) {
+ /*
+ * This is a user property: make sure it's a
+ * string, and that it's less than ZAP_MAXNAMELEN.
+ */
+ if (nvpair_type(elem) != DATA_TYPE_STRING) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a string"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property name '%s' is too long"),
+ propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ (void) nvpair_value_string(elem, &strval);
+ if (nvlist_add_string(ret, propname, strval) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+ continue;
+ }
+
+ /*
+ * Currently, only user properties can be modified on
+ * snapshots.
+ */
+ if (type == ZFS_TYPE_SNAPSHOT) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "this property can not be modified for snapshots"));
+ (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
+ goto error;
+ }
+
+ if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) {
+ zfs_userquota_prop_t uqtype;
+ char newpropname[128];
+ char domain[128];
+ uint64_t rid;
+ uint64_t valary[3];
+
+ if (userquota_propname_decode(propname, zoned,
+ &uqtype, domain, sizeof (domain), &rid) != 0) {
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN,
+ "'%s' has an invalid user/group name"),
+ propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (uqtype != ZFS_PROP_USERQUOTA &&
+ uqtype != ZFS_PROP_GROUPQUOTA) {
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "'%s' is readonly"),
+ propname);
+ (void) zfs_error(hdl, EZFS_PROPREADONLY,
+ errbuf);
+ goto error;
+ }
+
+ if (nvpair_type(elem) == DATA_TYPE_STRING) {
+ (void) nvpair_value_string(elem, &strval);
+ if (strcmp(strval, "none") == 0) {
+ intval = 0;
+ } else if (zfs_nicestrtonum(hdl,
+ strval, &intval) != 0) {
+ (void) zfs_error(hdl,
+ EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ } else if (nvpair_type(elem) ==
+ DATA_TYPE_UINT64) {
+ (void) nvpair_value_uint64(elem, &intval);
+ if (intval == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "use 'none' to disable "
+ "userquota/groupquota"));
+ goto error;
+ }
+ } else {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a number"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ /*
+ * Encode the prop name as
+ * userquota@<hex-rid>-domain, to make it easy
+ * for the kernel to decode.
+ */
+ (void) snprintf(newpropname, sizeof (newpropname),
+ "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype],
+ (longlong_t)rid, domain);
+ valary[0] = uqtype;
+ valary[1] = rid;
+ valary[2] = intval;
+ if (nvlist_add_uint64_array(ret, newpropname,
+ valary, 3) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+ continue;
+ } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is readonly"),
+ propname);
+ (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
+ goto error;
+ }
+
+ if (prop == ZPROP_INVAL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid property '%s'"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (!zfs_prop_valid_for_type(prop, type)) {
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "'%s' does not "
+ "apply to datasets of this type"), propname);
+ (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
+ goto error;
+ }
+
+ if (zfs_prop_readonly(prop) &&
+ (!zfs_prop_setonce(prop) || zhp != NULL)) {
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "'%s' is readonly"),
+ propname);
+ (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
+ goto error;
+ }
+
+ if (zprop_parse_value(hdl, elem, prop, type, ret,
+ &strval, &intval, errbuf) != 0)
+ goto error;
+
+ /*
+ * Perform some additional checks for specific properties.
+ */
+ switch (prop) {
+ case ZFS_PROP_VERSION:
+ {
+ int version;
+
+ if (zhp == NULL)
+ break;
+ version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+ if (intval < version) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Can not downgrade; already at version %u"),
+ version);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+ }
+
+ case ZFS_PROP_VOLBLOCKSIZE:
+ case ZFS_PROP_RECORDSIZE:
+ {
+ int maxbs = SPA_MAXBLOCKSIZE;
+ if (zpool_hdl != NULL) {
+ maxbs = zpool_get_prop_int(zpool_hdl,
+ ZPOOL_PROP_MAXBLOCKSIZE, NULL);
+ }
+ /*
+ * Volumes are limited to a volblocksize of 128KB,
+ * because they typically service workloads with
+ * small random writes, which incur a large performance
+ * penalty with large blocks.
+ */
+ if (prop == ZFS_PROP_VOLBLOCKSIZE)
+ maxbs = SPA_OLD_MAXBLOCKSIZE;
+ /*
+ * The value must be a power of two between
+ * SPA_MINBLOCKSIZE and maxbs.
+ */
+ if (intval < SPA_MINBLOCKSIZE ||
+ intval > maxbs || !ISP2(intval)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be power of 2 from 512B "
+ "to %uKB"), propname, maxbs >> 10);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+ }
+
+ case ZFS_PROP_SPECIAL_SMALL_BLOCKS:
+ if (zpool_hdl != NULL) {
+ char state[64] = "";
+
+ /*
+ * Issue a warning but do not fail so that
+ * tests for setable properties succeed.
+ */
+ if (zpool_prop_get_feature(zpool_hdl,
+ "feature@allocation_classes", state,
+ sizeof (state)) != 0 ||
+ strcmp(state, ZFS_FEATURE_ACTIVE) != 0) {
+ (void) fprintf(stderr, gettext(
+ "%s: property requires a special "
+ "device in the pool\n"), propname);
+ }
+ }
+ if (intval != 0 &&
+ (intval < SPA_MINBLOCKSIZE ||
+ intval > SPA_OLD_MAXBLOCKSIZE || !ISP2(intval))) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid '%s=%d' property: must be zero or "
+ "a power of 2 from 512B to 128K"), propname,
+ intval);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+
+ case ZFS_PROP_MLSLABEL:
+ {
+#ifdef illumos
+ /*
+ * Verify the mlslabel string and convert to
+ * internal hex label string.
+ */
+
+ m_label_t *new_sl;
+ char *hex = NULL; /* internal label string */
+
+ /* Default value is already OK. */
+ if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
+ break;
+
+ /* Verify the label can be converted to binary form */
+ if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) ||
+ (str_to_label(strval, &new_sl, MAC_LABEL,
+ L_NO_CORRECTION, NULL) == -1)) {
+ goto badlabel;
+ }
+
+ /* Now translate to hex internal label string */
+ if (label_to_str(new_sl, &hex, M_INTERNAL,
+ DEF_NAMES) != 0) {
+ if (hex)
+ free(hex);
+ goto badlabel;
+ }
+ m_label_free(new_sl);
+
+ /* If string is already in internal form, we're done. */
+ if (strcmp(strval, hex) == 0) {
+ free(hex);
+ break;
+ }
+
+ /* Replace the label string with the internal form. */
+ (void) nvlist_remove(ret, zfs_prop_to_name(prop),
+ DATA_TYPE_STRING);
+ verify(nvlist_add_string(ret, zfs_prop_to_name(prop),
+ hex) == 0);
+ free(hex);
+
+ break;
+
+badlabel:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid mlslabel '%s'"), strval);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ m_label_free(new_sl); /* OK if null */
+#else /* !illumos */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "mlslabel is not supported on FreeBSD"));
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+#endif /* illumos */
+ goto error;
+
+ }
+
+ case ZFS_PROP_MOUNTPOINT:
+ {
+ namecheck_err_t why;
+
+ if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
+ strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
+ break;
+
+ if (mountpoint_namecheck(strval, &why)) {
+ switch (why) {
+ case NAME_ERR_LEADING_SLASH:
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN,
+ "'%s' must be an absolute path, "
+ "'none', or 'legacy'"), propname);
+ break;
+ case NAME_ERR_TOOLONG:
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN,
+ "component of '%s' is too long"),
+ propname);
+ break;
+
+ default:
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN,
+ "(%d) not defined"),
+ why);
+ break;
+ }
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ }
+
+ /*FALLTHRU*/
+
+ case ZFS_PROP_SHARESMB:
+ case ZFS_PROP_SHARENFS:
+ /*
+ * For the mountpoint and sharenfs or sharesmb
+ * properties, check if it can be set in a
+ * global/non-global zone based on
+ * the zoned property value:
+ *
+ * global zone non-global zone
+ * --------------------------------------------------
+ * zoned=on mountpoint (no) mountpoint (yes)
+ * sharenfs (no) sharenfs (no)
+ * sharesmb (no) sharesmb (no)
+ *
+ * zoned=off mountpoint (yes) N/A
+ * sharenfs (yes)
+ * sharesmb (yes)
+ */
+ if (zoned) {
+ if (getzoneid() == GLOBAL_ZONEID) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be set on "
+ "dataset in a non-global zone"),
+ propname);
+ (void) zfs_error(hdl, EZFS_ZONED,
+ errbuf);
+ goto error;
+ } else if (prop == ZFS_PROP_SHARENFS ||
+ prop == ZFS_PROP_SHARESMB) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be set in "
+ "a non-global zone"), propname);
+ (void) zfs_error(hdl, EZFS_ZONED,
+ errbuf);
+ goto error;
+ }
+ } else if (getzoneid() != GLOBAL_ZONEID) {
+ /*
+ * If zoned property is 'off', this must be in
+ * a global zone. If not, something is wrong.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be set while dataset "
+ "'zoned' property is set"), propname);
+ (void) zfs_error(hdl, EZFS_ZONED, errbuf);
+ goto error;
+ }
+
+ /*
+ * At this point, it is legitimate to set the
+ * property. Now we want to make sure that the
+ * property value is valid if it is sharenfs.
+ */
+ if ((prop == ZFS_PROP_SHARENFS ||
+ prop == ZFS_PROP_SHARESMB) &&
+ strcmp(strval, "on") != 0 &&
+ strcmp(strval, "off") != 0) {
+ zfs_share_proto_t proto;
+
+ if (prop == ZFS_PROP_SHARESMB)
+ proto = PROTO_SMB;
+ else
+ proto = PROTO_NFS;
+
+ /*
+ * Must be an valid sharing protocol
+ * option string so init the libshare
+ * in order to enable the parser and
+ * then parse the options. We use the
+ * control API since we don't care about
+ * the current configuration and don't
+ * want the overhead of loading it
+ * until we actually do something.
+ */
+
+ if (zfs_init_libshare(hdl,
+ SA_INIT_CONTROL_API) != SA_OK) {
+ /*
+ * An error occurred so we can't do
+ * anything
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be set: problem "
+ "in share initialization"),
+ propname);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+
+ if (zfs_parse_options(strval, proto) != SA_OK) {
+ /*
+ * There was an error in parsing so
+ * deal with it by issuing an error
+ * message and leaving after
+ * uninitializing the the libshare
+ * interface.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be set to invalid "
+ "options"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ zfs_uninit_libshare(hdl);
+ goto error;
+ }
+ zfs_uninit_libshare(hdl);
+ }
+
+ break;
+
+ case ZFS_PROP_UTF8ONLY:
+ chosen_utf = (int)intval;
+ break;
+
+ case ZFS_PROP_NORMALIZE:
+ chosen_normal = (int)intval;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * For changes to existing volumes, we have some additional
+ * checks to enforce.
+ */
+ if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
+ uint64_t volsize = zfs_prop_get_int(zhp,
+ ZFS_PROP_VOLSIZE);
+ uint64_t blocksize = zfs_prop_get_int(zhp,
+ ZFS_PROP_VOLBLOCKSIZE);
+ char buf[64];
+
+ switch (prop) {
+ case ZFS_PROP_RESERVATION:
+ if (intval > volsize) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is greater than current "
+ "volume size"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+ break;
+
+ case ZFS_PROP_REFRESERVATION:
+ if (intval > volsize && intval != UINT64_MAX) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is greater than current "
+ "volume size"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+ break;
+
+ case ZFS_PROP_VOLSIZE:
+ if (intval % blocksize != 0) {
+ zfs_nicenum(blocksize, buf,
+ sizeof (buf));
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a multiple of "
+ "volume block size (%s)"),
+ propname, buf);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+
+ if (intval == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be zero"),
+ propname);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ /*
+ * If normalization was chosen, but no UTF8 choice was made,
+ * enforce rejection of non-UTF8 names.
+ *
+ * If normalization was chosen, but rejecting non-UTF8 names
+ * was explicitly not chosen, it is an error.
+ */
+ if (chosen_normal > 0 && chosen_utf < 0) {
+ if (nvlist_add_uint64(ret,
+ zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+ } else if (chosen_normal > 0 && chosen_utf == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be set 'on' if normalization chosen"),
+ zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ return (ret);
+
+error:
+ nvlist_free(ret);
+ return (NULL);
+}
+
+int
+zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
+{
+ uint64_t old_volsize;
+ uint64_t new_volsize;
+ uint64_t old_reservation;
+ uint64_t new_reservation;
+ zfs_prop_t resv_prop;
+ nvlist_t *props;
+
+ /*
+ * If this is an existing volume, and someone is setting the volsize,
+ * make sure that it matches the reservation, or add it if necessary.
+ */
+ old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
+ if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
+ return (-1);
+ old_reservation = zfs_prop_get_int(zhp, resv_prop);
+
+ props = fnvlist_alloc();
+ fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
+
+ if ((zvol_volsize_to_reservation(old_volsize, props) !=
+ old_reservation) || nvlist_exists(nvl,
+ zfs_prop_to_name(resv_prop))) {
+ fnvlist_free(props);
+ return (0);
+ }
+ if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
+ &new_volsize) != 0) {
+ fnvlist_free(props);
+ return (-1);
+ }
+ new_reservation = zvol_volsize_to_reservation(new_volsize, props);
+ fnvlist_free(props);
+
+ if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
+ new_reservation) != 0) {
+ (void) no_memory(zhp->zfs_hdl);
+ return (-1);
+ }
+ return (1);
+}
+
+/*
+ * Helper for 'zfs {set|clone} refreservation=auto'. Must be called after
+ * zfs_valid_proplist(), as it is what sets the UINT64_MAX sentinal value.
+ * Return codes must match zfs_add_synthetic_resv().
+ */
+static int
+zfs_fix_auto_resv(zfs_handle_t *zhp, nvlist_t *nvl)
+{
+ uint64_t volsize;
+ uint64_t resvsize;
+ zfs_prop_t prop;
+ nvlist_t *props;
+
+ if (!ZFS_IS_VOLUME(zhp)) {
+ return (0);
+ }
+
+ if (zfs_which_resv_prop(zhp, &prop) != 0) {
+ return (-1);
+ }
+
+ if (prop != ZFS_PROP_REFRESERVATION) {
+ return (0);
+ }
+
+ if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(prop), &resvsize) != 0) {
+ /* No value being set, so it can't be "auto" */
+ return (0);
+ }
+ if (resvsize != UINT64_MAX) {
+ /* Being set to a value other than "auto" */
+ return (0);
+ }
+
+ props = fnvlist_alloc();
+
+ fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
+
+ if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
+ &volsize) != 0) {
+ volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
+ }
+
+ resvsize = zvol_volsize_to_reservation(volsize, props);
+ fnvlist_free(props);
+
+ (void) nvlist_remove_all(nvl, zfs_prop_to_name(prop));
+ if (nvlist_add_uint64(nvl, zfs_prop_to_name(prop), resvsize) != 0) {
+ (void) no_memory(zhp->zfs_hdl);
+ return (-1);
+ }
+ return (1);
+}
+
+void
+zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
+ char *errbuf)
+{
+ switch (err) {
+
+ case ENOSPC:
+ /*
+ * For quotas and reservations, ENOSPC indicates
+ * something different; setting a quota or reservation
+ * doesn't use any disk space.
+ */
+ switch (prop) {
+ case ZFS_PROP_QUOTA:
+ case ZFS_PROP_REFQUOTA:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "size is less than current used or "
+ "reserved space"));
+ (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
+ break;
+
+ case ZFS_PROP_RESERVATION:
+ case ZFS_PROP_REFRESERVATION:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "size is greater than available space"));
+ (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
+ break;
+
+ default:
+ (void) zfs_standard_error(hdl, err, errbuf);
+ break;
+ }
+ break;
+
+ case EBUSY:
+ (void) zfs_standard_error(hdl, EBUSY, errbuf);
+ break;
+
+ case EROFS:
+ (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
+ break;
+
+ case E2BIG:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property value too long"));
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ break;
+
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool and or dataset must be upgraded to set this "
+ "property or value"));
+ (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ break;
+
+ case ERANGE:
+ case EDOM:
+ if (prop == ZFS_PROP_COMPRESSION ||
+ prop == ZFS_PROP_RECORDSIZE) {
+ (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property setting is not allowed on "
+ "bootable datasets"));
+ (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
+ } else if (prop == ZFS_PROP_CHECKSUM ||
+ prop == ZFS_PROP_DEDUP) {
+ (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property setting is not allowed on "
+ "root pools"));
+ (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
+ } else {
+ (void) zfs_standard_error(hdl, err, errbuf);
+ }
+ break;
+
+ case EINVAL:
+ if (prop == ZPROP_INVAL) {
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ } else {
+ (void) zfs_standard_error(hdl, err, errbuf);
+ }
+ break;
+
+ case EOVERFLOW:
+ /*
+ * This platform can't address a volume this big.
+ */
+#ifdef _ILP32
+ if (prop == ZFS_PROP_VOLSIZE) {
+ (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
+ break;
+ }
+#endif
+ /* FALLTHROUGH */
+ default:
+ (void) zfs_standard_error(hdl, err, errbuf);
+ }
+}
+
+/*
+ * Given a property name and value, set the property for the given dataset.
+ */
+int
+zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
+{
+ int ret = -1;
+ char errbuf[1024];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ nvlist_t *nvl = NULL;
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
+ zhp->zfs_name);
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
+ nvlist_add_string(nvl, propname, propval) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+
+ ret = zfs_prop_set_list(zhp, nvl);
+
+error:
+ nvlist_free(nvl);
+ return (ret);
+}
+
+
+
+/*
+ * Given an nvlist of property names and values, set the properties for the
+ * given dataset.
+ */
+int
+zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)
+{
+ zfs_cmd_t zc = { 0 };
+ int ret = -1;
+ prop_changelist_t **cls = NULL;
+ int cl_idx;
+ char errbuf[1024];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ nvlist_t *nvl;
+ int nvl_len;
+ int added_resv = 0;
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
+ zhp->zfs_name);
+
+ if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props,
+ zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl,
+ errbuf)) == NULL)
+ goto error;
+
+ /*
+ * We have to check for any extra properties which need to be added
+ * before computing the length of the nvlist.
+ */
+ for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
+ elem != NULL;
+ elem = nvlist_next_nvpair(nvl, elem)) {
+ if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE &&
+ (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) {
+ goto error;
+ }
+ }
+
+ if (added_resv != 1 &&
+ (added_resv = zfs_fix_auto_resv(zhp, nvl)) == -1) {
+ goto error;
+ }
+
+ /*
+ * Check how many properties we're setting and allocate an array to
+ * store changelist pointers for postfix().
+ */
+ nvl_len = 0;
+ for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
+ elem != NULL;
+ elem = nvlist_next_nvpair(nvl, elem))
+ nvl_len++;
+ if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL)
+ goto error;
+
+ cl_idx = 0;
+ for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
+ elem != NULL;
+ elem = nvlist_next_nvpair(nvl, elem)) {
+
+ zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
+
+ assert(cl_idx < nvl_len);
+ /*
+ * We don't want to unmount & remount the dataset when changing
+ * its canmount property to 'on' or 'noauto'. We only use
+ * the changelist logic to unmount when setting canmount=off.
+ */
+ if (prop != ZFS_PROP_CANMOUNT ||
+ (fnvpair_value_uint64(elem) == ZFS_CANMOUNT_OFF &&
+ zfs_is_mounted(zhp, NULL))) {
+ cls[cl_idx] = changelist_gather(zhp, prop, 0, 0);
+ if (cls[cl_idx] == NULL)
+ goto error;
+ }
+
+ if (prop == ZFS_PROP_MOUNTPOINT &&
+ changelist_haszonedchild(cls[cl_idx])) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "child dataset with inherited mountpoint is used "
+ "in a non-global zone"));
+ ret = zfs_error(hdl, EZFS_ZONED, errbuf);
+ goto error;
+ }
+
+ /* We don't support those properties on FreeBSD. */
+ switch (prop) {
+ case ZFS_PROP_DEVICES:
+ case ZFS_PROP_ISCSIOPTIONS:
+ case ZFS_PROP_XATTR:
+ case ZFS_PROP_VSCAN:
+ case ZFS_PROP_NBMAND:
+ case ZFS_PROP_MLSLABEL:
+ (void) snprintf(errbuf, sizeof (errbuf),
+ "property '%s' not supported on FreeBSD",
+ nvpair_name(elem));
+ ret = zfs_error(hdl, EZFS_PERM, errbuf);
+ goto error;
+ }
+
+ if (cls[cl_idx] != NULL &&
+ (ret = changelist_prefix(cls[cl_idx])) != 0)
+ goto error;
+
+ cl_idx++;
+ }
+ assert(cl_idx == nvl_len);
+
+ /*
+ * Execute the corresponding ioctl() to set this list of properties.
+ */
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+ if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 ||
+ (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0)
+ goto error;
+
+ ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
+
+ if (ret != 0) {
+ if (zc.zc_nvlist_dst_filled == B_FALSE) {
+ (void) zfs_standard_error(hdl, errno, errbuf);
+ goto error;
+ }
+
+ /* Get the list of unset properties back and report them. */
+ nvlist_t *errorprops = NULL;
+ if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0)
+ goto error;
+ for (nvpair_t *elem = nvlist_next_nvpair(errorprops, NULL);
+ elem != NULL;
+ elem = nvlist_next_nvpair(errorprops, elem)) {
+ zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
+ zfs_setprop_error(hdl, prop, errno, errbuf);
+ }
+ nvlist_free(errorprops);
+
+ if (added_resv && errno == ENOSPC) {
+ /* clean up the volsize property we tried to set */
+ uint64_t old_volsize = zfs_prop_get_int(zhp,
+ ZFS_PROP_VOLSIZE);
+ nvlist_free(nvl);
+ nvl = NULL;
+ zcmd_free_nvlists(&zc);
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+ goto error;
+ if (nvlist_add_uint64(nvl,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE),
+ old_volsize) != 0)
+ goto error;
+ if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
+ goto error;
+ (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
+ }
+ } else {
+ for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
+ if (cls[cl_idx] != NULL) {
+ int clp_err = changelist_postfix(cls[cl_idx]);
+ if (clp_err != 0)
+ ret = clp_err;
+ }
+ }
+
+ /*
+ * Refresh the statistics so the new property value
+ * is reflected.
+ */
+ if (ret == 0)
+ (void) get_stats(zhp);
+ }
+
+error:
+ nvlist_free(nvl);
+ zcmd_free_nvlists(&zc);
+ if (cls != NULL) {
+ for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
+ if (cls[cl_idx] != NULL)
+ changelist_free(cls[cl_idx]);
+ }
+ free(cls);
+ }
+ return (ret);
+}
+
+/*
+ * Given a property, inherit the value from the parent dataset, or if received
+ * is TRUE, revert to the received value, if any.
+ */
+int
+zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received)
+{
+ zfs_cmd_t zc = { 0 };
+ int ret;
+ prop_changelist_t *cl;
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ char errbuf[1024];
+ zfs_prop_t prop;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
+
+ zc.zc_cookie = received;
+ if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
+ /*
+ * For user properties, the amount of work we have to do is very
+ * small, so just do it here.
+ */
+ if (!zfs_prop_user(propname)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid property"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ }
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
+
+ if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0)
+ return (zfs_standard_error(hdl, errno, errbuf));
+
+ return (0);
+ }
+
+ /*
+ * Verify that this property is inheritable.
+ */
+ if (zfs_prop_readonly(prop))
+ return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
+
+ if (!zfs_prop_inheritable(prop) && !received)
+ return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
+
+ /*
+ * Check to see if the value applies to this type
+ */
+ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
+ return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
+
+ /*
+ * Normalize the name, to get rid of shorthand abbreviations.
+ */
+ propname = zfs_prop_to_name(prop);
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
+
+ if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
+ zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset is used in a non-global zone"));
+ return (zfs_error(hdl, EZFS_ZONED, errbuf));
+ }
+
+ /*
+ * Determine datasets which will be affected by this change, if any.
+ */
+ if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
+ return (-1);
+
+ if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "child dataset with inherited mountpoint is used "
+ "in a non-global zone"));
+ ret = zfs_error(hdl, EZFS_ZONED, errbuf);
+ goto error;
+ }
+
+ if ((ret = changelist_prefix(cl)) != 0)
+ goto error;
+
+ if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) {
+ return (zfs_standard_error(hdl, errno, errbuf));
+ } else {
+
+ if ((ret = changelist_postfix(cl)) != 0)
+ goto error;
+
+ /*
+ * Refresh the statistics so the new property is reflected.
+ */
+ (void) get_stats(zhp);
+ }
+
+error:
+ changelist_free(cl);
+ return (ret);
+}
+
+/*
+ * True DSL properties are stored in an nvlist. The following two functions
+ * extract them appropriately.
+ */
+static uint64_t
+getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
+{
+ nvlist_t *nv;
+ uint64_t value;
+
+ *source = NULL;
+ if (nvlist_lookup_nvlist(zhp->zfs_props,
+ zfs_prop_to_name(prop), &nv) == 0) {
+ verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
+ (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
+ } else {
+ verify(!zhp->zfs_props_table ||
+ zhp->zfs_props_table[prop] == B_TRUE);
+ value = zfs_prop_default_numeric(prop);
+ *source = "";
+ }
+
+ return (value);
+}
+
+static const char *
+getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
+{
+ nvlist_t *nv;
+ const char *value;
+
+ *source = NULL;
+ if (nvlist_lookup_nvlist(zhp->zfs_props,
+ zfs_prop_to_name(prop), &nv) == 0) {
+ value = fnvlist_lookup_string(nv, ZPROP_VALUE);
+ (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
+ } else {
+ verify(!zhp->zfs_props_table ||
+ zhp->zfs_props_table[prop] == B_TRUE);
+ value = zfs_prop_default_string(prop);
+ *source = "";
+ }
+
+ return (value);
+}
+
+static boolean_t
+zfs_is_recvd_props_mode(zfs_handle_t *zhp)
+{
+ return (zhp->zfs_props == zhp->zfs_recvd_props);
+}
+
+static void
+zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
+{
+ *cookie = (uint64_t)(uintptr_t)zhp->zfs_props;
+ zhp->zfs_props = zhp->zfs_recvd_props;
+}
+
+static void
+zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
+{
+ zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie;
+ *cookie = 0;
+}
+
+/*
+ * Internal function for getting a numeric property. Both zfs_prop_get() and
+ * zfs_prop_get_int() are built using this interface.
+ *
+ * Certain properties can be overridden using 'mount -o'. In this case, scan
+ * the contents of the /etc/mnttab entry, searching for the appropriate options.
+ * If they differ from the on-disk values, report the current values and mark
+ * the source "temporary".
+ */
+static int
+get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
+ char **source, uint64_t *val)
+{
+ zfs_cmd_t zc = { 0 };
+ nvlist_t *zplprops = NULL;
+ struct mnttab mnt;
+ char *mntopt_on = NULL;
+ char *mntopt_off = NULL;
+ boolean_t received = zfs_is_recvd_props_mode(zhp);
+
+ *source = NULL;
+
+ switch (prop) {
+ case ZFS_PROP_ATIME:
+ mntopt_on = MNTOPT_ATIME;
+ mntopt_off = MNTOPT_NOATIME;
+ break;
+
+ case ZFS_PROP_DEVICES:
+ mntopt_on = MNTOPT_DEVICES;
+ mntopt_off = MNTOPT_NODEVICES;
+ break;
+
+ case ZFS_PROP_EXEC:
+ mntopt_on = MNTOPT_EXEC;
+ mntopt_off = MNTOPT_NOEXEC;
+ break;
+
+ case ZFS_PROP_READONLY:
+ mntopt_on = MNTOPT_RO;
+ mntopt_off = MNTOPT_RW;
+ break;
+
+ case ZFS_PROP_SETUID:
+ mntopt_on = MNTOPT_SETUID;
+ mntopt_off = MNTOPT_NOSETUID;
+ break;
+
+ case ZFS_PROP_XATTR:
+ mntopt_on = MNTOPT_XATTR;
+ mntopt_off = MNTOPT_NOXATTR;
+ break;
+
+ case ZFS_PROP_NBMAND:
+ mntopt_on = MNTOPT_NBMAND;
+ mntopt_off = MNTOPT_NONBMAND;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Because looking up the mount options is potentially expensive
+ * (iterating over all of /etc/mnttab), we defer its calculation until
+ * we're looking up a property which requires its presence.
+ */
+ if (!zhp->zfs_mntcheck &&
+ (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ struct mnttab entry;
+
+ if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) {
+ zhp->zfs_mntopts = zfs_strdup(hdl,
+ entry.mnt_mntopts);
+ if (zhp->zfs_mntopts == NULL)
+ return (-1);
+ }
+
+ zhp->zfs_mntcheck = B_TRUE;
+ }
+
+ if (zhp->zfs_mntopts == NULL)
+ mnt.mnt_mntopts = "";
+ else
+ mnt.mnt_mntopts = zhp->zfs_mntopts;
+
+ switch (prop) {
+ case ZFS_PROP_ATIME:
+ case ZFS_PROP_DEVICES:
+ case ZFS_PROP_EXEC:
+ case ZFS_PROP_READONLY:
+ case ZFS_PROP_SETUID:
+ case ZFS_PROP_XATTR:
+ case ZFS_PROP_NBMAND:
+ *val = getprop_uint64(zhp, prop, source);
+
+ if (received)
+ break;
+
+ if (hasmntopt(&mnt, mntopt_on) && !*val) {
+ *val = B_TRUE;
+ if (src)
+ *src = ZPROP_SRC_TEMPORARY;
+ } else if (hasmntopt(&mnt, mntopt_off) && *val) {
+ *val = B_FALSE;
+ if (src)
+ *src = ZPROP_SRC_TEMPORARY;
+ }
+ break;
+
+ case ZFS_PROP_CANMOUNT:
+ case ZFS_PROP_VOLSIZE:
+ case ZFS_PROP_QUOTA:
+ case ZFS_PROP_REFQUOTA:
+ case ZFS_PROP_RESERVATION:
+ case ZFS_PROP_REFRESERVATION:
+ case ZFS_PROP_FILESYSTEM_LIMIT:
+ case ZFS_PROP_SNAPSHOT_LIMIT:
+ case ZFS_PROP_FILESYSTEM_COUNT:
+ case ZFS_PROP_SNAPSHOT_COUNT:
+ *val = getprop_uint64(zhp, prop, source);
+
+ if (*source == NULL) {
+ /* not default, must be local */
+ *source = zhp->zfs_name;
+ }
+ break;
+
+ case ZFS_PROP_MOUNTED:
+ *val = (zhp->zfs_mntopts != NULL);
+ break;
+
+ case ZFS_PROP_NUMCLONES:
+ *val = zhp->zfs_dmustats.dds_num_clones;
+ break;
+
+ case ZFS_PROP_VERSION:
+ case ZFS_PROP_NORMALIZE:
+ case ZFS_PROP_UTF8ONLY:
+ case ZFS_PROP_CASE:
+ if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) ||
+ zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+ return (-1);
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 ||
+ nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop),
+ val) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ nvlist_free(zplprops);
+ zcmd_free_nvlists(&zc);
+ break;
+
+ case ZFS_PROP_INCONSISTENT:
+ *val = zhp->zfs_dmustats.dds_inconsistent;
+ break;
+
+ default:
+ switch (zfs_prop_get_type(prop)) {
+ case PROP_TYPE_NUMBER:
+ case PROP_TYPE_INDEX:
+ *val = getprop_uint64(zhp, prop, source);
+ /*
+ * If we tried to use a default value for a
+ * readonly property, it means that it was not
+ * present. Note this only applies to "truly"
+ * readonly properties, not set-once properties
+ * like volblocksize.
+ */
+ if (zfs_prop_readonly(prop) &&
+ !zfs_prop_setonce(prop) &&
+ *source != NULL && (*source)[0] == '\0') {
+ *source = NULL;
+ return (-1);
+ }
+ break;
+
+ case PROP_TYPE_STRING:
+ default:
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "cannot get non-numeric property"));
+ return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN, "internal error")));
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Calculate the source type, given the raw source string.
+ */
+static void
+get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source,
+ char *statbuf, size_t statlen)
+{
+ if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY)
+ return;
+
+ if (source == NULL) {
+ *srctype = ZPROP_SRC_NONE;
+ } else if (source[0] == '\0') {
+ *srctype = ZPROP_SRC_DEFAULT;
+ } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) {
+ *srctype = ZPROP_SRC_RECEIVED;
+ } else {
+ if (strcmp(source, zhp->zfs_name) == 0) {
+ *srctype = ZPROP_SRC_LOCAL;
+ } else {
+ (void) strlcpy(statbuf, source, statlen);
+ *srctype = ZPROP_SRC_INHERITED;
+ }
+ }
+
+}
+
+int
+zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
+ size_t proplen, boolean_t literal)
+{
+ zfs_prop_t prop;
+ int err = 0;
+
+ if (zhp->zfs_recvd_props == NULL)
+ if (get_recvd_props_ioctl(zhp) != 0)
+ return (-1);
+
+ prop = zfs_name_to_prop(propname);
+
+ if (prop != ZPROP_INVAL) {
+ uint64_t cookie;
+ if (!nvlist_exists(zhp->zfs_recvd_props, propname))
+ return (-1);
+ zfs_set_recvd_props_mode(zhp, &cookie);
+ err = zfs_prop_get(zhp, prop, propbuf, proplen,
+ NULL, NULL, 0, literal);
+ zfs_unset_recvd_props_mode(zhp, &cookie);
+ } else {
+ nvlist_t *propval;
+ char *recvdval;
+ if (nvlist_lookup_nvlist(zhp->zfs_recvd_props,
+ propname, &propval) != 0)
+ return (-1);
+ verify(nvlist_lookup_string(propval, ZPROP_VALUE,
+ &recvdval) == 0);
+ (void) strlcpy(propbuf, recvdval, proplen);
+ }
+
+ return (err == 0 ? 0 : -1);
+}
+
+static int
+get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
+{
+ nvlist_t *value;
+ nvpair_t *pair;
+
+ value = zfs_get_clones_nvl(zhp);
+ if (value == NULL)
+ return (-1);
+
+ propbuf[0] = '\0';
+ for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(value, pair)) {
+ if (propbuf[0] != '\0')
+ (void) strlcat(propbuf, ",", proplen);
+ (void) strlcat(propbuf, nvpair_name(pair), proplen);
+ }
+
+ return (0);
+}
+
+struct get_clones_arg {
+ uint64_t numclones;
+ nvlist_t *value;
+ const char *origin;
+ char buf[ZFS_MAX_DATASET_NAME_LEN];
+};
+
+int
+get_clones_cb(zfs_handle_t *zhp, void *arg)
+{
+ struct get_clones_arg *gca = arg;
+
+ if (gca->numclones == 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
+ NULL, NULL, 0, B_TRUE) != 0)
+ goto out;
+ if (strcmp(gca->buf, gca->origin) == 0) {
+ fnvlist_add_boolean(gca->value, zfs_get_name(zhp));
+ gca->numclones--;
+ }
+
+out:
+ (void) zfs_iter_children(zhp, get_clones_cb, gca);
+ zfs_close(zhp);
+ return (0);
+}
+
+nvlist_t *
+zfs_get_clones_nvl(zfs_handle_t *zhp)
+{
+ nvlist_t *nv, *value;
+
+ if (nvlist_lookup_nvlist(zhp->zfs_props,
+ zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
+ struct get_clones_arg gca;
+
+ /*
+ * if this is a snapshot, then the kernel wasn't able
+ * to get the clones. Do it by slowly iterating.
+ */
+ if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
+ return (NULL);
+ if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
+ return (NULL);
+ if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
+ nvlist_free(nv);
+ return (NULL);
+ }
+
+ gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
+ gca.value = value;
+ gca.origin = zhp->zfs_name;
+
+ if (gca.numclones != 0) {
+ zfs_handle_t *root;
+ char pool[ZFS_MAX_DATASET_NAME_LEN];
+ char *cp = pool;
+
+ /* get the pool name */
+ (void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
+ (void) strsep(&cp, "/@");
+ root = zfs_open(zhp->zfs_hdl, pool,
+ ZFS_TYPE_FILESYSTEM);
+
+ (void) get_clones_cb(root, &gca);
+ }
+
+ if (gca.numclones != 0 ||
+ nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
+ nvlist_add_nvlist(zhp->zfs_props,
+ zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
+ nvlist_free(nv);
+ nvlist_free(value);
+ return (NULL);
+ }
+ nvlist_free(nv);
+ nvlist_free(value);
+ verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
+ zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
+ }
+
+ verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
+
+ return (value);
+}
+
+/*
+ * Accepts a property and value and checks that the value
+ * matches the one found by the channel program. If they are
+ * not equal, print both of them.
+ */
+void
+zcp_check(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t intval,
+ const char *strval)
+{
+ if (!zhp->zfs_hdl->libzfs_prop_debug)
+ return;
+ int error;
+ char *poolname = zhp->zpool_hdl->zpool_name;
+ const char *program =
+ "args = ...\n"
+ "ds = args['dataset']\n"
+ "prop = args['property']\n"
+ "value, setpoint = zfs.get_prop(ds, prop)\n"
+ "return {value=value, setpoint=setpoint}\n";
+ nvlist_t *outnvl;
+ nvlist_t *retnvl;
+ nvlist_t *argnvl = fnvlist_alloc();
+
+ fnvlist_add_string(argnvl, "dataset", zhp->zfs_name);
+ fnvlist_add_string(argnvl, "property", zfs_prop_to_name(prop));
+
+ error = lzc_channel_program_nosync(poolname, program,
+ 10 * 1000 * 1000, 10 * 1024 * 1024, argnvl, &outnvl);
+
+ if (error == 0) {
+ retnvl = fnvlist_lookup_nvlist(outnvl, "return");
+ if (zfs_prop_get_type(prop) == PROP_TYPE_NUMBER) {
+ int64_t ans;
+ error = nvlist_lookup_int64(retnvl, "value", &ans);
+ if (error != 0) {
+ (void) fprintf(stderr, "zcp check error: %u\n",
+ error);
+ return;
+ }
+ if (ans != intval) {
+ (void) fprintf(stderr,
+ "%s: zfs found %lld, but zcp found %lld\n",
+ zfs_prop_to_name(prop),
+ (longlong_t)intval, (longlong_t)ans);
+ }
+ } else {
+ char *str_ans;
+ error = nvlist_lookup_string(retnvl, "value", &str_ans);
+ if (error != 0) {
+ (void) fprintf(stderr, "zcp check error: %u\n",
+ error);
+ return;
+ }
+ if (strcmp(strval, str_ans) != 0) {
+ (void) fprintf(stderr,
+ "%s: zfs found %s, but zcp found %s\n",
+ zfs_prop_to_name(prop),
+ strval, str_ans);
+ }
+ }
+ } else {
+ (void) fprintf(stderr,
+ "zcp check failed, channel program error: %u\n", error);
+ }
+ nvlist_free(argnvl);
+ nvlist_free(outnvl);
+}
+
+/*
+ * Retrieve a property from the given object. If 'literal' is specified, then
+ * numbers are left as exact values. Otherwise, numbers are converted to a
+ * human-readable form.
+ *
+ * Returns 0 on success, or -1 on error.
+ */
+int
+zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
+ zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
+{
+ char *source = NULL;
+ uint64_t val;
+ const char *str;
+ const char *strval;
+ boolean_t received = zfs_is_recvd_props_mode(zhp);
+
+ /*
+ * Check to see if this property applies to our object
+ */
+ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
+ return (-1);
+
+ if (received && zfs_prop_readonly(prop))
+ return (-1);
+
+ if (src)
+ *src = ZPROP_SRC_NONE;
+
+ switch (prop) {
+ case ZFS_PROP_CREATION:
+ /*
+ * 'creation' is a time_t stored in the statistics. We convert
+ * this into a string unless 'literal' is specified.
+ */
+ {
+ val = getprop_uint64(zhp, prop, &source);
+ time_t time = (time_t)val;
+ struct tm t;
+
+ if (literal ||
+ localtime_r(&time, &t) == NULL ||
+ strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
+ &t) == 0)
+ (void) snprintf(propbuf, proplen, "%llu", val);
+ }
+ zcp_check(zhp, prop, val, NULL);
+ break;
+
+ case ZFS_PROP_MOUNTPOINT:
+ /*
+ * Getting the precise mountpoint can be tricky.
+ *
+ * - for 'none' or 'legacy', return those values.
+ * - for inherited mountpoints, we want to take everything
+ * after our ancestor and append it to the inherited value.
+ *
+ * If the pool has an alternate root, we want to prepend that
+ * root to any values we return.
+ */
+
+ str = getprop_string(zhp, prop, &source);
+
+ if (str[0] == '/') {
+ char buf[MAXPATHLEN];
+ char *root = buf;
+ const char *relpath;
+
+ /*
+ * If we inherit the mountpoint, even from a dataset
+ * with a received value, the source will be the path of
+ * the dataset we inherit from. If source is
+ * ZPROP_SOURCE_VAL_RECVD, the received value is not
+ * inherited.
+ */
+ if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
+ relpath = "";
+ } else {
+ relpath = zhp->zfs_name + strlen(source);
+ if (relpath[0] == '/')
+ relpath++;
+ }
+
+ if ((zpool_get_prop(zhp->zpool_hdl,
+ ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL,
+ B_FALSE)) || (strcmp(root, "-") == 0))
+ root[0] = '\0';
+ /*
+ * Special case an alternate root of '/'. This will
+ * avoid having multiple leading slashes in the
+ * mountpoint path.
+ */
+ if (strcmp(root, "/") == 0)
+ root++;
+
+ /*
+ * If the mountpoint is '/' then skip over this
+ * if we are obtaining either an alternate root or
+ * an inherited mountpoint.
+ */
+ if (str[1] == '\0' && (root[0] != '\0' ||
+ relpath[0] != '\0'))
+ str++;
+
+ if (relpath[0] == '\0')
+ (void) snprintf(propbuf, proplen, "%s%s",
+ root, str);
+ else
+ (void) snprintf(propbuf, proplen, "%s%s%s%s",
+ root, str, relpath[0] == '@' ? "" : "/",
+ relpath);
+ } else {
+ /* 'legacy' or 'none' */
+ (void) strlcpy(propbuf, str, proplen);
+ }
+ zcp_check(zhp, prop, NULL, propbuf);
+ break;
+
+ case ZFS_PROP_ORIGIN:
+ str = getprop_string(zhp, prop, &source);
+ if (str == NULL)
+ return (-1);
+ (void) strlcpy(propbuf, str, proplen);
+ zcp_check(zhp, prop, NULL, str);
+ break;
+
+ case ZFS_PROP_CLONES:
+ if (get_clones_string(zhp, propbuf, proplen) != 0)
+ return (-1);
+ break;
+
+ case ZFS_PROP_QUOTA:
+ case ZFS_PROP_REFQUOTA:
+ case ZFS_PROP_RESERVATION:
+ case ZFS_PROP_REFRESERVATION:
+
+ if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+ return (-1);
+ /*
+ * If quota or reservation is 0, we translate this into 'none'
+ * (unless literal is set), and indicate that it's the default
+ * value. Otherwise, we print the number nicely and indicate
+ * that its set locally.
+ */
+ if (val == 0) {
+ if (literal)
+ (void) strlcpy(propbuf, "0", proplen);
+ else
+ (void) strlcpy(propbuf, "none", proplen);
+ } else {
+ if (literal)
+ (void) snprintf(propbuf, proplen, "%llu",
+ (u_longlong_t)val);
+ else
+ zfs_nicenum(val, propbuf, proplen);
+ }
+ zcp_check(zhp, prop, val, NULL);
+ break;
+
+ case ZFS_PROP_FILESYSTEM_LIMIT:
+ case ZFS_PROP_SNAPSHOT_LIMIT:
+ case ZFS_PROP_FILESYSTEM_COUNT:
+ case ZFS_PROP_SNAPSHOT_COUNT:
+
+ if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+ return (-1);
+
+ /*
+ * If limit is UINT64_MAX, we translate this into 'none' (unless
+ * literal is set), and indicate that it's the default value.
+ * Otherwise, we print the number nicely and indicate that it's
+ * set locally.
+ */
+ if (literal) {
+ (void) snprintf(propbuf, proplen, "%llu",
+ (u_longlong_t)val);
+ } else if (val == UINT64_MAX) {
+ (void) strlcpy(propbuf, "none", proplen);
+ } else {
+ zfs_nicenum(val, propbuf, proplen);
+ }
+
+ zcp_check(zhp, prop, val, NULL);
+ break;
+
+ case ZFS_PROP_REFRATIO:
+ case ZFS_PROP_COMPRESSRATIO:
+ if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+ return (-1);
+ (void) snprintf(propbuf, proplen, "%llu.%02llux",
+ (u_longlong_t)(val / 100),
+ (u_longlong_t)(val % 100));
+ zcp_check(zhp, prop, val, NULL);
+ break;
+
+ case ZFS_PROP_TYPE:
+ switch (zhp->zfs_type) {
+ case ZFS_TYPE_FILESYSTEM:
+ str = "filesystem";
+ break;
+ case ZFS_TYPE_VOLUME:
+ str = "volume";
+ break;
+ case ZFS_TYPE_SNAPSHOT:
+ str = "snapshot";
+ break;
+ case ZFS_TYPE_BOOKMARK:
+ str = "bookmark";
+ break;
+ default:
+ abort();
+ }
+ (void) snprintf(propbuf, proplen, "%s", str);
+ zcp_check(zhp, prop, NULL, propbuf);
+ break;
+
+ case ZFS_PROP_MOUNTED:
+ /*
+ * The 'mounted' property is a pseudo-property that described
+ * whether the filesystem is currently mounted. Even though
+ * it's a boolean value, the typical values of "on" and "off"
+ * don't make sense, so we translate to "yes" and "no".
+ */
+ if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
+ src, &source, &val) != 0)
+ return (-1);
+ if (val)
+ (void) strlcpy(propbuf, "yes", proplen);
+ else
+ (void) strlcpy(propbuf, "no", proplen);
+ break;
+
+ case ZFS_PROP_NAME:
+ /*
+ * The 'name' property is a pseudo-property derived from the
+ * dataset name. It is presented as a real property to simplify
+ * consumers.
+ */
+ (void) strlcpy(propbuf, zhp->zfs_name, proplen);
+ zcp_check(zhp, prop, NULL, propbuf);
+ break;
+
+ case ZFS_PROP_MLSLABEL:
+ {
+#ifdef illumos
+ m_label_t *new_sl = NULL;
+ char *ascii = NULL; /* human readable label */
+
+ (void) strlcpy(propbuf,
+ getprop_string(zhp, prop, &source), proplen);
+
+ if (literal || (strcasecmp(propbuf,
+ ZFS_MLSLABEL_DEFAULT) == 0))
+ break;
+
+ /*
+ * Try to translate the internal hex string to
+ * human-readable output. If there are any
+ * problems just use the hex string.
+ */
+
+ if (str_to_label(propbuf, &new_sl, MAC_LABEL,
+ L_NO_CORRECTION, NULL) == -1) {
+ m_label_free(new_sl);
+ break;
+ }
+
+ if (label_to_str(new_sl, &ascii, M_LABEL,
+ DEF_NAMES) != 0) {
+ if (ascii)
+ free(ascii);
+ m_label_free(new_sl);
+ break;
+ }
+ m_label_free(new_sl);
+
+ (void) strlcpy(propbuf, ascii, proplen);
+ free(ascii);
+#else /* !illumos */
+ propbuf[0] = '\0';
+#endif /* illumos */
+ }
+ break;
+
+ case ZFS_PROP_GUID:
+ case ZFS_PROP_CREATETXG:
+ /*
+ * GUIDs are stored as numbers, but they are identifiers.
+ * We don't want them to be pretty printed, because pretty
+ * printing mangles the ID into a truncated and useless value.
+ */
+ if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+ return (-1);
+ (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val);
+ zcp_check(zhp, prop, val, NULL);
+ break;
+
+ default:
+ switch (zfs_prop_get_type(prop)) {
+ case PROP_TYPE_NUMBER:
+ if (get_numeric_property(zhp, prop, src,
+ &source, &val) != 0) {
+ return (-1);
+ }
+
+ if (literal) {
+ (void) snprintf(propbuf, proplen, "%llu",
+ (u_longlong_t)val);
+ } else {
+ zfs_nicenum(val, propbuf, proplen);
+ }
+ zcp_check(zhp, prop, val, NULL);
+ break;
+
+ case PROP_TYPE_STRING:
+ str = getprop_string(zhp, prop, &source);
+ if (str == NULL)
+ return (-1);
+
+ (void) strlcpy(propbuf, str, proplen);
+ zcp_check(zhp, prop, NULL, str);
+ break;
+
+ case PROP_TYPE_INDEX:
+ if (get_numeric_property(zhp, prop, src,
+ &source, &val) != 0)
+ return (-1);
+ if (zfs_prop_index_to_string(prop, val, &strval) != 0)
+ return (-1);
+
+ (void) strlcpy(propbuf, strval, proplen);
+ zcp_check(zhp, prop, NULL, strval);
+ break;
+
+ default:
+ abort();
+ }
+ }
+
+ get_source(zhp, src, source, statbuf, statlen);
+
+ return (0);
+}
+
+/*
+ * Utility function to get the given numeric property. Does no validation that
+ * the given property is the appropriate type; should only be used with
+ * hard-coded property types.
+ */
+uint64_t
+zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
+{
+ char *source;
+ uint64_t val;
+
+ (void) get_numeric_property(zhp, prop, NULL, &source, &val);
+
+ return (val);
+}
+
+int
+zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
+{
+ char buf[64];
+
+ (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val);
+ return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
+}
+
+/*
+ * Similar to zfs_prop_get(), but returns the value as an integer.
+ */
+int
+zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
+ zprop_source_t *src, char *statbuf, size_t statlen)
+{
+ char *source;
+
+ /*
+ * Check to see if this property applies to our object
+ */
+ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) {
+ return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
+ dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
+ zfs_prop_to_name(prop)));
+ }
+
+ if (src)
+ *src = ZPROP_SRC_NONE;
+
+ if (get_numeric_property(zhp, prop, src, &source, value) != 0)
+ return (-1);
+
+ get_source(zhp, src, source, statbuf, statlen);
+
+ return (0);
+}
+
+static int
+idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
+ char **domainp, idmap_rid_t *ridp)
+{
+#ifdef illumos
+ idmap_get_handle_t *get_hdl = NULL;
+ idmap_stat status;
+ int err = EINVAL;
+
+ if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS)
+ goto out;
+
+ if (isuser) {
+ err = idmap_get_sidbyuid(get_hdl, id,
+ IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
+ } else {
+ err = idmap_get_sidbygid(get_hdl, id,
+ IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
+ }
+ if (err == IDMAP_SUCCESS &&
+ idmap_get_mappings(get_hdl) == IDMAP_SUCCESS &&
+ status == IDMAP_SUCCESS)
+ err = 0;
+ else
+ err = EINVAL;
+out:
+ if (get_hdl)
+ idmap_get_destroy(get_hdl);
+ return (err);
+#else /* !illumos */
+ assert(!"invalid code path");
+ return (EINVAL); // silence compiler warning
+#endif /* illumos */
+}
+
+/*
+ * convert the propname into parameters needed by kernel
+ * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829
+ * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789
+ */
+static int
+userquota_propname_decode(const char *propname, boolean_t zoned,
+ zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
+{
+ zfs_userquota_prop_t type;
+ char *cp, *end;
+ char *numericsid = NULL;
+ boolean_t isuser;
+
+ domain[0] = '\0';
+ *ridp = 0;
+ /* Figure out the property type ({user|group}{quota|space}) */
+ for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
+ if (strncmp(propname, zfs_userquota_prop_prefixes[type],
+ strlen(zfs_userquota_prop_prefixes[type])) == 0)
+ break;
+ }
+ if (type == ZFS_NUM_USERQUOTA_PROPS)
+ return (EINVAL);
+ *typep = type;
+
+ isuser = (type == ZFS_PROP_USERQUOTA ||
+ type == ZFS_PROP_USERUSED);
+
+ cp = strchr(propname, '@') + 1;
+
+ if (strchr(cp, '@')) {
+#ifdef illumos
+ /*
+ * It's a SID name (eg "user@domain") that needs to be
+ * turned into S-1-domainID-RID.
+ */
+ int flag = 0;
+ idmap_stat stat, map_stat;
+ uid_t pid;
+ idmap_rid_t rid;
+ idmap_get_handle_t *gh = NULL;
+
+ stat = idmap_get_create(&gh);
+ if (stat != IDMAP_SUCCESS) {
+ idmap_get_destroy(gh);
+ return (ENOMEM);
+ }
+ if (zoned && getzoneid() == GLOBAL_ZONEID)
+ return (ENOENT);
+ if (isuser) {
+ stat = idmap_getuidbywinname(cp, NULL, flag, &pid);
+ if (stat < 0)
+ return (ENOENT);
+ stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid,
+ &rid, &map_stat);
+ } else {
+ stat = idmap_getgidbywinname(cp, NULL, flag, &pid);
+ if (stat < 0)
+ return (ENOENT);
+ stat = idmap_get_sidbygid(gh, pid, flag, &numericsid,
+ &rid, &map_stat);
+ }
+ if (stat < 0) {
+ idmap_get_destroy(gh);
+ return (ENOENT);
+ }
+ stat = idmap_get_mappings(gh);
+ idmap_get_destroy(gh);
+
+ if (stat < 0) {
+ return (ENOENT);
+ }
+ if (numericsid == NULL)
+ return (ENOENT);
+ cp = numericsid;
+ *ridp = rid;
+ /* will be further decoded below */
+#else /* !illumos */
+ return (ENOENT);
+#endif /* illumos */
+ }
+
+ if (strncmp(cp, "S-1-", 4) == 0) {
+ /* It's a numeric SID (eg "S-1-234-567-89") */
+ (void) strlcpy(domain, cp, domainlen);
+ errno = 0;
+ if (*ridp == 0) {
+ cp = strrchr(domain, '-');
+ *cp = '\0';
+ cp++;
+ *ridp = strtoull(cp, &end, 10);
+ } else {
+ end = "";
+ }
+ if (numericsid) {
+ free(numericsid);
+ numericsid = NULL;
+ }
+ if (errno != 0 || *end != '\0')
+ return (EINVAL);
+ } else if (!isdigit(*cp)) {
+ /*
+ * It's a user/group name (eg "user") that needs to be
+ * turned into a uid/gid
+ */
+ if (zoned && getzoneid() == GLOBAL_ZONEID)
+ return (ENOENT);
+ if (isuser) {
+ struct passwd *pw;
+ pw = getpwnam(cp);
+ if (pw == NULL)
+ return (ENOENT);
+ *ridp = pw->pw_uid;
+ } else {
+ struct group *gr;
+ gr = getgrnam(cp);
+ if (gr == NULL)
+ return (ENOENT);
+ *ridp = gr->gr_gid;
+ }
+ } else {
+ /* It's a user/group ID (eg "12345"). */
+ uid_t id = strtoul(cp, &end, 10);
+ idmap_rid_t rid;
+ char *mapdomain;
+
+ if (*end != '\0')
+ return (EINVAL);
+ if (id > MAXUID) {
+ /* It's an ephemeral ID. */
+ if (idmap_id_to_numeric_domain_rid(id, isuser,
+ &mapdomain, &rid) != 0)
+ return (ENOENT);
+ (void) strlcpy(domain, mapdomain, domainlen);
+ *ridp = rid;
+ } else {
+ *ridp = id;
+ }
+ }
+
+ ASSERT3P(numericsid, ==, NULL);
+ return (0);
+}
+
+static int
+zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
+ uint64_t *propvalue, zfs_userquota_prop_t *typep)
+{
+ int err;
+ zfs_cmd_t zc = { 0 };
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+ err = userquota_propname_decode(propname,
+ zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
+ typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid);
+ zc.zc_objset_type = *typep;
+ if (err)
+ return (err);
+
+ err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc);
+ if (err)
+ return (err);
+
+ *propvalue = zc.zc_cookie;
+ return (0);
+}
+
+int
+zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
+ uint64_t *propvalue)
+{
+ zfs_userquota_prop_t type;
+
+ return (zfs_prop_get_userquota_common(zhp, propname, propvalue,
+ &type));
+}
+
+int
+zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
+ char *propbuf, int proplen, boolean_t literal)
+{
+ int err;
+ uint64_t propvalue;
+ zfs_userquota_prop_t type;
+
+ err = zfs_prop_get_userquota_common(zhp, propname, &propvalue,
+ &type);
+
+ if (err)
+ return (err);
+
+ if (literal) {
+ (void) snprintf(propbuf, proplen, "%llu", propvalue);
+ } else if (propvalue == 0 &&
+ (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) {
+ (void) strlcpy(propbuf, "none", proplen);
+ } else {
+ zfs_nicenum(propvalue, propbuf, proplen);
+ }
+ return (0);
+}
+
+int
+zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
+ uint64_t *propvalue)
+{
+ int err;
+ zfs_cmd_t zc = { 0 };
+ const char *snapname;
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+ snapname = strchr(propname, '@') + 1;
+ if (strchr(snapname, '@')) {
+ (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
+ } else {
+ /* snapname is the short name, append it to zhp's fsname */
+ char *cp;
+
+ (void) strlcpy(zc.zc_value, zhp->zfs_name,
+ sizeof (zc.zc_value));
+ cp = strchr(zc.zc_value, '@');
+ if (cp != NULL)
+ *cp = '\0';
+ (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
+ (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
+ }
+
+ err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
+ if (err)
+ return (err);
+
+ *propvalue = zc.zc_cookie;
+ return (0);
+}
+
+int
+zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
+ char *propbuf, int proplen, boolean_t literal)
+{
+ int err;
+ uint64_t propvalue;
+
+ err = zfs_prop_get_written_int(zhp, propname, &propvalue);
+
+ if (err)
+ return (err);
+
+ if (literal) {
+ (void) snprintf(propbuf, proplen, "%llu", propvalue);
+ } else {
+ zfs_nicenum(propvalue, propbuf, proplen);
+ }
+ return (0);
+}
+
+/*
+ * Returns the name of the given zfs handle.
+ */
+const char *
+zfs_get_name(const zfs_handle_t *zhp)
+{
+ return (zhp->zfs_name);
+}
+
+/*
+ * Returns the name of the parent pool for the given zfs handle.
+ */
+const char *
+zfs_get_pool_name(const zfs_handle_t *zhp)
+{
+ return (zhp->zpool_hdl->zpool_name);
+}
+
+/*
+ * Returns the type of the given zfs handle.
+ */
+zfs_type_t
+zfs_get_type(const zfs_handle_t *zhp)
+{
+ return (zhp->zfs_type);
+}
+
+/*
+ * Is one dataset name a child dataset of another?
+ *
+ * Needs to handle these cases:
+ * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo"
+ * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar"
+ * Descendant? No. No. No. Yes.
+ */
+static boolean_t
+is_descendant(const char *ds1, const char *ds2)
+{
+ size_t d1len = strlen(ds1);
+
+ /* ds2 can't be a descendant if it's smaller */
+ if (strlen(ds2) < d1len)
+ return (B_FALSE);
+
+ /* otherwise, compare strings and verify that there's a '/' char */
+ return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
+}
+
+/*
+ * Given a complete name, return just the portion that refers to the parent.
+ * Will return -1 if there is no parent (path is just the name of the
+ * pool).
+ */
+static int
+parent_name(const char *path, char *buf, size_t buflen)
+{
+ char *slashp;
+
+ (void) strlcpy(buf, path, buflen);
+
+ if ((slashp = strrchr(buf, '/')) == NULL)
+ return (-1);
+ *slashp = '\0';
+
+ return (0);
+}
+
+/*
+ * If accept_ancestor is false, then check to make sure that the given path has
+ * a parent, and that it exists. If accept_ancestor is true, then find the
+ * closest existing ancestor for the given path. In prefixlen return the
+ * length of already existing prefix of the given path. We also fetch the
+ * 'zoned' property, which is used to validate property settings when creating
+ * new datasets.
+ */
+static int
+check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
+ boolean_t accept_ancestor, int *prefixlen)
+{
+ zfs_cmd_t zc = { 0 };
+ char parent[ZFS_MAX_DATASET_NAME_LEN];
+ char *slash;
+ zfs_handle_t *zhp;
+ char errbuf[1024];
+ uint64_t is_zoned;
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot create '%s'"), path);
+
+ /* get parent, and check to see if this is just a pool */
+ if (parent_name(path, parent, sizeof (parent)) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "missing dataset name"));
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ }
+
+ /* check to see if the pool exists */
+ if ((slash = strchr(parent, '/')) == NULL)
+ slash = parent + strlen(parent);
+ (void) strncpy(zc.zc_name, parent, slash - parent);
+ zc.zc_name[slash - parent] = '\0';
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
+ errno == ENOENT) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "no such pool '%s'"), zc.zc_name);
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+ }
+
+ /* check to see if the parent dataset exists */
+ while ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
+ if (errno == ENOENT && accept_ancestor) {
+ /*
+ * Go deeper to find an ancestor, give up on top level.
+ */
+ if (parent_name(parent, parent, sizeof (parent)) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "no such pool '%s'"), zc.zc_name);
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+ }
+ } else if (errno == ENOENT) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "parent does not exist"));
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+ } else
+ return (zfs_standard_error(hdl, errno, errbuf));
+ }
+
+ is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
+ if (zoned != NULL)
+ *zoned = is_zoned;
+
+ /* we are in a non-global zone, but parent is in the global zone */
+ if (getzoneid() != GLOBAL_ZONEID && !is_zoned) {
+ (void) zfs_standard_error(hdl, EPERM, errbuf);
+ zfs_close(zhp);
+ return (-1);
+ }
+
+ /* make sure parent is a filesystem */
+ if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "parent is not a filesystem"));
+ (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+ zfs_close(zhp);
+ return (-1);
+ }
+
+ zfs_close(zhp);
+ if (prefixlen != NULL)
+ *prefixlen = strlen(parent);
+ return (0);
+}
+
+/*
+ * Finds whether the dataset of the given type(s) exists.
+ */
+boolean_t
+zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types)
+{
+ zfs_handle_t *zhp;
+
+ if (!zfs_validate_name(hdl, path, types, B_FALSE))
+ return (B_FALSE);
+
+ /*
+ * Try to get stats for the dataset, which will tell us if it exists.
+ */
+ if ((zhp = make_dataset_handle(hdl, path)) != NULL) {
+ int ds_type = zhp->zfs_type;
+
+ zfs_close(zhp);
+ if (types & ds_type)
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Given a path to 'target', create all the ancestors between
+ * the prefixlen portion of the path, and the target itself.
+ * Fail if the initial prefixlen-ancestor does not already exist.
+ */
+int
+create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
+{
+ zfs_handle_t *h;
+ char *cp;
+ const char *opname;
+
+ /* make sure prefix exists */
+ cp = target + prefixlen;
+ if (*cp != '/') {
+ assert(strchr(cp, '/') == NULL);
+ h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
+ } else {
+ *cp = '\0';
+ h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
+ *cp = '/';
+ }
+ if (h == NULL)
+ return (-1);
+ zfs_close(h);
+
+ /*
+ * Attempt to create, mount, and share any ancestor filesystems,
+ * up to the prefixlen-long one.
+ */
+ for (cp = target + prefixlen + 1;
+ (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) {
+
+ *cp = '\0';
+
+ h = make_dataset_handle(hdl, target);
+ if (h) {
+ /* it already exists, nothing to do here */
+ zfs_close(h);
+ continue;
+ }
+
+ if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
+ NULL) != 0) {
+ opname = dgettext(TEXT_DOMAIN, "create");
+ goto ancestorerr;
+ }
+
+ h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
+ if (h == NULL) {
+ opname = dgettext(TEXT_DOMAIN, "open");
+ goto ancestorerr;
+ }
+
+ if (zfs_mount(h, NULL, 0) != 0) {
+ opname = dgettext(TEXT_DOMAIN, "mount");
+ goto ancestorerr;
+ }
+
+ if (zfs_share(h) != 0) {
+ opname = dgettext(TEXT_DOMAIN, "share");
+ goto ancestorerr;
+ }
+
+ zfs_close(h);
+ }
+
+ return (0);
+
+ancestorerr:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "failed to %s ancestor '%s'"), opname, target);
+ return (-1);
+}
+
+/*
+ * Creates non-existing ancestors of the given path.
+ */
+int
+zfs_create_ancestors(libzfs_handle_t *hdl, const char *path)
+{
+ int prefix;
+ char *path_copy;
+ char errbuf[1024];
+ int rc = 0;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot create '%s'"), path);
+
+ /*
+ * Check that we are not passing the nesting limit
+ * before we start creating any ancestors.
+ */
+ if (dataset_nestcheck(path) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "maximum name nesting depth exceeded"));
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ }
+
+ if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0)
+ return (-1);
+
+ if ((path_copy = strdup(path)) != NULL) {
+ rc = create_parents(hdl, path_copy, prefix);
+ free(path_copy);
+ }
+ if (path_copy == NULL || rc != 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Create a new filesystem or volume.
+ */
+int
+zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
+ nvlist_t *props)
+{
+ int ret;
+ uint64_t size = 0;
+ uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
+ char errbuf[1024];
+ uint64_t zoned;
+ enum lzc_dataset_type ost;
+ zpool_handle_t *zpool_handle;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot create '%s'"), path);
+
+ /* validate the path, taking care to note the extended error message */
+ if (!zfs_validate_name(hdl, path, type, B_TRUE))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+ if (dataset_nestcheck(path) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "maximum name nesting depth exceeded"));
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ }
+
+ /* validate parents exist */
+ if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0)
+ return (-1);
+
+ /*
+ * The failure modes when creating a dataset of a different type over
+ * one that already exists is a little strange. In particular, if you
+ * try to create a dataset on top of an existing dataset, the ioctl()
+ * will return ENOENT, not EEXIST. To prevent this from happening, we
+ * first try to see if the dataset exists.
+ */
+ if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset already exists"));
+ return (zfs_error(hdl, EZFS_EXISTS, errbuf));
+ }
+
+ if (type == ZFS_TYPE_VOLUME)
+ ost = LZC_DATSET_TYPE_ZVOL;
+ else
+ ost = LZC_DATSET_TYPE_ZFS;
+
+ /* open zpool handle for prop validation */
+ char pool_path[ZFS_MAX_DATASET_NAME_LEN];
+ (void) strlcpy(pool_path, path, sizeof (pool_path));
+
+ /* truncate pool_path at first slash */
+ char *p = strchr(pool_path, '/');
+ if (p != NULL)
+ *p = '\0';
+
+ if ((zpool_handle = zpool_open(hdl, pool_path)) == NULL)
+ return (-1);
+
+ if (props && (props = zfs_valid_proplist(hdl, type, props,
+ zoned, NULL, zpool_handle, errbuf)) == 0) {
+ zpool_close(zpool_handle);
+ return (-1);
+ }
+ zpool_close(zpool_handle);
+
+ if (type == ZFS_TYPE_VOLUME) {
+ /*
+ * If we are creating a volume, the size and block size must
+ * satisfy a few restraints. First, the blocksize must be a
+ * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the
+ * volsize must be a multiple of the block size, and cannot be
+ * zero.
+ */
+ if (props == NULL || nvlist_lookup_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
+ nvlist_free(props);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "missing volume size"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ }
+
+ if ((ret = nvlist_lookup_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ &blocksize)) != 0) {
+ if (ret == ENOENT) {
+ blocksize = zfs_prop_default_numeric(
+ ZFS_PROP_VOLBLOCKSIZE);
+ } else {
+ nvlist_free(props);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "missing volume block size"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ }
+ }
+
+ if (size == 0) {
+ nvlist_free(props);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "volume size cannot be zero"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ }
+
+ if (size % blocksize != 0) {
+ nvlist_free(props);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "volume size must be a multiple of volume block "
+ "size"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ }
+ }
+
+ /* create the dataset */
+ ret = lzc_create(path, ost, props);
+ nvlist_free(props);
+
+ /* check for failure */
+ if (ret != 0) {
+ char parent[ZFS_MAX_DATASET_NAME_LEN];
+ (void) parent_name(path, parent, sizeof (parent));
+
+ switch (errno) {
+ case ENOENT:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "no such parent '%s'"), parent);
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+ case EINVAL:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "parent '%s' is not a filesystem"), parent);
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded to set this "
+ "property or value"));
+ return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
+ case ERANGE:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid property value(s) specified"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+#ifdef _ILP32
+ case EOVERFLOW:
+ /*
+ * This platform can't address a volume this big.
+ */
+ if (type == ZFS_TYPE_VOLUME)
+ return (zfs_error(hdl, EZFS_VOLTOOBIG,
+ errbuf));
+#endif
+ /* FALLTHROUGH */
+ default:
+ return (zfs_standard_error(hdl, errno, errbuf));
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Destroys the given dataset. The caller must make sure that the filesystem
+ * isn't mounted, and that there are no active dependents. If the file system
+ * does not exist this function does nothing.
+ */
+int
+zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
+{
+ int error;
+
+ if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT && defer)
+ return (EINVAL);
+
+ if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
+ nvlist_t *nv = fnvlist_alloc();
+ fnvlist_add_boolean(nv, zhp->zfs_name);
+ error = lzc_destroy_bookmarks(nv, NULL);
+ fnvlist_free(nv);
+ if (error != 0) {
+ return (zfs_standard_error_fmt(zhp->zfs_hdl, error,
+ dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
+ zhp->zfs_name));
+ }
+ return (0);
+ }
+
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+ nvlist_t *nv = fnvlist_alloc();
+ fnvlist_add_boolean(nv, zhp->zfs_name);
+ error = lzc_destroy_snaps(nv, defer, NULL);
+ fnvlist_free(nv);
+ } else {
+ error = lzc_destroy(zhp->zfs_name);
+ }
+
+ if (error != 0 && error != ENOENT) {
+ return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
+ zhp->zfs_name));
+ }
+
+ remove_mountpoint(zhp);
+
+ return (0);
+}
+
+struct destroydata {
+ nvlist_t *nvl;
+ const char *snapname;
+};
+
+static int
+zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
+{
+ struct destroydata *dd = arg;
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ int rv = 0;
+
+ (void) snprintf(name, sizeof (name),
+ "%s@%s", zhp->zfs_name, dd->snapname);
+
+ if (lzc_exists(name))
+ verify(nvlist_add_boolean(dd->nvl, name) == 0);
+
+ rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
+ zfs_close(zhp);
+ return (rv);
+}
+
+/*
+ * Destroys all snapshots with the given name in zhp & descendants.
+ */
+int
+zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
+{
+ int ret;
+ struct destroydata dd = { 0 };
+
+ dd.snapname = snapname;
+ verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
+ (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
+
+ if (nvlist_empty(dd.nvl)) {
+ ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
+ dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
+ zhp->zfs_name, snapname);
+ } else {
+ ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer);
+ }
+ nvlist_free(dd.nvl);
+ return (ret);
+}
+
+/*
+ * Destroys all the snapshots named in the nvlist.
+ */
+int
+zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
+{
+ int ret;
+ nvlist_t *errlist = NULL;
+
+ ret = lzc_destroy_snaps(snaps, defer, &errlist);
+
+ if (ret == 0) {
+ nvlist_free(errlist);
+ return (0);
+ }
+
+ if (nvlist_empty(errlist)) {
+ char errbuf[1024];
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot destroy snapshots"));
+
+ ret = zfs_standard_error(hdl, ret, errbuf);
+ }
+ for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
+ char errbuf[1024];
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
+ nvpair_name(pair));
+
+ switch (fnvpair_value_int32(pair)) {
+ case EEXIST:
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "snapshot is cloned"));
+ ret = zfs_error(hdl, EZFS_EXISTS, errbuf);
+ break;
+ default:
+ ret = zfs_standard_error(hdl, errno, errbuf);
+ break;
+ }
+ }
+
+ nvlist_free(errlist);
+ return (ret);
+}
+
+/*
+ * Clones the given dataset. The target must be of the same type as the source.
+ */
+int
+zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
+{
+ char parent[ZFS_MAX_DATASET_NAME_LEN];
+ int ret;
+ char errbuf[1024];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ uint64_t zoned;
+
+ assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot create '%s'"), target);
+
+ /* validate the target/clone name */
+ if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+ /* validate parents exist */
+ if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0)
+ return (-1);
+
+ (void) parent_name(target, parent, sizeof (parent));
+
+ /* do the clone */
+
+ if (props) {
+ zfs_type_t type;
+
+ if (ZFS_IS_VOLUME(zhp)) {
+ type = ZFS_TYPE_VOLUME;
+ } else {
+ type = ZFS_TYPE_FILESYSTEM;
+ }
+ if ((props = zfs_valid_proplist(hdl, type, props, zoned,
+ zhp, zhp->zpool_hdl, errbuf)) == NULL)
+ return (-1);
+ if (zfs_fix_auto_resv(zhp, props) == -1) {
+ nvlist_free(props);
+ return (-1);
+ }
+ }
+
+ ret = lzc_clone(target, zhp->zfs_name, props);
+ nvlist_free(props);
+
+ if (ret != 0) {
+ switch (errno) {
+
+ case ENOENT:
+ /*
+ * The parent doesn't exist. We should have caught this
+ * above, but there may a race condition that has since
+ * destroyed the parent.
+ *
+ * At this point, we don't know whether it's the source
+ * that doesn't exist anymore, or whether the target
+ * dataset doesn't exist.
+ */
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "no such parent '%s'"), parent);
+ return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
+
+ case EXDEV:
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "source and target pools differ"));
+ return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
+ errbuf));
+
+ default:
+ return (zfs_standard_error(zhp->zfs_hdl, errno,
+ errbuf));
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * Promotes the given clone fs to be the clone parent.
+ */
+int
+zfs_promote(zfs_handle_t *zhp)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ char snapname[ZFS_MAX_DATASET_NAME_LEN];
+ int ret;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot promote '%s'"), zhp->zfs_name);
+
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "snapshots can not be promoted"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ }
+
+ if (zhp->zfs_dmustats.dds_origin[0] == '\0') {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not a cloned filesystem"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ }
+
+ if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+ ret = lzc_promote(zhp->zfs_name, snapname, sizeof (snapname));
+
+ if (ret != 0) {
+ switch (ret) {
+ case EEXIST:
+ /* There is a conflicting snapshot name. */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "conflicting snapshot '%s' from parent '%s'"),
+ snapname, zhp->zfs_dmustats.dds_origin);
+ return (zfs_error(hdl, EZFS_EXISTS, errbuf));
+
+ default:
+ return (zfs_standard_error(hdl, ret, errbuf));
+ }
+ }
+ return (ret);
+}
+
+typedef struct snapdata {
+ nvlist_t *sd_nvl;
+ const char *sd_snapname;
+} snapdata_t;
+
+static int
+zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
+{
+ snapdata_t *sd = arg;
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ int rv = 0;
+
+ if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) {
+ (void) snprintf(name, sizeof (name),
+ "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
+
+ fnvlist_add_boolean(sd->sd_nvl, name);
+
+ rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
+ }
+ zfs_close(zhp);
+
+ return (rv);
+}
+
+int
+zfs_remap_indirects(libzfs_handle_t *hdl, const char *fs)
+{
+ int err;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot remap dataset '%s'"), fs);
+
+ err = lzc_remap(fs);
+
+ if (err != 0) {
+ switch (err) {
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded"));
+ (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ break;
+ case EINVAL:
+ (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+ break;
+ default:
+ (void) zfs_standard_error(hdl, err, errbuf);
+ break;
+ }
+ }
+
+ return (err);
+}
+
+/*
+ * Creates snapshots. The keys in the snaps nvlist are the snapshots to be
+ * created.
+ */
+int
+zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
+{
+ int ret;
+ char errbuf[1024];
+ nvpair_t *elem;
+ nvlist_t *errors;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot create snapshots "));
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
+ const char *snapname = nvpair_name(elem);
+
+ /* validate the target name */
+ if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
+ B_TRUE)) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot create snapshot '%s'"), snapname);
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ }
+ }
+
+ /*
+ * get pool handle for prop validation. assumes all snaps are in the
+ * same pool, as does lzc_snapshot (below).
+ */
+ char pool[ZFS_MAX_DATASET_NAME_LEN];
+ elem = nvlist_next_nvpair(snaps, NULL);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/@")] = '\0';
+ zpool_handle_t *zpool_hdl = zpool_open(hdl, pool);
+
+ if (props != NULL &&
+ (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
+ props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) {
+ zpool_close(zpool_hdl);
+ return (-1);
+ }
+ zpool_close(zpool_hdl);
+
+ ret = lzc_snapshot(snaps, props, &errors);
+
+ if (ret != 0) {
+ boolean_t printed = B_FALSE;
+ for (elem = nvlist_next_nvpair(errors, NULL);
+ elem != NULL;
+ elem = nvlist_next_nvpair(errors, elem)) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot create snapshot '%s'"), nvpair_name(elem));
+ (void) zfs_standard_error(hdl,
+ fnvpair_value_int32(elem), errbuf);
+ printed = B_TRUE;
+ }
+ if (!printed) {
+ switch (ret) {
+ case EXDEV:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "multiple snapshots of same "
+ "fs not allowed"));
+ (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
+
+ break;
+ default:
+ (void) zfs_standard_error(hdl, ret, errbuf);
+ }
+ }
+ }
+
+ nvlist_free(props);
+ nvlist_free(errors);
+ return (ret);
+}
+
+int
+zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
+ nvlist_t *props)
+{
+ int ret;
+ snapdata_t sd = { 0 };
+ char fsname[ZFS_MAX_DATASET_NAME_LEN];
+ char *cp;
+ zfs_handle_t *zhp;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot snapshot %s"), path);
+
+ if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+ (void) strlcpy(fsname, path, sizeof (fsname));
+ cp = strchr(fsname, '@');
+ *cp = '\0';
+ sd.sd_snapname = cp + 1;
+
+ if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
+ ZFS_TYPE_VOLUME)) == NULL) {
+ return (-1);
+ }
+
+ verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
+ if (recursive) {
+ (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
+ } else {
+ fnvlist_add_boolean(sd.sd_nvl, path);
+ }
+
+ ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
+ nvlist_free(sd.sd_nvl);
+ zfs_close(zhp);
+ return (ret);
+}
+
+/*
+ * Destroy any more recent snapshots. We invoke this callback on any dependents
+ * of the snapshot first. If the 'cb_dependent' member is non-zero, then this
+ * is a dependent and we should just destroy it without checking the transaction
+ * group.
+ */
+typedef struct rollback_data {
+ const char *cb_target; /* the snapshot */
+ uint64_t cb_create; /* creation time reference */
+ boolean_t cb_error;
+ boolean_t cb_force;
+} rollback_data_t;
+
+static int
+rollback_destroy_dependent(zfs_handle_t *zhp, void *data)
+{
+ rollback_data_t *cbp = data;
+ prop_changelist_t *clp;
+
+ /* We must destroy this clone; first unmount it */
+ clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+ cbp->cb_force ? MS_FORCE: 0);
+ if (clp == NULL || changelist_prefix(clp) != 0) {
+ cbp->cb_error = B_TRUE;
+ zfs_close(zhp);
+ return (0);
+ }
+ if (zfs_destroy(zhp, B_FALSE) != 0)
+ cbp->cb_error = B_TRUE;
+ else
+ changelist_remove(clp, zhp->zfs_name);
+ (void) changelist_postfix(clp);
+ changelist_free(clp);
+
+ zfs_close(zhp);
+ return (0);
+}
+
+static int
+rollback_destroy(zfs_handle_t *zhp, void *data)
+{
+ rollback_data_t *cbp = data;
+
+ if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
+ cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
+ rollback_destroy_dependent, cbp);
+
+ cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
+ }
+
+ zfs_close(zhp);
+ return (0);
+}
+
+/*
+ * Given a dataset, rollback to a specific snapshot, discarding any
+ * data changes since then and making it the active dataset.
+ *
+ * Any snapshots and bookmarks more recent than the target are
+ * destroyed, along with their dependents (i.e. clones).
+ */
+int
+zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
+{
+ rollback_data_t cb = { 0 };
+ int err;
+ boolean_t restore_resv = 0;
+ uint64_t min_txg = 0, old_volsize = 0, new_volsize;
+ zfs_prop_t resv_prop;
+
+ assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
+ zhp->zfs_type == ZFS_TYPE_VOLUME);
+
+ /*
+ * Destroy all recent snapshots and their dependents.
+ */
+ cb.cb_force = force;
+ cb.cb_target = snap->zfs_name;
+ cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
+
+ if (cb.cb_create > 0)
+ min_txg = cb.cb_create;
+
+ (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb,
+ min_txg, 0);
+
+ (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
+
+ if (cb.cb_error)
+ return (-1);
+
+ /*
+ * Now that we have verified that the snapshot is the latest,
+ * rollback to the given snapshot.
+ */
+
+ if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
+ if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
+ return (-1);
+ old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
+ restore_resv =
+ (old_volsize == zfs_prop_get_int(zhp, resv_prop));
+ }
+
+ /*
+ * Pass both the filesystem and the wanted snapshot names,
+ * we would get an error back if the snapshot is destroyed or
+ * a new snapshot is created before this request is processed.
+ */
+ err = lzc_rollback_to(zhp->zfs_name, snap->zfs_name);
+ if (err != 0) {
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
+ zhp->zfs_name);
+ switch (err) {
+ case EEXIST:
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "there is a snapshot or bookmark more recent "
+ "than '%s'"), snap->zfs_name);
+ (void) zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf);
+ break;
+ case ESRCH:
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is not found among snapshots of '%s'"),
+ snap->zfs_name, zhp->zfs_name);
+ (void) zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf);
+ break;
+ case EINVAL:
+ (void) zfs_error(zhp->zfs_hdl, EZFS_BADTYPE, errbuf);
+ break;
+ default:
+ (void) zfs_standard_error(zhp->zfs_hdl, err, errbuf);
+ }
+ return (err);
+ }
+
+ /*
+ * For volumes, if the pre-rollback volsize matched the pre-
+ * rollback reservation and the volsize has changed then set
+ * the reservation property to the post-rollback volsize.
+ * Make a new handle since the rollback closed the dataset.
+ */
+ if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
+ (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
+ if (restore_resv) {
+ new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
+ if (old_volsize != new_volsize)
+ err = zfs_prop_set_int(zhp, resv_prop,
+ new_volsize);
+ }
+ zfs_close(zhp);
+ }
+ return (err);
+}
+
+/*
+ * Renames the given dataset.
+ */
+int
+zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
+ renameflags_t flags)
+{
+ int ret = 0;
+ zfs_cmd_t zc = { 0 };
+ char *delim;
+ prop_changelist_t *cl = NULL;
+ zfs_handle_t *zhrp = NULL;
+ char *parentname = NULL;
+ char parent[ZFS_MAX_DATASET_NAME_LEN];
+ char property[ZFS_MAXPROPLEN];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ char errbuf[1024];
+
+ /* if we have the same exact name, just return success */
+ if (strcmp(zhp->zfs_name, target) == 0)
+ return (0);
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot rename to '%s'"), target);
+
+ if (source != NULL) {
+ /*
+ * This is recursive snapshots rename, put snapshot name
+ * (that might not exist) into zfs_name.
+ */
+ assert(flags.recurse);
+
+ (void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name));
+ (void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name));
+ zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
+ }
+
+ /* make sure source name is valid */
+ if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+ /*
+ * Make sure the target name is valid
+ */
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
+ zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
+ const char sep = zhp->zfs_type == ZFS_TYPE_SNAPSHOT ? '@' : '#';
+
+ if ((strchr(target, sep) == NULL) || *target == sep) {
+ /*
+ * Snapshot target name is abbreviated,
+ * reconstruct full dataset name
+ */
+ (void) strlcpy(parent, zhp->zfs_name, sizeof (parent));
+ delim = strchr(parent, sep);
+ if (strchr(target, sep) == NULL)
+ *(++delim) = '\0';
+ else
+ *delim = '\0';
+ (void) strlcat(parent, target, sizeof (parent));
+ target = parent;
+ } else {
+ /*
+ * Make sure we're renaming within the same dataset.
+ */
+ delim = strchr(target, sep);
+ if (strncmp(zhp->zfs_name, target, delim - target)
+ != 0 || zhp->zfs_name[delim - target] != sep) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "%s must be part of same dataset"),
+ zhp->zfs_type == ZFS_TYPE_SNAPSHOT ?
+ "snapshots" : "bookmarks");
+ return (zfs_error(hdl, EZFS_CROSSTARGET,
+ errbuf));
+ }
+ }
+
+ if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ } else {
+ if (flags.recurse) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "recursive rename must be a snapshot"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ }
+
+ if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+ /* validate parents */
+ if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0)
+ return (-1);
+
+ /* make sure we're in the same pool */
+ verify((delim = strchr(target, '/')) != NULL);
+ if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
+ zhp->zfs_name[delim - target] != '/') {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "datasets must be within same pool"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+ }
+
+ /* new name cannot be a child of the current dataset name */
+ if (is_descendant(zhp->zfs_name, target)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "New dataset name cannot be a descendant of "
+ "current dataset name"));
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ }
+ }
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
+
+ if (getzoneid() == GLOBAL_ZONEID &&
+ zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset is used in a non-global zone"));
+ return (zfs_error(hdl, EZFS_ZONED, errbuf));
+ }
+
+ /*
+ * Avoid unmounting file systems with mountpoint property set to
+ * 'legacy' or 'none' even if -u option is not given.
+ */
+ if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
+ !flags.recurse && !flags.nounmount &&
+ zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property,
+ sizeof (property), NULL, NULL, 0, B_FALSE) == 0 &&
+ (strcmp(property, "legacy") == 0 ||
+ strcmp(property, "none") == 0)) {
+ flags.nounmount = B_TRUE;
+ }
+ if (flags.recurse) {
+ parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
+ if (parentname == NULL) {
+ ret = -1;
+ goto error;
+ }
+ delim = strchr(parentname, '@');
+ *delim = '\0';
+ zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET);
+ if (zhrp == NULL) {
+ ret = -1;
+ goto error;
+ }
+ } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT &&
+ zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
+ if ((cl = changelist_gather(zhp, ZFS_PROP_NAME,
+ flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0,
+ flags.forceunmount ? MS_FORCE : 0)) == NULL) {
+ return (-1);
+ }
+
+ if (changelist_haszonedchild(cl)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "child dataset with inherited mountpoint is used "
+ "in a non-global zone"));
+ (void) zfs_error(hdl, EZFS_ZONED, errbuf);
+ ret = -1;
+ goto error;
+ }
+
+ if ((ret = changelist_prefix(cl)) != 0)
+ goto error;
+ }
+
+ if (ZFS_IS_VOLUME(zhp))
+ zc.zc_objset_type = DMU_OST_ZVOL;
+ else
+ zc.zc_objset_type = DMU_OST_ZFS;
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
+
+ zc.zc_cookie = flags.recurse ? 1 : 0;
+ if (flags.nounmount)
+ zc.zc_cookie |= 2;
+
+ if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
+ /*
+ * if it was recursive, the one that actually failed will
+ * be in zc.zc_name
+ */
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot rename '%s'"), zc.zc_name);
+
+ if (flags.recurse && errno == EEXIST) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "a child dataset already has a snapshot "
+ "with the new name"));
+ (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
+ } else if (errno == EINVAL) {
+ (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
+ } else {
+ (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
+ }
+
+ /*
+ * On failure, we still want to remount any filesystems that
+ * were previously mounted, so we don't alter the system state.
+ */
+ if (cl != NULL)
+ (void) changelist_postfix(cl);
+ } else {
+ if (cl != NULL) {
+ changelist_rename(cl, zfs_get_name(zhp), target);
+ ret = changelist_postfix(cl);
+ }
+ }
+
+error:
+ if (parentname != NULL) {
+ free(parentname);
+ }
+ if (zhrp != NULL) {
+ zfs_close(zhrp);
+ }
+ if (cl != NULL) {
+ changelist_free(cl);
+ }
+ return (ret);
+}
+
+nvlist_t *
+zfs_get_user_props(zfs_handle_t *zhp)
+{
+ return (zhp->zfs_user_props);
+}
+
+nvlist_t *
+zfs_get_recvd_props(zfs_handle_t *zhp)
+{
+ if (zhp->zfs_recvd_props == NULL)
+ if (get_recvd_props_ioctl(zhp) != 0)
+ return (NULL);
+ return (zhp->zfs_recvd_props);
+}
+
+/*
+ * This function is used by 'zfs list' to determine the exact set of columns to
+ * display, and their maximum widths. This does two main things:
+ *
+ * - If this is a list of all properties, then expand the list to include
+ * all native properties, and set a flag so that for each dataset we look
+ * for new unique user properties and add them to the list.
+ *
+ * - For non fixed-width properties, keep track of the maximum width seen
+ * so that we can size the column appropriately. If the user has
+ * requested received property values, we also need to compute the width
+ * of the RECEIVED column.
+ */
+int
+zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received,
+ boolean_t literal)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ zprop_list_t *entry;
+ zprop_list_t **last, **start;
+ nvlist_t *userprops, *propval;
+ nvpair_t *elem;
+ char *strval;
+ char buf[ZFS_MAXPROPLEN];
+
+ if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0)
+ return (-1);
+
+ userprops = zfs_get_user_props(zhp);
+
+ entry = *plp;
+ if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
+ /*
+ * Go through and add any user properties as necessary. We
+ * start by incrementing our list pointer to the first
+ * non-native property.
+ */
+ start = plp;
+ while (*start != NULL) {
+ if ((*start)->pl_prop == ZPROP_INVAL)
+ break;
+ start = &(*start)->pl_next;
+ }
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
+ /*
+ * See if we've already found this property in our list.
+ */
+ for (last = start; *last != NULL;
+ last = &(*last)->pl_next) {
+ if (strcmp((*last)->pl_user_prop,
+ nvpair_name(elem)) == 0)
+ break;
+ }
+
+ if (*last == NULL) {
+ if ((entry = zfs_alloc(hdl,
+ sizeof (zprop_list_t))) == NULL ||
+ ((entry->pl_user_prop = zfs_strdup(hdl,
+ nvpair_name(elem)))) == NULL) {
+ free(entry);
+ return (-1);
+ }
+
+ entry->pl_prop = ZPROP_INVAL;
+ entry->pl_width = strlen(nvpair_name(elem));
+ entry->pl_all = B_TRUE;
+ *last = entry;
+ }
+ }
+ }
+
+ /*
+ * Now go through and check the width of any non-fixed columns
+ */
+ for (entry = *plp; entry != NULL; entry = entry->pl_next) {
+ if (entry->pl_fixed && !literal)
+ continue;
+
+ if (entry->pl_prop != ZPROP_INVAL) {
+ if (zfs_prop_get(zhp, entry->pl_prop,
+ buf, sizeof (buf), NULL, NULL, 0, literal) == 0) {
+ if (strlen(buf) > entry->pl_width)
+ entry->pl_width = strlen(buf);
+ }
+ if (received && zfs_prop_get_recvd(zhp,
+ zfs_prop_to_name(entry->pl_prop),
+ buf, sizeof (buf), literal) == 0)
+ if (strlen(buf) > entry->pl_recvd_width)
+ entry->pl_recvd_width = strlen(buf);
+ } else {
+ if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop,
+ &propval) == 0) {
+ verify(nvlist_lookup_string(propval,
+ ZPROP_VALUE, &strval) == 0);
+ if (strlen(strval) > entry->pl_width)
+ entry->pl_width = strlen(strval);
+ }
+ if (received && zfs_prop_get_recvd(zhp,
+ entry->pl_user_prop,
+ buf, sizeof (buf), literal) == 0)
+ if (strlen(buf) > entry->pl_recvd_width)
+ entry->pl_recvd_width = strlen(buf);
+ }
+ }
+
+ return (0);
+}
+
+int
+zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
+ char *resource, void *export, void *sharetab,
+ int sharemax, zfs_share_op_t operation)
+{
+ zfs_cmd_t zc = { 0 };
+ int error;
+
+ (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
+ if (resource)
+ (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string));
+ zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
+ zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
+ zc.zc_share.z_sharetype = operation;
+ zc.zc_share.z_sharemax = sharemax;
+ error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
+ return (error);
+}
+
+void
+zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
+{
+ nvpair_t *curr;
+
+ /*
+ * Keep a reference to the props-table against which we prune the
+ * properties.
+ */
+ zhp->zfs_props_table = props;
+
+ curr = nvlist_next_nvpair(zhp->zfs_props, NULL);
+
+ while (curr) {
+ zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr));
+ nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr);
+
+ /*
+ * User properties will result in ZPROP_INVAL, and since we
+ * only know how to prune standard ZFS properties, we always
+ * leave these in the list. This can also happen if we
+ * encounter an unknown DSL property (when running older
+ * software, for example).
+ */
+ if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
+ (void) nvlist_remove(zhp->zfs_props,
+ nvpair_name(curr), nvpair_type(curr));
+ curr = next;
+ }
+}
+
+#ifdef illumos
+static int
+zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
+ zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
+{
+ zfs_cmd_t zc = { 0 };
+ nvlist_t *nvlist = NULL;
+ int error;
+
+ (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
+ zc.zc_cookie = (uint64_t)cmd;
+
+ if (cmd == ZFS_SMB_ACL_RENAME) {
+ if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
+ (void) no_memory(hdl);
+ return (0);
+ }
+ }
+
+ switch (cmd) {
+ case ZFS_SMB_ACL_ADD:
+ case ZFS_SMB_ACL_REMOVE:
+ (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string));
+ break;
+ case ZFS_SMB_ACL_RENAME:
+ if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC,
+ resource1) != 0) {
+ (void) no_memory(hdl);
+ return (-1);
+ }
+ if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET,
+ resource2) != 0) {
+ (void) no_memory(hdl);
+ return (-1);
+ }
+ if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) {
+ nvlist_free(nvlist);
+ return (-1);
+ }
+ break;
+ case ZFS_SMB_ACL_PURGE:
+ break;
+ default:
+ return (-1);
+ }
+ error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
+ nvlist_free(nvlist);
+ return (error);
+}
+
+int
+zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset,
+ char *path, char *resource)
+{
+ return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD,
+ resource, NULL));
+}
+
+int
+zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset,
+ char *path, char *resource)
+{
+ return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE,
+ resource, NULL));
+}
+
+int
+zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path)
+{
+ return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE,
+ NULL, NULL));
+}
+
+int
+zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path,
+ char *oldname, char *newname)
+{
+ return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
+ oldname, newname));
+}
+#endif /* illumos */
+
+int
+zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
+ zfs_userspace_cb_t func, void *arg)
+{
+ zfs_cmd_t zc = { 0 };
+ zfs_useracct_t buf[100];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ int ret;
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+ zc.zc_objset_type = type;
+ zc.zc_nvlist_dst = (uintptr_t)buf;
+
+ for (;;) {
+ zfs_useracct_t *zua = buf;
+
+ zc.zc_nvlist_dst_size = sizeof (buf);
+ if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot get used/quota for %s"), zc.zc_name);
+ return (zfs_standard_error_fmt(hdl, errno, errbuf));
+ }
+ if (zc.zc_nvlist_dst_size == 0)
+ break;
+
+ while (zc.zc_nvlist_dst_size > 0) {
+ if ((ret = func(arg, zua->zu_domain, zua->zu_rid,
+ zua->zu_space)) != 0)
+ return (ret);
+ zua++;
+ zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
+ }
+ }
+
+ return (0);
+}
+
+struct holdarg {
+ nvlist_t *nvl;
+ const char *snapname;
+ const char *tag;
+ boolean_t recursive;
+ int error;
+};
+
+static int
+zfs_hold_one(zfs_handle_t *zhp, void *arg)
+{
+ struct holdarg *ha = arg;
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ int rv = 0;
+
+ (void) snprintf(name, sizeof (name),
+ "%s@%s", zhp->zfs_name, ha->snapname);
+
+ if (lzc_exists(name))
+ fnvlist_add_string(ha->nvl, name, ha->tag);
+
+ if (ha->recursive)
+ rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
+ zfs_close(zhp);
+ return (rv);
+}
+
+int
+zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
+ boolean_t recursive, int cleanup_fd)
+{
+ int ret;
+ struct holdarg ha;
+
+ ha.nvl = fnvlist_alloc();
+ ha.snapname = snapname;
+ ha.tag = tag;
+ ha.recursive = recursive;
+ (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
+
+ if (nvlist_empty(ha.nvl)) {
+ char errbuf[1024];
+
+ fnvlist_free(ha.nvl);
+ ret = ENOENT;
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot hold snapshot '%s@%s'"),
+ zhp->zfs_name, snapname);
+ (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
+ return (ret);
+ }
+
+ ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
+ fnvlist_free(ha.nvl);
+
+ return (ret);
+}
+
+int
+zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
+{
+ int ret;
+ nvlist_t *errors;
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ char errbuf[1024];
+ nvpair_t *elem;
+
+ errors = NULL;
+ ret = lzc_hold(holds, cleanup_fd, &errors);
+
+ if (ret == 0) {
+ /* There may be errors even in the success case. */
+ fnvlist_free(errors);
+ return (0);
+ }
+
+ if (nvlist_empty(errors)) {
+ /* no hold-specific errors */
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot hold"));
+ switch (ret) {
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded"));
+ (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ break;
+ case EINVAL:
+ (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+ break;
+ default:
+ (void) zfs_standard_error(hdl, ret, errbuf);
+ }
+ }
+
+ for (elem = nvlist_next_nvpair(errors, NULL);
+ elem != NULL;
+ elem = nvlist_next_nvpair(errors, elem)) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot hold snapshot '%s'"), nvpair_name(elem));
+ switch (fnvpair_value_int32(elem)) {
+ case E2BIG:
+ /*
+ * Temporary tags wind up having the ds object id
+ * prepended. So even if we passed the length check
+ * above, it's still possible for the tag to wind
+ * up being slightly too long.
+ */
+ (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
+ break;
+ case EINVAL:
+ (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+ break;
+ case EEXIST:
+ (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
+ break;
+ default:
+ (void) zfs_standard_error(hdl,
+ fnvpair_value_int32(elem), errbuf);
+ }
+ }
+
+ fnvlist_free(errors);
+ return (ret);
+}
+
+static int
+zfs_release_one(zfs_handle_t *zhp, void *arg)
+{
+ struct holdarg *ha = arg;
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ int rv = 0;
+ nvlist_t *existing_holds;
+
+ (void) snprintf(name, sizeof (name),
+ "%s@%s", zhp->zfs_name, ha->snapname);
+
+ if (lzc_get_holds(name, &existing_holds) != 0) {
+ ha->error = ENOENT;
+ } else if (!nvlist_exists(existing_holds, ha->tag)) {
+ ha->error = ESRCH;
+ } else {
+ nvlist_t *torelease = fnvlist_alloc();
+ fnvlist_add_boolean(torelease, ha->tag);
+ fnvlist_add_nvlist(ha->nvl, name, torelease);
+ fnvlist_free(torelease);
+ }
+
+ if (ha->recursive)
+ rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
+ zfs_close(zhp);
+ return (rv);
+}
+
+int
+zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
+ boolean_t recursive)
+{
+ int ret;
+ struct holdarg ha;
+ nvlist_t *errors = NULL;
+ nvpair_t *elem;
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ char errbuf[1024];
+
+ ha.nvl = fnvlist_alloc();
+ ha.snapname = snapname;
+ ha.tag = tag;
+ ha.recursive = recursive;
+ ha.error = 0;
+ (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
+
+ if (nvlist_empty(ha.nvl)) {
+ fnvlist_free(ha.nvl);
+ ret = ha.error;
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot release hold from snapshot '%s@%s'"),
+ zhp->zfs_name, snapname);
+ if (ret == ESRCH) {
+ (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
+ } else {
+ (void) zfs_standard_error(hdl, ret, errbuf);
+ }
+ return (ret);
+ }
+
+ ret = lzc_release(ha.nvl, &errors);
+ fnvlist_free(ha.nvl);
+
+ if (ret == 0) {
+ /* There may be errors even in the success case. */
+ fnvlist_free(errors);
+ return (0);
+ }
+
+ if (nvlist_empty(errors)) {
+ /* no hold-specific errors */
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot release"));
+ switch (errno) {
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded"));
+ (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ break;
+ default:
+ (void) zfs_standard_error_fmt(hdl, errno, errbuf);
+ }
+ }
+
+ for (elem = nvlist_next_nvpair(errors, NULL);
+ elem != NULL;
+ elem = nvlist_next_nvpair(errors, elem)) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot release hold from snapshot '%s'"),
+ nvpair_name(elem));
+ switch (fnvpair_value_int32(elem)) {
+ case ESRCH:
+ (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
+ break;
+ case EINVAL:
+ (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+ break;
+ default:
+ (void) zfs_standard_error_fmt(hdl,
+ fnvpair_value_int32(elem), errbuf);
+ }
+ }
+
+ fnvlist_free(errors);
+ return (ret);
+}
+
+int
+zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
+{
+ zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ int nvsz = 2048;
+ void *nvbuf;
+ int err = 0;
+ char errbuf[1024];
+
+ assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
+ zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
+
+tryagain:
+
+ nvbuf = malloc(nvsz);
+ if (nvbuf == NULL) {
+ err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
+ goto out;
+ }
+
+ zc.zc_nvlist_dst_size = nvsz;
+ zc.zc_nvlist_dst = (uintptr_t)nvbuf;
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"),
+ zc.zc_name);
+ switch (errno) {
+ case ENOMEM:
+ free(nvbuf);
+ nvsz = zc.zc_nvlist_dst_size;
+ goto tryagain;
+
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded"));
+ err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ break;
+ case EINVAL:
+ err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
+ break;
+ case ENOENT:
+ err = zfs_error(hdl, EZFS_NOENT, errbuf);
+ break;
+ default:
+ err = zfs_standard_error_fmt(hdl, errno, errbuf);
+ break;
+ }
+ } else {
+ /* success */
+ int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
+ if (rc) {
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(
+ TEXT_DOMAIN, "cannot get permissions on '%s'"),
+ zc.zc_name);
+ err = zfs_standard_error_fmt(hdl, rc, errbuf);
+ }
+ }
+
+ free(nvbuf);
+out:
+ return (err);
+}
+
+int
+zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
+{
+ zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ char *nvbuf;
+ char errbuf[1024];
+ size_t nvsz;
+ int err;
+
+ assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
+ zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
+
+ err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
+ assert(err == 0);
+
+ nvbuf = malloc(nvsz);
+
+ err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
+ assert(err == 0);
+
+ zc.zc_nvlist_src_size = nvsz;
+ zc.zc_nvlist_src = (uintptr_t)nvbuf;
+ zc.zc_perm_action = un;
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+ if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"),
+ zc.zc_name);
+ switch (errno) {
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded"));
+ err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ break;
+ case EINVAL:
+ err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
+ break;
+ case ENOENT:
+ err = zfs_error(hdl, EZFS_NOENT, errbuf);
+ break;
+ default:
+ err = zfs_standard_error_fmt(hdl, errno, errbuf);
+ break;
+ }
+ }
+
+ free(nvbuf);
+
+ return (err);
+}
+
+int
+zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
+{
+ int err;
+ char errbuf[1024];
+
+ err = lzc_get_holds(zhp->zfs_name, nvl);
+
+ if (err != 0) {
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
+ zhp->zfs_name);
+ switch (err) {
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded"));
+ err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ break;
+ case EINVAL:
+ err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
+ break;
+ case ENOENT:
+ err = zfs_error(hdl, EZFS_NOENT, errbuf);
+ break;
+ default:
+ err = zfs_standard_error_fmt(hdl, errno, errbuf);
+ break;
+ }
+ }
+
+ return (err);
+}
+
+/*
+ * Convert the zvol's volume size to an appropriate reservation.
+ * Note: If this routine is updated, it is necessary to update the ZFS test
+ * suite's shell version in reservation.kshlib.
+ */
+uint64_t
+zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props)
+{
+ uint64_t numdb;
+ uint64_t nblocks, volblocksize;
+ int ncopies;
+ char *strval;
+
+ if (nvlist_lookup_string(props,
+ zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
+ ncopies = atoi(strval);
+ else
+ ncopies = 1;
+ if (nvlist_lookup_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ &volblocksize) != 0)
+ volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
+ nblocks = volsize/volblocksize;
+ /* start with metadnode L0-L6 */
+ numdb = 7;
+ /* calculate number of indirects */
+ while (nblocks > 1) {
+ nblocks += DNODES_PER_LEVEL - 1;
+ nblocks /= DNODES_PER_LEVEL;
+ numdb += nblocks;
+ }
+ numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
+ volsize *= ncopies;
+ /*
+ * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
+ * compressed, but in practice they compress down to about
+ * 1100 bytes
+ */
+ numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
+ volsize += numdb;
+ return (volsize);
+}
+
+/*
+ * Attach/detach the given filesystem to/from the given jail.
+ */
+int
+zfs_jail(zfs_handle_t *zhp, int jailid, int attach)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ zfs_cmd_t zc = { 0 };
+ char errbuf[1024];
+ unsigned long cmd;
+ int ret;
+
+ if (attach) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
+ } else {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name);
+ }
+
+ switch (zhp->zfs_type) {
+ case ZFS_TYPE_VOLUME:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "volumes can not be jailed"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ case ZFS_TYPE_SNAPSHOT:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "snapshots can not be jailed"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ }
+ assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ zc.zc_objset_type = DMU_OST_ZFS;
+ zc.zc_jailid = jailid;
+
+ cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL;
+ if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0)
+ zfs_standard_error(hdl, errno, errbuf);
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c
new file mode 100644
index 000000000000..db132190154c
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c
@@ -0,0 +1,834 @@
+/*
+ * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2015, 2018 by Delphix. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
+ */
+
+/*
+ * zfs diff support
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <libintl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/zfs_ioctl.h>
+#include <libzfs.h>
+#include "libzfs_impl.h"
+
+#define ZDIFF_SNAPDIR "/.zfs/snapshot/"
+#define ZDIFF_SHARESDIR "/.zfs/shares/"
+#define ZDIFF_PREFIX "zfs-diff-%d"
+
+#define ZDIFF_ADDED '+'
+#define ZDIFF_MODIFIED 'M'
+#define ZDIFF_REMOVED '-'
+#define ZDIFF_RENAMED 'R'
+
+typedef struct differ_info {
+ zfs_handle_t *zhp;
+ char *fromsnap;
+ char *frommnt;
+ char *tosnap;
+ char *tomnt;
+ char *ds;
+ char *dsmnt;
+ char *tmpsnap;
+ char errbuf[1024];
+ boolean_t isclone;
+ boolean_t scripted;
+ boolean_t classify;
+ boolean_t timestamped;
+ uint64_t shares;
+ int zerr;
+ int cleanupfd;
+ int outputfd;
+ int datafd;
+} differ_info_t;
+
+/*
+ * Given a {dsname, object id}, get the object path
+ */
+static int
+get_stats_for_obj(differ_info_t *di, const char *dsname, uint64_t obj,
+ char *pn, int maxlen, zfs_stat_t *sb)
+{
+ zfs_cmd_t zc = { 0 };
+ int error;
+
+ (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
+ zc.zc_obj = obj;
+
+ errno = 0;
+ error = ioctl(di->zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_STATS, &zc);
+ di->zerr = errno;
+
+ /* we can get stats even if we failed to get a path */
+ (void) memcpy(sb, &zc.zc_stat, sizeof (zfs_stat_t));
+ if (error == 0) {
+ ASSERT(di->zerr == 0);
+ (void) strlcpy(pn, zc.zc_value, maxlen);
+ return (0);
+ }
+
+ if (di->zerr == ESTALE) {
+ (void) snprintf(pn, maxlen, "(on_delete_queue)");
+ return (0);
+ } else if (di->zerr == EPERM) {
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN,
+ "The sys_config privilege or diff delegated permission "
+ "is needed\nto discover path names"));
+ return (-1);
+ } else {
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN,
+ "Unable to determine path or stats for "
+ "object %jd in %s"), (uintmax_t)obj, dsname);
+ return (-1);
+ }
+}
+
+/*
+ * stream_bytes
+ *
+ * Prints a file name out a character at a time. If the character is
+ * not in the range of what we consider "printable" ASCII, display it
+ * as an escaped 3-digit octal value. ASCII values less than a space
+ * are all control characters and we declare the upper end as the
+ * DELete character. This also is the last 7-bit ASCII character.
+ * We choose to treat all 8-bit ASCII as not printable for this
+ * application.
+ */
+static void
+stream_bytes(FILE *fp, const char *string)
+{
+ char c;
+
+ while ((c = *string++) != '\0') {
+ if (c > ' ' && c != '\\' && c < '\177') {
+ (void) fprintf(fp, "%c", c);
+ } else {
+ (void) fprintf(fp, "\\%03o", (uint8_t)c);
+ }
+ }
+}
+
+static void
+print_what(FILE *fp, mode_t what)
+{
+ char symbol;
+
+ switch (what & S_IFMT) {
+ case S_IFBLK:
+ symbol = 'B';
+ break;
+ case S_IFCHR:
+ symbol = 'C';
+ break;
+ case S_IFDIR:
+ symbol = '/';
+ break;
+#ifdef S_IFDOOR
+ case S_IFDOOR:
+ symbol = '>';
+ break;
+#endif
+ case S_IFIFO:
+ symbol = '|';
+ break;
+ case S_IFLNK:
+ symbol = '@';
+ break;
+#ifdef S_IFPORT
+ case S_IFPORT:
+ symbol = 'P';
+ break;
+#endif
+ case S_IFSOCK:
+ symbol = '=';
+ break;
+ case S_IFREG:
+ symbol = 'F';
+ break;
+ default:
+ symbol = '?';
+ break;
+ }
+ (void) fprintf(fp, "%c", symbol);
+}
+
+static void
+print_cmn(FILE *fp, differ_info_t *di, const char *file)
+{
+ stream_bytes(fp, di->dsmnt);
+ stream_bytes(fp, file);
+}
+
+static void
+print_rename(FILE *fp, differ_info_t *di, const char *old, const char *new,
+ zfs_stat_t *isb)
+{
+ if (di->timestamped)
+ (void) fprintf(fp, "%10lld.%09lld\t",
+ (longlong_t)isb->zs_ctime[0],
+ (longlong_t)isb->zs_ctime[1]);
+ (void) fprintf(fp, "%c\t", ZDIFF_RENAMED);
+ if (di->classify) {
+ print_what(fp, isb->zs_mode);
+ (void) fprintf(fp, "\t");
+ }
+ print_cmn(fp, di, old);
+ if (di->scripted)
+ (void) fprintf(fp, "\t");
+ else
+ (void) fprintf(fp, " -> ");
+ print_cmn(fp, di, new);
+ (void) fprintf(fp, "\n");
+}
+
+static void
+print_link_change(FILE *fp, differ_info_t *di, int delta, const char *file,
+ zfs_stat_t *isb)
+{
+ if (di->timestamped)
+ (void) fprintf(fp, "%10lld.%09lld\t",
+ (longlong_t)isb->zs_ctime[0],
+ (longlong_t)isb->zs_ctime[1]);
+ (void) fprintf(fp, "%c\t", ZDIFF_MODIFIED);
+ if (di->classify) {
+ print_what(fp, isb->zs_mode);
+ (void) fprintf(fp, "\t");
+ }
+ print_cmn(fp, di, file);
+ (void) fprintf(fp, "\t(%+d)", delta);
+ (void) fprintf(fp, "\n");
+}
+
+static void
+print_file(FILE *fp, differ_info_t *di, char type, const char *file,
+ zfs_stat_t *isb)
+{
+ if (di->timestamped)
+ (void) fprintf(fp, "%10lld.%09lld\t",
+ (longlong_t)isb->zs_ctime[0],
+ (longlong_t)isb->zs_ctime[1]);
+ (void) fprintf(fp, "%c\t", type);
+ if (di->classify) {
+ print_what(fp, isb->zs_mode);
+ (void) fprintf(fp, "\t");
+ }
+ print_cmn(fp, di, file);
+ (void) fprintf(fp, "\n");
+}
+
+static int
+write_inuse_diffs_one(FILE *fp, differ_info_t *di, uint64_t dobj)
+{
+ struct zfs_stat fsb, tsb;
+ mode_t fmode, tmode;
+ char fobjname[MAXPATHLEN], tobjname[MAXPATHLEN];
+ int fobjerr, tobjerr;
+ int change;
+
+ if (dobj == di->shares)
+ return (0);
+
+ /*
+ * Check the from and to snapshots for info on the object. If
+ * we get ENOENT, then the object just didn't exist in that
+ * snapshot. If we get ENOTSUP, then we tried to get
+ * info on a non-ZPL object, which we don't care about anyway.
+ */
+ fobjerr = get_stats_for_obj(di, di->fromsnap, dobj, fobjname,
+ MAXPATHLEN, &fsb);
+ if (fobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP)
+ return (-1);
+
+ tobjerr = get_stats_for_obj(di, di->tosnap, dobj, tobjname,
+ MAXPATHLEN, &tsb);
+ if (tobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP)
+ return (-1);
+
+ /*
+ * Unallocated object sharing the same meta dnode block
+ */
+ if (fobjerr && tobjerr) {
+ ASSERT(di->zerr == ENOENT || di->zerr == ENOTSUP);
+ di->zerr = 0;
+ return (0);
+ }
+
+ di->zerr = 0; /* negate get_stats_for_obj() from side that failed */
+ fmode = fsb.zs_mode & S_IFMT;
+ tmode = tsb.zs_mode & S_IFMT;
+ if (fmode == S_IFDIR || tmode == S_IFDIR || fsb.zs_links == 0 ||
+ tsb.zs_links == 0)
+ change = 0;
+ else
+ change = tsb.zs_links - fsb.zs_links;
+
+ if (fobjerr) {
+ if (change) {
+ print_link_change(fp, di, change, tobjname, &tsb);
+ return (0);
+ }
+ print_file(fp, di, ZDIFF_ADDED, tobjname, &tsb);
+ return (0);
+ } else if (tobjerr) {
+ if (change) {
+ print_link_change(fp, di, change, fobjname, &fsb);
+ return (0);
+ }
+ print_file(fp, di, ZDIFF_REMOVED, fobjname, &fsb);
+ return (0);
+ }
+
+ if (fmode != tmode && fsb.zs_gen == tsb.zs_gen)
+ tsb.zs_gen++; /* Force a generational difference */
+
+ /* Simple modification or no change */
+ if (fsb.zs_gen == tsb.zs_gen) {
+ /* No apparent changes. Could we assert !this? */
+ if (fsb.zs_ctime[0] == tsb.zs_ctime[0] &&
+ fsb.zs_ctime[1] == tsb.zs_ctime[1])
+ return (0);
+ if (change) {
+ print_link_change(fp, di, change,
+ change > 0 ? fobjname : tobjname, &tsb);
+ } else if (strcmp(fobjname, tobjname) == 0) {
+ print_file(fp, di, ZDIFF_MODIFIED, fobjname, &tsb);
+ } else {
+ print_rename(fp, di, fobjname, tobjname, &tsb);
+ }
+ return (0);
+ } else {
+ /* file re-created or object re-used */
+ print_file(fp, di, ZDIFF_REMOVED, fobjname, &fsb);
+ print_file(fp, di, ZDIFF_ADDED, tobjname, &tsb);
+ return (0);
+ }
+}
+
+static int
+write_inuse_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr)
+{
+ uint64_t o;
+ int err;
+
+ for (o = dr->ddr_first; o <= dr->ddr_last; o++) {
+ if ((err = write_inuse_diffs_one(fp, di, o)) != 0)
+ return (err);
+ }
+ return (0);
+}
+
+static int
+describe_free(FILE *fp, differ_info_t *di, uint64_t object, char *namebuf,
+ int maxlen)
+{
+ struct zfs_stat sb;
+
+ if (get_stats_for_obj(di, di->fromsnap, object, namebuf,
+ maxlen, &sb) != 0) {
+ return (-1);
+ }
+ /* Don't print if in the delete queue on from side */
+ if (di->zerr == ESTALE) {
+ di->zerr = 0;
+ return (0);
+ }
+
+ print_file(fp, di, ZDIFF_REMOVED, namebuf, &sb);
+ return (0);
+}
+
+static int
+write_free_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr)
+{
+ zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *lhdl = di->zhp->zfs_hdl;
+ char fobjname[MAXPATHLEN];
+
+ (void) strlcpy(zc.zc_name, di->fromsnap, sizeof (zc.zc_name));
+ zc.zc_obj = dr->ddr_first - 1;
+
+ ASSERT(di->zerr == 0);
+
+ while (zc.zc_obj < dr->ddr_last) {
+ int err;
+
+ err = ioctl(lhdl->libzfs_fd, ZFS_IOC_NEXT_OBJ, &zc);
+ if (err == 0) {
+ if (zc.zc_obj == di->shares) {
+ zc.zc_obj++;
+ continue;
+ }
+ if (zc.zc_obj > dr->ddr_last) {
+ break;
+ }
+ err = describe_free(fp, di, zc.zc_obj, fobjname,
+ MAXPATHLEN);
+ if (err)
+ break;
+ } else if (errno == ESRCH) {
+ break;
+ } else {
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN,
+ "next allocated object (> %jd) find failure"),
+ (uintmax_t)zc.zc_obj);
+ di->zerr = errno;
+ break;
+ }
+ }
+ if (di->zerr)
+ return (-1);
+ return (0);
+}
+
+static void *
+differ(void *arg)
+{
+ differ_info_t *di = arg;
+ dmu_diff_record_t dr;
+ FILE *ofp;
+ int err = 0;
+
+ if ((ofp = fdopen(di->outputfd, "w")) == NULL) {
+ di->zerr = errno;
+ (void) strerror_r(errno, di->errbuf, sizeof (di->errbuf));
+ (void) close(di->datafd);
+ return ((void *)-1);
+ }
+
+ for (;;) {
+ char *cp = (char *)&dr;
+ int len = sizeof (dr);
+ int rv;
+
+ do {
+ rv = read(di->datafd, cp, len);
+ cp += rv;
+ len -= rv;
+ } while (len > 0 && rv > 0);
+
+ if (rv < 0 || (rv == 0 && len != sizeof (dr))) {
+ di->zerr = EPIPE;
+ break;
+ } else if (rv == 0) {
+ /* end of file at a natural breaking point */
+ break;
+ }
+
+ switch (dr.ddr_type) {
+ case DDR_FREE:
+ err = write_free_diffs(ofp, di, &dr);
+ break;
+ case DDR_INUSE:
+ err = write_inuse_diffs(ofp, di, &dr);
+ break;
+ default:
+ di->zerr = EPIPE;
+ break;
+ }
+
+ if (err || di->zerr)
+ break;
+ }
+
+ (void) fclose(ofp);
+ (void) close(di->datafd);
+ if (err)
+ return ((void *)-1);
+ if (di->zerr) {
+ ASSERT(di->zerr == EPIPE);
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN,
+ "Internal error: bad data from diff IOCTL"));
+ return ((void *)-1);
+ }
+ return ((void *)0);
+}
+
+static int
+find_shares_object(differ_info_t *di)
+{
+ char fullpath[MAXPATHLEN];
+ struct stat64 sb = { 0 };
+
+ (void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN);
+ (void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
+
+ if (stat64(fullpath, &sb) != 0) {
+#ifdef illumos
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
+ return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
+#else
+ return (0);
+#endif
+ }
+
+ di->shares = (uint64_t)sb.st_ino;
+ return (0);
+}
+
+static int
+make_temp_snapshot(differ_info_t *di)
+{
+ libzfs_handle_t *hdl = di->zhp->zfs_hdl;
+ zfs_cmd_t zc = { 0 };
+
+ (void) snprintf(zc.zc_value, sizeof (zc.zc_value),
+ ZDIFF_PREFIX, getpid());
+ (void) strlcpy(zc.zc_name, di->ds, sizeof (zc.zc_name));
+ zc.zc_cleanup_fd = di->cleanupfd;
+
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_TMP_SNAPSHOT, &zc) != 0) {
+ int err = errno;
+ if (err == EPERM) {
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN, "The diff delegated "
+ "permission is needed in order\nto create a "
+ "just-in-time snapshot for diffing\n"));
+ return (zfs_error(hdl, EZFS_DIFF, di->errbuf));
+ } else {
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN, "Cannot create just-in-time "
+ "snapshot of '%s'"), zc.zc_name);
+ return (zfs_standard_error(hdl, err, di->errbuf));
+ }
+ }
+
+ di->tmpsnap = zfs_strdup(hdl, zc.zc_value);
+ di->tosnap = zfs_asprintf(hdl, "%s@%s", di->ds, di->tmpsnap);
+ return (0);
+}
+
+static void
+teardown_differ_info(differ_info_t *di)
+{
+ free(di->ds);
+ free(di->dsmnt);
+ free(di->fromsnap);
+ free(di->frommnt);
+ free(di->tosnap);
+ free(di->tmpsnap);
+ free(di->tomnt);
+ (void) close(di->cleanupfd);
+}
+
+static int
+get_snapshot_names(differ_info_t *di, const char *fromsnap,
+ const char *tosnap)
+{
+ libzfs_handle_t *hdl = di->zhp->zfs_hdl;
+ char *atptrf = NULL;
+ char *atptrt = NULL;
+ int fdslen, fsnlen;
+ int tdslen, tsnlen;
+
+ /*
+ * Can accept
+ * dataset@snap1
+ * dataset@snap1 dataset@snap2
+ * dataset@snap1 @snap2
+ * dataset@snap1 dataset
+ * @snap1 dataset@snap2
+ */
+ if (tosnap == NULL) {
+ /* only a from snapshot given, must be valid */
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN,
+ "Badly formed snapshot name %s"), fromsnap);
+
+ if (!zfs_validate_name(hdl, fromsnap, ZFS_TYPE_SNAPSHOT,
+ B_FALSE)) {
+ return (zfs_error(hdl, EZFS_INVALIDNAME,
+ di->errbuf));
+ }
+
+ atptrf = strchr(fromsnap, '@');
+ ASSERT(atptrf != NULL);
+ fdslen = atptrf - fromsnap;
+
+ di->fromsnap = zfs_strdup(hdl, fromsnap);
+ di->ds = zfs_strdup(hdl, fromsnap);
+ di->ds[fdslen] = '\0';
+
+ /* the to snap will be a just-in-time snap of the head */
+ return (make_temp_snapshot(di));
+ }
+
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN,
+ "Unable to determine which snapshots to compare"));
+
+ atptrf = strchr(fromsnap, '@');
+ atptrt = strchr(tosnap, '@');
+ fdslen = atptrf ? atptrf - fromsnap : strlen(fromsnap);
+ tdslen = atptrt ? atptrt - tosnap : strlen(tosnap);
+ fsnlen = strlen(fromsnap) - fdslen; /* includes @ sign */
+ tsnlen = strlen(tosnap) - tdslen; /* includes @ sign */
+
+ if (fsnlen <= 1 || tsnlen == 1 || (fdslen == 0 && tdslen == 0) ||
+ (fsnlen == 0 && tsnlen == 0)) {
+ return (zfs_error(hdl, EZFS_INVALIDNAME, di->errbuf));
+ } else if ((fdslen > 0 && tdslen > 0) &&
+ ((tdslen != fdslen || strncmp(fromsnap, tosnap, fdslen) != 0))) {
+ /*
+ * not the same dataset name, might be okay if
+ * tosnap is a clone of a fromsnap descendant.
+ */
+ char origin[ZFS_MAX_DATASET_NAME_LEN];
+ zprop_source_t src;
+ zfs_handle_t *zhp;
+
+ di->ds = zfs_alloc(di->zhp->zfs_hdl, tdslen + 1);
+ (void) strncpy(di->ds, tosnap, tdslen);
+ di->ds[tdslen] = '\0';
+
+ zhp = zfs_open(hdl, di->ds, ZFS_TYPE_FILESYSTEM);
+ while (zhp != NULL) {
+ if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
+ sizeof (origin), &src, NULL, 0, B_FALSE) != 0) {
+ (void) zfs_close(zhp);
+ zhp = NULL;
+ break;
+ }
+ if (strncmp(origin, fromsnap, fsnlen) == 0)
+ break;
+
+ (void) zfs_close(zhp);
+ zhp = zfs_open(hdl, origin, ZFS_TYPE_FILESYSTEM);
+ }
+
+ if (zhp == NULL) {
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN,
+ "Not an earlier snapshot from the same fs"));
+ return (zfs_error(hdl, EZFS_INVALIDNAME, di->errbuf));
+ } else {
+ (void) zfs_close(zhp);
+ }
+
+ di->isclone = B_TRUE;
+ di->fromsnap = zfs_strdup(hdl, fromsnap);
+ if (tsnlen) {
+ di->tosnap = zfs_strdup(hdl, tosnap);
+ } else {
+ return (make_temp_snapshot(di));
+ }
+ } else {
+ int dslen = fdslen ? fdslen : tdslen;
+
+ di->ds = zfs_alloc(hdl, dslen + 1);
+ (void) strncpy(di->ds, fdslen ? fromsnap : tosnap, dslen);
+ di->ds[dslen] = '\0';
+
+ di->fromsnap = zfs_asprintf(hdl, "%s%s", di->ds, atptrf);
+ if (tsnlen) {
+ di->tosnap = zfs_asprintf(hdl, "%s%s", di->ds, atptrt);
+ } else {
+ return (make_temp_snapshot(di));
+ }
+ }
+ return (0);
+}
+
+static int
+get_mountpoint(differ_info_t *di, char *dsnm, char **mntpt)
+{
+ boolean_t mounted;
+
+ mounted = is_mounted(di->zhp->zfs_hdl, dsnm, mntpt);
+ if (mounted == B_FALSE) {
+ (void) snprintf(di->errbuf, sizeof (di->errbuf),
+ dgettext(TEXT_DOMAIN,
+ "Cannot diff an unmounted snapshot"));
+ return (zfs_error(di->zhp->zfs_hdl, EZFS_BADTYPE, di->errbuf));
+ }
+
+ /* Avoid a double slash at the beginning of root-mounted datasets */
+ if (**mntpt == '/' && *(*mntpt + 1) == '\0')
+ **mntpt = '\0';
+ return (0);
+}
+
+static int
+get_mountpoints(differ_info_t *di)
+{
+ char *strptr;
+ char *frommntpt;
+
+ /*
+ * first get the mountpoint for the parent dataset
+ */
+ if (get_mountpoint(di, di->ds, &di->dsmnt) != 0)
+ return (-1);
+
+ strptr = strchr(di->tosnap, '@');
+ ASSERT3P(strptr, !=, NULL);
+ di->tomnt = zfs_asprintf(di->zhp->zfs_hdl, "%s%s%s", di->dsmnt,
+ ZDIFF_SNAPDIR, ++strptr);
+
+ strptr = strchr(di->fromsnap, '@');
+ ASSERT3P(strptr, !=, NULL);
+
+ frommntpt = di->dsmnt;
+ if (di->isclone) {
+ char *mntpt;
+ int err;
+
+ *strptr = '\0';
+ err = get_mountpoint(di, di->fromsnap, &mntpt);
+ *strptr = '@';
+ if (err != 0)
+ return (-1);
+ frommntpt = mntpt;
+ }
+
+ di->frommnt = zfs_asprintf(di->zhp->zfs_hdl, "%s%s%s", frommntpt,
+ ZDIFF_SNAPDIR, ++strptr);
+
+ if (di->isclone)
+ free(frommntpt);
+
+ return (0);
+}
+
+static int
+setup_differ_info(zfs_handle_t *zhp, const char *fromsnap,
+ const char *tosnap, differ_info_t *di)
+{
+ di->zhp = zhp;
+
+ di->cleanupfd = open(ZFS_DEV, O_RDWR|O_EXCL);
+ VERIFY(di->cleanupfd >= 0);
+
+ if (get_snapshot_names(di, fromsnap, tosnap) != 0)
+ return (-1);
+
+ if (get_mountpoints(di) != 0)
+ return (-1);
+
+ if (find_shares_object(di) != 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+zfs_show_diffs(zfs_handle_t *zhp, int outfd, const char *fromsnap,
+ const char *tosnap, int flags)
+{
+ zfs_cmd_t zc = { 0 };
+ char errbuf[1024];
+ differ_info_t di = { 0 };
+ pthread_t tid;
+ int pipefd[2];
+ int iocerr;
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "zfs diff failed"));
+
+ if (setup_differ_info(zhp, fromsnap, tosnap, &di)) {
+ teardown_differ_info(&di);
+ return (-1);
+ }
+
+ if (pipe(pipefd)) {
+ zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+ teardown_differ_info(&di);
+ return (zfs_error(zhp->zfs_hdl, EZFS_PIPEFAILED, errbuf));
+ }
+
+ di.scripted = (flags & ZFS_DIFF_PARSEABLE);
+ di.classify = (flags & ZFS_DIFF_CLASSIFY);
+ di.timestamped = (flags & ZFS_DIFF_TIMESTAMP);
+
+ di.outputfd = outfd;
+ di.datafd = pipefd[0];
+
+ if (pthread_create(&tid, NULL, differ, &di)) {
+ zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+ (void) close(pipefd[0]);
+ (void) close(pipefd[1]);
+ teardown_differ_info(&di);
+ return (zfs_error(zhp->zfs_hdl,
+ EZFS_THREADCREATEFAILED, errbuf));
+ }
+
+ /* do the ioctl() */
+ (void) strlcpy(zc.zc_value, di.fromsnap, strlen(di.fromsnap) + 1);
+ (void) strlcpy(zc.zc_name, di.tosnap, strlen(di.tosnap) + 1);
+ zc.zc_cookie = pipefd[1];
+
+ iocerr = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DIFF, &zc);
+ if (iocerr != 0) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "Unable to obtain diffs"));
+ if (errno == EPERM) {
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "\n The sys_mount privilege or diff delegated "
+ "permission is needed\n to execute the "
+ "diff ioctl"));
+ } else if (errno == EXDEV) {
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "\n Not an earlier snapshot from the same fs"));
+ } else if (errno != EPIPE || di.zerr == 0) {
+ zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+ }
+ (void) close(pipefd[1]);
+ (void) pthread_cancel(tid);
+ (void) pthread_join(tid, NULL);
+ teardown_differ_info(&di);
+ if (di.zerr != 0 && di.zerr != EPIPE) {
+ zfs_error_aux(zhp->zfs_hdl, strerror(di.zerr));
+ return (zfs_error(zhp->zfs_hdl, EZFS_DIFF, di.errbuf));
+ } else {
+ return (zfs_error(zhp->zfs_hdl, EZFS_DIFFDATA, errbuf));
+ }
+ }
+
+ (void) close(pipefd[1]);
+ (void) pthread_join(tid, NULL);
+
+ if (di.zerr != 0) {
+ zfs_error_aux(zhp->zfs_hdl, strerror(di.zerr));
+ return (zfs_error(zhp->zfs_hdl, EZFS_DIFF, di.errbuf));
+ }
+ teardown_differ_info(&di);
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c
new file mode 100644
index 000000000000..474470c416ea
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c
@@ -0,0 +1,452 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <libintl.h>
+#include <link.h>
+#include <pthread.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <libzfs.h>
+
+#include <fm/libtopo.h>
+#include <sys/fm/protocol.h>
+#include <sys/systeminfo.h>
+
+#include "libzfs_impl.h"
+
+/*
+ * This file is responsible for determining the relationship between I/O
+ * devices paths and physical locations. In the world of MPxIO and external
+ * enclosures, the device path is not synonymous with the physical location.
+ * If you remove a drive and insert it into a different slot, it will end up
+ * with the same path under MPxIO. If you recable storage enclosures, the
+ * device paths may change. All of this makes it difficult to implement the
+ * 'autoreplace' property, which is supposed to automatically manage disk
+ * replacement based on physical slot.
+ *
+ * In order to work around these limitations, we have a per-vdev FRU property
+ * that is the libtopo path (minus disk-specific authority information) to the
+ * physical location of the device on the system. This is an optional
+ * property, and is only needed when using the 'autoreplace' property or when
+ * generating FMA faults against vdevs.
+ */
+
+/*
+ * Because the FMA packages depend on ZFS, we have to dlopen() libtopo in case
+ * it is not present. We only need this once per library instance, so it is
+ * not part of the libzfs handle.
+ */
+static void *_topo_dlhandle;
+static topo_hdl_t *(*_topo_open)(int, const char *, int *);
+static void (*_topo_close)(topo_hdl_t *);
+static char *(*_topo_snap_hold)(topo_hdl_t *, const char *, int *);
+static void (*_topo_snap_release)(topo_hdl_t *);
+static topo_walk_t *(*_topo_walk_init)(topo_hdl_t *, const char *,
+ topo_walk_cb_t, void *, int *);
+static int (*_topo_walk_step)(topo_walk_t *, int);
+static void (*_topo_walk_fini)(topo_walk_t *);
+static void (*_topo_hdl_strfree)(topo_hdl_t *, char *);
+static char *(*_topo_node_name)(tnode_t *);
+static int (*_topo_prop_get_string)(tnode_t *, const char *, const char *,
+ char **, int *);
+static int (*_topo_node_fru)(tnode_t *, nvlist_t **, nvlist_t *, int *);
+static int (*_topo_fmri_nvl2str)(topo_hdl_t *, nvlist_t *, char **, int *);
+static int (*_topo_fmri_strcmp_noauth)(topo_hdl_t *, const char *,
+ const char *);
+
+#define ZFS_FRU_HASH_SIZE 257
+
+static size_t
+fru_strhash(const char *key)
+{
+ ulong_t g, h = 0;
+ const char *p;
+
+ for (p = key; *p != '\0'; p++) {
+ h = (h << 4) + *p;
+
+ if ((g = (h & 0xf0000000)) != 0) {
+ h ^= (g >> 24);
+ h ^= g;
+ }
+ }
+
+ return (h % ZFS_FRU_HASH_SIZE);
+}
+
+static int
+libzfs_fru_gather(topo_hdl_t *thp, tnode_t *tn, void *arg)
+{
+ libzfs_handle_t *hdl = arg;
+ nvlist_t *fru;
+ char *devpath, *frustr;
+ int err;
+ libzfs_fru_t *frup;
+ size_t idx;
+
+ /*
+ * If this is the chassis node, and we don't yet have the system
+ * chassis ID, then fill in this value now.
+ */
+ if (hdl->libzfs_chassis_id[0] == '\0' &&
+ strcmp(_topo_node_name(tn), "chassis") == 0) {
+ if (_topo_prop_get_string(tn, FM_FMRI_AUTHORITY,
+ FM_FMRI_AUTH_CHASSIS, &devpath, &err) == 0)
+ (void) strlcpy(hdl->libzfs_chassis_id, devpath,
+ sizeof (hdl->libzfs_chassis_id));
+ }
+
+ /*
+ * Skip non-disk nodes.
+ */
+ if (strcmp(_topo_node_name(tn), "disk") != 0)
+ return (TOPO_WALK_NEXT);
+
+ /*
+ * Get the devfs path and FRU.
+ */
+ if (_topo_prop_get_string(tn, "io", "devfs-path", &devpath, &err) != 0)
+ return (TOPO_WALK_NEXT);
+
+ if (libzfs_fru_lookup(hdl, devpath) != NULL) {
+ _topo_hdl_strfree(thp, devpath);
+ return (TOPO_WALK_NEXT);
+ }
+
+ if (_topo_node_fru(tn, &fru, NULL, &err) != 0) {
+ _topo_hdl_strfree(thp, devpath);
+ return (TOPO_WALK_NEXT);
+ }
+
+ /*
+ * Convert the FRU into a string.
+ */
+ if (_topo_fmri_nvl2str(thp, fru, &frustr, &err) != 0) {
+ nvlist_free(fru);
+ _topo_hdl_strfree(thp, devpath);
+ return (TOPO_WALK_NEXT);
+ }
+
+ nvlist_free(fru);
+
+ /*
+ * Finally, we have a FRU string and device path. Add it to the hash.
+ */
+ if ((frup = calloc(sizeof (libzfs_fru_t), 1)) == NULL) {
+ _topo_hdl_strfree(thp, devpath);
+ _topo_hdl_strfree(thp, frustr);
+ return (TOPO_WALK_NEXT);
+ }
+
+ if ((frup->zf_device = strdup(devpath)) == NULL ||
+ (frup->zf_fru = strdup(frustr)) == NULL) {
+ free(frup->zf_device);
+ free(frup);
+ _topo_hdl_strfree(thp, devpath);
+ _topo_hdl_strfree(thp, frustr);
+ return (TOPO_WALK_NEXT);
+ }
+
+ _topo_hdl_strfree(thp, devpath);
+ _topo_hdl_strfree(thp, frustr);
+
+ idx = fru_strhash(frup->zf_device);
+ frup->zf_chain = hdl->libzfs_fru_hash[idx];
+ hdl->libzfs_fru_hash[idx] = frup;
+ frup->zf_next = hdl->libzfs_fru_list;
+ hdl->libzfs_fru_list = frup;
+
+ return (TOPO_WALK_NEXT);
+}
+
+/*
+ * Called during initialization to setup the dynamic libtopo connection.
+ */
+#pragma init(libzfs_init_fru)
+static void
+libzfs_init_fru(void)
+{
+ char path[MAXPATHLEN];
+ char isa[257];
+
+#if defined(_LP64)
+ if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
+ isa[0] = '\0';
+#else
+ isa[0] = '\0';
+#endif
+ (void) snprintf(path, sizeof (path),
+ "/usr/lib/fm/%s/libtopo.so", isa);
+
+ if ((_topo_dlhandle = dlopen(path, RTLD_LAZY)) == NULL)
+ return;
+
+ _topo_open = (topo_hdl_t *(*)())
+ dlsym(_topo_dlhandle, "topo_open");
+ _topo_close = (void (*)())
+ dlsym(_topo_dlhandle, "topo_close");
+ _topo_snap_hold = (char *(*)())
+ dlsym(_topo_dlhandle, "topo_snap_hold");
+ _topo_snap_release = (void (*)())
+ dlsym(_topo_dlhandle, "topo_snap_release");
+ _topo_walk_init = (topo_walk_t *(*)())
+ dlsym(_topo_dlhandle, "topo_walk_init");
+ _topo_walk_step = (int (*)())
+ dlsym(_topo_dlhandle, "topo_walk_step");
+ _topo_walk_fini = (void (*)())
+ dlsym(_topo_dlhandle, "topo_walk_fini");
+ _topo_hdl_strfree = (void (*)())
+ dlsym(_topo_dlhandle, "topo_hdl_strfree");
+ _topo_node_name = (char *(*)())
+ dlsym(_topo_dlhandle, "topo_node_name");
+ _topo_prop_get_string = (int (*)())
+ dlsym(_topo_dlhandle, "topo_prop_get_string");
+ _topo_node_fru = (int (*)())
+ dlsym(_topo_dlhandle, "topo_node_fru");
+ _topo_fmri_nvl2str = (int (*)())
+ dlsym(_topo_dlhandle, "topo_fmri_nvl2str");
+ _topo_fmri_strcmp_noauth = (int (*)())
+ dlsym(_topo_dlhandle, "topo_fmri_strcmp_noauth");
+
+ if (_topo_open == NULL || _topo_close == NULL ||
+ _topo_snap_hold == NULL || _topo_snap_release == NULL ||
+ _topo_walk_init == NULL || _topo_walk_step == NULL ||
+ _topo_walk_fini == NULL || _topo_hdl_strfree == NULL ||
+ _topo_node_name == NULL || _topo_prop_get_string == NULL ||
+ _topo_node_fru == NULL || _topo_fmri_nvl2str == NULL ||
+ _topo_fmri_strcmp_noauth == NULL) {
+ (void) dlclose(_topo_dlhandle);
+ _topo_dlhandle = NULL;
+ }
+}
+
+/*
+ * Refresh the mappings from device path -> FMRI. We do this by walking the
+ * hc topology looking for disk nodes, and recording the io/devfs-path and FRU.
+ * Note that we strip out the disk-specific authority information (serial,
+ * part, revision, etc) so that we are left with only the identifying
+ * characteristics of the slot (hc path and chassis-id).
+ */
+void
+libzfs_fru_refresh(libzfs_handle_t *hdl)
+{
+ int err;
+ char *uuid;
+ topo_hdl_t *thp;
+ topo_walk_t *twp;
+
+ if (_topo_dlhandle == NULL)
+ return;
+
+ /*
+ * Clear the FRU hash and initialize our basic structures.
+ */
+ libzfs_fru_clear(hdl, B_FALSE);
+
+ if ((hdl->libzfs_topo_hdl = _topo_open(TOPO_VERSION,
+ NULL, &err)) == NULL)
+ return;
+
+ thp = hdl->libzfs_topo_hdl;
+
+ if ((uuid = _topo_snap_hold(thp, NULL, &err)) == NULL)
+ return;
+
+ _topo_hdl_strfree(thp, uuid);
+
+ if (hdl->libzfs_fru_hash == NULL &&
+ (hdl->libzfs_fru_hash =
+ calloc(ZFS_FRU_HASH_SIZE, sizeof (void *))) == NULL)
+ return;
+
+ /*
+ * We now have a topo snapshot, so iterate over the hc topology looking
+ * for disks to add to the hash.
+ */
+ twp = _topo_walk_init(thp, FM_FMRI_SCHEME_HC,
+ libzfs_fru_gather, hdl, &err);
+ if (twp != NULL) {
+ (void) _topo_walk_step(twp, TOPO_WALK_CHILD);
+ _topo_walk_fini(twp);
+ }
+}
+
+/*
+ * Given a devfs path, return the FRU for the device, if known. This will
+ * automatically call libzfs_fru_refresh() if it hasn't already been called by
+ * the consumer. The string returned is valid until the next call to
+ * libzfs_fru_refresh().
+ */
+const char *
+libzfs_fru_lookup(libzfs_handle_t *hdl, const char *devpath)
+{
+ size_t idx = fru_strhash(devpath);
+ libzfs_fru_t *frup;
+
+ if (hdl->libzfs_fru_hash == NULL)
+ libzfs_fru_refresh(hdl);
+
+ if (hdl->libzfs_fru_hash == NULL)
+ return (NULL);
+
+ for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
+ frup = frup->zf_chain) {
+ if (strcmp(devpath, frup->zf_device) == 0)
+ return (frup->zf_fru);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Given a fru path, return the device path. This will automatically call
+ * libzfs_fru_refresh() if it hasn't already been called by the consumer. The
+ * string returned is valid until the next call to libzfs_fru_refresh().
+ */
+const char *
+libzfs_fru_devpath(libzfs_handle_t *hdl, const char *fru)
+{
+ libzfs_fru_t *frup;
+ size_t idx;
+
+ if (hdl->libzfs_fru_hash == NULL)
+ libzfs_fru_refresh(hdl);
+
+ if (hdl->libzfs_fru_hash == NULL)
+ return (NULL);
+
+ for (idx = 0; idx < ZFS_FRU_HASH_SIZE; idx++) {
+ for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
+ frup = frup->zf_next) {
+ if (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl,
+ fru, frup->zf_fru))
+ return (frup->zf_device);
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * Change the stored FRU for the given vdev.
+ */
+int
+zpool_fru_set(zpool_handle_t *zhp, uint64_t vdev_guid, const char *fru)
+{
+ zfs_cmd_t zc = { 0 };
+
+ (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ (void) strncpy(zc.zc_value, fru, sizeof (zc.zc_value));
+ zc.zc_guid = vdev_guid;
+
+ if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SETFRU, &zc) != 0)
+ return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot set FRU")));
+
+ return (0);
+}
+
+/*
+ * Compare to two FRUs, ignoring any authority information.
+ */
+boolean_t
+libzfs_fru_compare(libzfs_handle_t *hdl, const char *a, const char *b)
+{
+ if (hdl->libzfs_fru_hash == NULL)
+ libzfs_fru_refresh(hdl);
+
+ if (hdl->libzfs_fru_hash == NULL)
+ return (strcmp(a, b) == 0);
+
+ return (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl, a, b));
+}
+
+/*
+ * This special function checks to see whether the FRU indicates it's supposed
+ * to be in the system chassis, but the chassis-id doesn't match. This can
+ * happen in a clustered case, where both head nodes have the same logical
+ * disk, but opening the device on the other head node is meaningless.
+ */
+boolean_t
+libzfs_fru_notself(libzfs_handle_t *hdl, const char *fru)
+{
+ const char *chassisid;
+ size_t len;
+
+ if (hdl->libzfs_fru_hash == NULL)
+ libzfs_fru_refresh(hdl);
+
+ if (hdl->libzfs_chassis_id[0] == '\0')
+ return (B_FALSE);
+
+ if (strstr(fru, "/chassis=0/") == NULL)
+ return (B_FALSE);
+
+ if ((chassisid = strstr(fru, ":chassis-id=")) == NULL)
+ return (B_FALSE);
+
+ chassisid += 12;
+ len = strlen(hdl->libzfs_chassis_id);
+ if (strncmp(chassisid, hdl->libzfs_chassis_id, len) == 0 &&
+ (chassisid[len] == '/' || chassisid[len] == ':'))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
+ * Clear memory associated with the FRU hash.
+ */
+void
+libzfs_fru_clear(libzfs_handle_t *hdl, boolean_t final)
+{
+ libzfs_fru_t *frup;
+
+ while ((frup = hdl->libzfs_fru_list) != NULL) {
+ hdl->libzfs_fru_list = frup->zf_next;
+ free(frup->zf_device);
+ free(frup->zf_fru);
+ free(frup);
+ }
+
+ hdl->libzfs_fru_list = NULL;
+
+ if (hdl->libzfs_topo_hdl != NULL) {
+ _topo_snap_release(hdl->libzfs_topo_hdl);
+ _topo_close(hdl->libzfs_topo_hdl);
+ hdl->libzfs_topo_hdl = NULL;
+ }
+
+ if (final) {
+ free(hdl->libzfs_fru_hash);
+ } else if (hdl->libzfs_fru_hash != NULL) {
+ bzero(hdl->libzfs_fru_hash,
+ ZFS_FRU_HASH_SIZE * sizeof (void *));
+ }
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
new file mode 100644
index 000000000000..a0338afadb8f
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
@@ -0,0 +1,228 @@
+/*
+ * CDDL HEADER SART
+ *
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ */
+
+#ifndef _LIBZFS_IMPL_H
+#define _LIBZFS_IMPL_H
+
+#include <sys/fs/zfs.h>
+#include <sys/spa.h>
+#include <sys/nvpair.h>
+#include <sys/dmu.h>
+#include <sys/zfs_ioctl.h>
+
+#include <libshare.h>
+#include <libuutil.h>
+#include <libzfs.h>
+#include <libzfs_core.h>
+#include <libzfs_compat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef VERIFY
+#undef VERIFY
+#endif
+#define VERIFY verify
+
+typedef struct libzfs_fru {
+ char *zf_device;
+ char *zf_fru;
+ struct libzfs_fru *zf_chain;
+ struct libzfs_fru *zf_next;
+} libzfs_fru_t;
+
+struct libzfs_handle {
+ int libzfs_error;
+ int libzfs_fd;
+ FILE *libzfs_mnttab;
+ FILE *libzfs_sharetab;
+ zpool_handle_t *libzfs_pool_handles;
+ uu_avl_pool_t *libzfs_ns_avlpool;
+ uu_avl_t *libzfs_ns_avl;
+ uint64_t libzfs_ns_gen;
+ int libzfs_desc_active;
+ char libzfs_action[1024];
+ char libzfs_desc[1024];
+ int libzfs_printerr;
+ int libzfs_storeerr; /* stuff error messages into buffer */
+ void *libzfs_sharehdl; /* libshare handle */
+ boolean_t libzfs_mnttab_enable;
+ /*
+ * We need a lock to handle the case where parallel mount
+ * threads are populating the mnttab cache simultaneously. The
+ * lock only protects the integrity of the avl tree, and does
+ * not protect the contents of the mnttab entries themselves.
+ */
+ pthread_mutex_t libzfs_mnttab_cache_lock;
+ avl_tree_t libzfs_mnttab_cache;
+ int libzfs_pool_iter;
+ libzfs_fru_t **libzfs_fru_hash;
+ libzfs_fru_t *libzfs_fru_list;
+ char libzfs_chassis_id[256];
+ boolean_t libzfs_prop_debug;
+};
+
+struct zfs_handle {
+ libzfs_handle_t *zfs_hdl;
+ zpool_handle_t *zpool_hdl;
+ char zfs_name[ZFS_MAX_DATASET_NAME_LEN];
+ zfs_type_t zfs_type; /* type including snapshot */
+ zfs_type_t zfs_head_type; /* type excluding snapshot */
+ dmu_objset_stats_t zfs_dmustats;
+ nvlist_t *zfs_props;
+ nvlist_t *zfs_user_props;
+ nvlist_t *zfs_recvd_props;
+ boolean_t zfs_mntcheck;
+ char *zfs_mntopts;
+ uint8_t *zfs_props_table;
+};
+
+/*
+ * This is different from checking zfs_type, because it will also catch
+ * snapshots of volumes.
+ */
+#define ZFS_IS_VOLUME(zhp) ((zhp)->zfs_head_type == ZFS_TYPE_VOLUME)
+
+struct zpool_handle {
+ libzfs_handle_t *zpool_hdl;
+ zpool_handle_t *zpool_next;
+ char zpool_name[ZFS_MAX_DATASET_NAME_LEN];
+ int zpool_state;
+ size_t zpool_config_size;
+ nvlist_t *zpool_config;
+ nvlist_t *zpool_old_config;
+ nvlist_t *zpool_props;
+ diskaddr_t zpool_start_block;
+};
+
+typedef enum {
+ PROTO_NFS = 0,
+ PROTO_SMB = 1,
+ PROTO_END = 2
+} zfs_share_proto_t;
+
+/*
+ * The following can be used as a bitmask and any new values
+ * added must preserve that capability.
+ */
+typedef enum {
+ SHARED_NOT_SHARED = 0x0,
+ SHARED_NFS = 0x2,
+ SHARED_SMB = 0x4
+} zfs_share_type_t;
+
+#define CONFIG_BUF_MINSIZE 262144
+
+int zfs_error(libzfs_handle_t *, int, const char *);
+int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...);
+void zfs_error_aux(libzfs_handle_t *, const char *, ...);
+void *zfs_alloc(libzfs_handle_t *, size_t);
+void *zfs_realloc(libzfs_handle_t *, void *, size_t, size_t);
+char *zfs_asprintf(libzfs_handle_t *, const char *, ...);
+char *zfs_strdup(libzfs_handle_t *, const char *);
+int no_memory(libzfs_handle_t *);
+
+int zfs_standard_error(libzfs_handle_t *, int, const char *);
+int zfs_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
+int zpool_standard_error(libzfs_handle_t *, int, const char *);
+int zpool_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
+
+int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***,
+ size_t *);
+zfs_handle_t *make_dataset_handle_zc(libzfs_handle_t *, zfs_cmd_t *);
+zfs_handle_t *make_dataset_simple_handle_zc(zfs_handle_t *, zfs_cmd_t *);
+
+int zprop_parse_value(libzfs_handle_t *, nvpair_t *, int, zfs_type_t,
+ nvlist_t *, char **, uint64_t *, const char *);
+int zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp,
+ zfs_type_t type);
+
+/*
+ * Use this changelist_gather() flag to force attempting mounts
+ * on each change node regardless of whether or not it is currently
+ * mounted.
+ */
+#define CL_GATHER_MOUNT_ALWAYS 0x01
+/*
+ * Use this changelist_gather() flag to prevent unmounting of file systems.
+ */
+#define CL_GATHER_DONT_UNMOUNT 0x02
+
+typedef struct prop_changelist prop_changelist_t;
+
+int zcmd_alloc_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, size_t);
+int zcmd_write_src_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t *);
+int zcmd_write_conf_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t *);
+int zcmd_expand_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *);
+int zcmd_read_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t **);
+void zcmd_free_nvlists(zfs_cmd_t *);
+
+int changelist_prefix(prop_changelist_t *);
+int changelist_postfix(prop_changelist_t *);
+void changelist_rename(prop_changelist_t *, const char *, const char *);
+void changelist_remove(prop_changelist_t *, const char *);
+void changelist_free(prop_changelist_t *);
+prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int, int);
+int changelist_unshare(prop_changelist_t *, zfs_share_proto_t *);
+int changelist_haszonedchild(prop_changelist_t *);
+
+void remove_mountpoint(zfs_handle_t *);
+int create_parents(libzfs_handle_t *, char *, int);
+boolean_t isa_child_of(const char *dataset, const char *parent);
+
+zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
+zfs_handle_t *make_bookmark_handle(zfs_handle_t *, const char *,
+ nvlist_t *props);
+
+int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **);
+
+boolean_t zpool_name_valid(libzfs_handle_t *, boolean_t, const char *);
+
+int zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
+ boolean_t modifying);
+
+void namespace_clear(libzfs_handle_t *);
+
+/*
+ * libshare (sharemgr) interfaces used internally.
+ */
+
+extern int zfs_init_libshare(libzfs_handle_t *, int);
+extern int zfs_parse_options(char *, zfs_share_proto_t);
+
+extern int zfs_unshare_proto(zfs_handle_t *,
+ const char *, zfs_share_proto_t *);
+
+extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBZFS_IMPL_H */
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
new file mode 100644
index 000000000000..a982e545a0b8
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
@@ -0,0 +1,1917 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright 2015 RackTop Systems.
+ * Copyright 2016 Nexenta Systems, Inc.
+ */
+
+/*
+ * Pool import support functions.
+ *
+ * To import a pool, we rely on reading the configuration information from the
+ * ZFS label of each device. If we successfully read the label, then we
+ * organize the configuration information in the following hierarchy:
+ *
+ * pool guid -> toplevel vdev guid -> label txg
+ *
+ * Duplicate entries matching this same tuple will be discarded. Once we have
+ * examined every device, we pick the best label txg config for each toplevel
+ * vdev. We then arrange these toplevel vdevs into a complete pool config, and
+ * update any paths that have changed. Finally, we attempt to import the pool
+ * using our derived config, and record the results.
+ */
+
+#include <aio.h>
+#include <ctype.h>
+#include <devid.h>
+#include <dirent.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <thread_pool.h>
+#include <libgeom.h>
+
+#include <sys/vdev_impl.h>
+
+#include "libzfs.h"
+#include "libzfs_impl.h"
+
+/*
+ * Intermediate structures used to gather configuration information.
+ */
+typedef struct config_entry {
+ uint64_t ce_txg;
+ nvlist_t *ce_config;
+ struct config_entry *ce_next;
+} config_entry_t;
+
+typedef struct vdev_entry {
+ uint64_t ve_guid;
+ config_entry_t *ve_configs;
+ struct vdev_entry *ve_next;
+} vdev_entry_t;
+
+typedef struct pool_entry {
+ uint64_t pe_guid;
+ vdev_entry_t *pe_vdevs;
+ struct pool_entry *pe_next;
+} pool_entry_t;
+
+typedef struct name_entry {
+ char *ne_name;
+ uint64_t ne_guid;
+ struct name_entry *ne_next;
+} name_entry_t;
+
+typedef struct pool_list {
+ pool_entry_t *pools;
+ name_entry_t *names;
+} pool_list_t;
+
+static char *
+get_devid(const char *path)
+{
+#ifdef have_devid
+ int fd;
+ ddi_devid_t devid;
+ char *minor, *ret;
+
+ if ((fd = open(path, O_RDONLY)) < 0)
+ return (NULL);
+
+ minor = NULL;
+ ret = NULL;
+ if (devid_get(fd, &devid) == 0) {
+ if (devid_get_minor_name(fd, &minor) == 0)
+ ret = devid_str_encode(devid, minor);
+ if (minor != NULL)
+ devid_str_free(minor);
+ devid_free(devid);
+ }
+ (void) close(fd);
+
+ return (ret);
+#else
+ return (NULL);
+#endif
+}
+
+
+/*
+ * Go through and fix up any path and/or devid information for the given vdev
+ * configuration.
+ */
+static int
+fix_paths(nvlist_t *nv, name_entry_t *names)
+{
+ nvlist_t **child;
+ uint_t c, children;
+ uint64_t guid;
+ name_entry_t *ne, *best;
+ char *path, *devid;
+ int matched;
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++)
+ if (fix_paths(child[c], names) != 0)
+ return (-1);
+ return (0);
+ }
+
+ /*
+ * This is a leaf (file or disk) vdev. In either case, go through
+ * the name list and see if we find a matching guid. If so, replace
+ * the path and see if we can calculate a new devid.
+ *
+ * There may be multiple names associated with a particular guid, in
+ * which case we have overlapping slices or multiple paths to the same
+ * disk. If this is the case, then we want to pick the path that is
+ * the most similar to the original, where "most similar" is the number
+ * of matching characters starting from the end of the path. This will
+ * preserve slice numbers even if the disks have been reorganized, and
+ * will also catch preferred disk names if multiple paths exist.
+ */
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0);
+ if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
+ path = NULL;
+
+ matched = 0;
+ best = NULL;
+ for (ne = names; ne != NULL; ne = ne->ne_next) {
+ if (ne->ne_guid == guid) {
+ const char *src, *dst;
+ int count;
+
+ if (path == NULL) {
+ best = ne;
+ break;
+ }
+
+ src = ne->ne_name + strlen(ne->ne_name) - 1;
+ dst = path + strlen(path) - 1;
+ for (count = 0; src >= ne->ne_name && dst >= path;
+ src--, dst--, count++)
+ if (*src != *dst)
+ break;
+
+ /*
+ * At this point, 'count' is the number of characters
+ * matched from the end.
+ */
+ if (count > matched || best == NULL) {
+ best = ne;
+ matched = count;
+ }
+ }
+ }
+
+ if (best == NULL)
+ return (0);
+
+ if (nvlist_add_string(nv, ZPOOL_CONFIG_PATH, best->ne_name) != 0)
+ return (-1);
+
+ if ((devid = get_devid(best->ne_name)) == NULL) {
+ (void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
+ } else {
+ if (nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) != 0) {
+ devid_str_free(devid);
+ return (-1);
+ }
+ devid_str_free(devid);
+ }
+
+ return (0);
+}
+
+/*
+ * Add the given configuration to the list of known devices.
+ */
+static int
+add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
+ nvlist_t *config)
+{
+ uint64_t pool_guid, vdev_guid, top_guid, txg, state;
+ pool_entry_t *pe;
+ vdev_entry_t *ve;
+ config_entry_t *ce;
+ name_entry_t *ne;
+
+ /*
+ * If this is a hot spare not currently in use or level 2 cache
+ * device, add it to the list of names to translate, but don't do
+ * anything else.
+ */
+ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+ &state) == 0 &&
+ (state == POOL_STATE_SPARE || state == POOL_STATE_L2CACHE) &&
+ nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, &vdev_guid) == 0) {
+ if ((ne = zfs_alloc(hdl, sizeof (name_entry_t))) == NULL)
+ return (-1);
+
+ if ((ne->ne_name = zfs_strdup(hdl, path)) == NULL) {
+ free(ne);
+ return (-1);
+ }
+
+ ne->ne_guid = vdev_guid;
+ ne->ne_next = pl->names;
+ pl->names = ne;
+
+ return (0);
+ }
+
+ /*
+ * If we have a valid config but cannot read any of these fields, then
+ * it means we have a half-initialized label. In vdev_label_init()
+ * we write a label with txg == 0 so that we can identify the device
+ * in case the user refers to the same disk later on. If we fail to
+ * create the pool, we'll be left with a label in this state
+ * which should not be considered part of a valid pool.
+ */
+ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+ &pool_guid) != 0 ||
+ nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,
+ &vdev_guid) != 0 ||
+ nvlist_lookup_uint64(config, ZPOOL_CONFIG_TOP_GUID,
+ &top_guid) != 0 ||
+ nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG,
+ &txg) != 0 || txg == 0) {
+ return (0);
+ }
+
+ /*
+ * First, see if we know about this pool. If not, then add it to the
+ * list of known pools.
+ */
+ for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
+ if (pe->pe_guid == pool_guid)
+ break;
+ }
+
+ if (pe == NULL) {
+ if ((pe = zfs_alloc(hdl, sizeof (pool_entry_t))) == NULL) {
+ return (-1);
+ }
+ pe->pe_guid = pool_guid;
+ pe->pe_next = pl->pools;
+ pl->pools = pe;
+ }
+
+ /*
+ * Second, see if we know about this toplevel vdev. Add it if its
+ * missing.
+ */
+ for (ve = pe->pe_vdevs; ve != NULL; ve = ve->ve_next) {
+ if (ve->ve_guid == top_guid)
+ break;
+ }
+
+ if (ve == NULL) {
+ if ((ve = zfs_alloc(hdl, sizeof (vdev_entry_t))) == NULL) {
+ return (-1);
+ }
+ ve->ve_guid = top_guid;
+ ve->ve_next = pe->pe_vdevs;
+ pe->pe_vdevs = ve;
+ }
+
+ /*
+ * Third, see if we have a config with a matching transaction group. If
+ * so, then we do nothing. Otherwise, add it to the list of known
+ * configs.
+ */
+ for (ce = ve->ve_configs; ce != NULL; ce = ce->ce_next) {
+ if (ce->ce_txg == txg)
+ break;
+ }
+
+ if (ce == NULL) {
+ if ((ce = zfs_alloc(hdl, sizeof (config_entry_t))) == NULL) {
+ return (-1);
+ }
+ ce->ce_txg = txg;
+ ce->ce_config = fnvlist_dup(config);
+ ce->ce_next = ve->ve_configs;
+ ve->ve_configs = ce;
+ }
+
+ /*
+ * At this point we've successfully added our config to the list of
+ * known configs. The last thing to do is add the vdev guid -> path
+ * mappings so that we can fix up the configuration as necessary before
+ * doing the import.
+ */
+ if ((ne = zfs_alloc(hdl, sizeof (name_entry_t))) == NULL)
+ return (-1);
+
+ if ((ne->ne_name = zfs_strdup(hdl, path)) == NULL) {
+ free(ne);
+ return (-1);
+ }
+
+ ne->ne_guid = vdev_guid;
+ ne->ne_next = pl->names;
+ pl->names = ne;
+
+ return (0);
+}
+
+/*
+ * Returns true if the named pool matches the given GUID.
+ */
+static int
+pool_active(libzfs_handle_t *hdl, const char *name, uint64_t guid,
+ boolean_t *isactive)
+{
+ zpool_handle_t *zhp;
+ uint64_t theguid;
+
+ if (zpool_open_silent(hdl, name, &zhp) != 0)
+ return (-1);
+
+ if (zhp == NULL) {
+ *isactive = B_FALSE;
+ return (0);
+ }
+
+ verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID,
+ &theguid) == 0);
+
+ zpool_close(zhp);
+
+ *isactive = (theguid == guid);
+ return (0);
+}
+
+static nvlist_t *
+refresh_config(libzfs_handle_t *hdl, nvlist_t *config)
+{
+ nvlist_t *nvl;
+ zfs_cmd_t zc = { 0 };
+ int err, dstbuf_size;
+
+ if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0)
+ return (NULL);
+
+ dstbuf_size = MAX(CONFIG_BUF_MINSIZE, zc.zc_nvlist_conf_size * 4);
+
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, dstbuf_size) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (NULL);
+ }
+
+ while ((err = ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_TRYIMPORT,
+ &zc)) != 0 && errno == ENOMEM) {
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (NULL);
+ }
+ }
+
+ if (err) {
+ zcmd_free_nvlists(&zc);
+ return (NULL);
+ }
+
+ if (zcmd_read_dst_nvlist(hdl, &zc, &nvl) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (NULL);
+ }
+
+ zcmd_free_nvlists(&zc);
+ return (nvl);
+}
+
+/*
+ * Determine if the vdev id is a hole in the namespace.
+ */
+boolean_t
+vdev_is_hole(uint64_t *hole_array, uint_t holes, uint_t id)
+{
+ for (int c = 0; c < holes; c++) {
+
+ /* Top-level is a hole */
+ if (hole_array[c] == id)
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Convert our list of pools into the definitive set of configurations. We
+ * start by picking the best config for each toplevel vdev. Once that's done,
+ * we assemble the toplevel vdevs into a full config for the pool. We make a
+ * pass to fix up any incorrect paths, and then add it to the main list to
+ * return to the user.
+ */
+static nvlist_t *
+get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok,
+ nvlist_t *policy)
+{
+ pool_entry_t *pe;
+ vdev_entry_t *ve;
+ config_entry_t *ce;
+ nvlist_t *ret = NULL, *config = NULL, *tmp = NULL, *nvtop, *nvroot;
+ nvlist_t **spares, **l2cache;
+ uint_t i, nspares, nl2cache;
+ boolean_t config_seen;
+ uint64_t best_txg;
+ char *name, *hostname = NULL;
+ uint64_t guid;
+ uint_t children = 0;
+ nvlist_t **child = NULL;
+ uint_t holes;
+ uint64_t *hole_array, max_id;
+ uint_t c;
+ boolean_t isactive;
+ uint64_t hostid;
+ nvlist_t *nvl;
+ boolean_t found_one = B_FALSE;
+ boolean_t valid_top_config = B_FALSE;
+
+ if (nvlist_alloc(&ret, 0, 0) != 0)
+ goto nomem;
+
+ for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
+ uint64_t id, max_txg = 0;
+
+ if (nvlist_alloc(&config, NV_UNIQUE_NAME, 0) != 0)
+ goto nomem;
+ config_seen = B_FALSE;
+
+ /*
+ * Iterate over all toplevel vdevs. Grab the pool configuration
+ * from the first one we find, and then go through the rest and
+ * add them as necessary to the 'vdevs' member of the config.
+ */
+ for (ve = pe->pe_vdevs; ve != NULL; ve = ve->ve_next) {
+
+ /*
+ * Determine the best configuration for this vdev by
+ * selecting the config with the latest transaction
+ * group.
+ */
+ best_txg = 0;
+ for (ce = ve->ve_configs; ce != NULL;
+ ce = ce->ce_next) {
+
+ if (ce->ce_txg > best_txg) {
+ tmp = ce->ce_config;
+ best_txg = ce->ce_txg;
+ }
+ }
+
+ /*
+ * We rely on the fact that the max txg for the
+ * pool will contain the most up-to-date information
+ * about the valid top-levels in the vdev namespace.
+ */
+ if (best_txg > max_txg) {
+ (void) nvlist_remove(config,
+ ZPOOL_CONFIG_VDEV_CHILDREN,
+ DATA_TYPE_UINT64);
+ (void) nvlist_remove(config,
+ ZPOOL_CONFIG_HOLE_ARRAY,
+ DATA_TYPE_UINT64_ARRAY);
+
+ max_txg = best_txg;
+ hole_array = NULL;
+ holes = 0;
+ max_id = 0;
+ valid_top_config = B_FALSE;
+
+ if (nvlist_lookup_uint64(tmp,
+ ZPOOL_CONFIG_VDEV_CHILDREN, &max_id) == 0) {
+ verify(nvlist_add_uint64(config,
+ ZPOOL_CONFIG_VDEV_CHILDREN,
+ max_id) == 0);
+ valid_top_config = B_TRUE;
+ }
+
+ if (nvlist_lookup_uint64_array(tmp,
+ ZPOOL_CONFIG_HOLE_ARRAY, &hole_array,
+ &holes) == 0) {
+ verify(nvlist_add_uint64_array(config,
+ ZPOOL_CONFIG_HOLE_ARRAY,
+ hole_array, holes) == 0);
+ }
+ }
+
+ if (!config_seen) {
+ /*
+ * Copy the relevant pieces of data to the pool
+ * configuration:
+ *
+ * version
+ * pool guid
+ * name
+ * comment (if available)
+ * pool state
+ * hostid (if available)
+ * hostname (if available)
+ */
+ uint64_t state, version;
+ char *comment = NULL;
+
+ version = fnvlist_lookup_uint64(tmp,
+ ZPOOL_CONFIG_VERSION);
+ fnvlist_add_uint64(config,
+ ZPOOL_CONFIG_VERSION, version);
+ guid = fnvlist_lookup_uint64(tmp,
+ ZPOOL_CONFIG_POOL_GUID);
+ fnvlist_add_uint64(config,
+ ZPOOL_CONFIG_POOL_GUID, guid);
+ name = fnvlist_lookup_string(tmp,
+ ZPOOL_CONFIG_POOL_NAME);
+ fnvlist_add_string(config,
+ ZPOOL_CONFIG_POOL_NAME, name);
+
+ if (nvlist_lookup_string(tmp,
+ ZPOOL_CONFIG_COMMENT, &comment) == 0)
+ fnvlist_add_string(config,
+ ZPOOL_CONFIG_COMMENT, comment);
+
+ state = fnvlist_lookup_uint64(tmp,
+ ZPOOL_CONFIG_POOL_STATE);
+ fnvlist_add_uint64(config,
+ ZPOOL_CONFIG_POOL_STATE, state);
+
+ hostid = 0;
+ if (nvlist_lookup_uint64(tmp,
+ ZPOOL_CONFIG_HOSTID, &hostid) == 0) {
+ fnvlist_add_uint64(config,
+ ZPOOL_CONFIG_HOSTID, hostid);
+ hostname = fnvlist_lookup_string(tmp,
+ ZPOOL_CONFIG_HOSTNAME);
+ fnvlist_add_string(config,
+ ZPOOL_CONFIG_HOSTNAME, hostname);
+ }
+
+ config_seen = B_TRUE;
+ }
+
+ /*
+ * Add this top-level vdev to the child array.
+ */
+ verify(nvlist_lookup_nvlist(tmp,
+ ZPOOL_CONFIG_VDEV_TREE, &nvtop) == 0);
+ verify(nvlist_lookup_uint64(nvtop, ZPOOL_CONFIG_ID,
+ &id) == 0);
+
+ if (id >= children) {
+ nvlist_t **newchild;
+
+ newchild = zfs_alloc(hdl, (id + 1) *
+ sizeof (nvlist_t *));
+ if (newchild == NULL)
+ goto nomem;
+
+ for (c = 0; c < children; c++)
+ newchild[c] = child[c];
+
+ free(child);
+ child = newchild;
+ children = id + 1;
+ }
+ if (nvlist_dup(nvtop, &child[id], 0) != 0)
+ goto nomem;
+
+ }
+
+ /*
+ * If we have information about all the top-levels then
+ * clean up the nvlist which we've constructed. This
+ * means removing any extraneous devices that are
+ * beyond the valid range or adding devices to the end
+ * of our array which appear to be missing.
+ */
+ if (valid_top_config) {
+ if (max_id < children) {
+ for (c = max_id; c < children; c++)
+ nvlist_free(child[c]);
+ children = max_id;
+ } else if (max_id > children) {
+ nvlist_t **newchild;
+
+ newchild = zfs_alloc(hdl, (max_id) *
+ sizeof (nvlist_t *));
+ if (newchild == NULL)
+ goto nomem;
+
+ for (c = 0; c < children; c++)
+ newchild[c] = child[c];
+
+ free(child);
+ child = newchild;
+ children = max_id;
+ }
+ }
+
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+ &guid) == 0);
+
+ /*
+ * The vdev namespace may contain holes as a result of
+ * device removal. We must add them back into the vdev
+ * tree before we process any missing devices.
+ */
+ if (holes > 0) {
+ ASSERT(valid_top_config);
+
+ for (c = 0; c < children; c++) {
+ nvlist_t *holey;
+
+ if (child[c] != NULL ||
+ !vdev_is_hole(hole_array, holes, c))
+ continue;
+
+ if (nvlist_alloc(&holey, NV_UNIQUE_NAME,
+ 0) != 0)
+ goto nomem;
+
+ /*
+ * Holes in the namespace are treated as
+ * "hole" top-level vdevs and have a
+ * special flag set on them.
+ */
+ if (nvlist_add_string(holey,
+ ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_HOLE) != 0 ||
+ nvlist_add_uint64(holey,
+ ZPOOL_CONFIG_ID, c) != 0 ||
+ nvlist_add_uint64(holey,
+ ZPOOL_CONFIG_GUID, 0ULL) != 0) {
+ nvlist_free(holey);
+ goto nomem;
+ }
+ child[c] = holey;
+ }
+ }
+
+ /*
+ * Look for any missing top-level vdevs. If this is the case,
+ * create a faked up 'missing' vdev as a placeholder. We cannot
+ * simply compress the child array, because the kernel performs
+ * certain checks to make sure the vdev IDs match their location
+ * in the configuration.
+ */
+ for (c = 0; c < children; c++) {
+ if (child[c] == NULL) {
+ nvlist_t *missing;
+ if (nvlist_alloc(&missing, NV_UNIQUE_NAME,
+ 0) != 0)
+ goto nomem;
+ if (nvlist_add_string(missing,
+ ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_MISSING) != 0 ||
+ nvlist_add_uint64(missing,
+ ZPOOL_CONFIG_ID, c) != 0 ||
+ nvlist_add_uint64(missing,
+ ZPOOL_CONFIG_GUID, 0ULL) != 0) {
+ nvlist_free(missing);
+ goto nomem;
+ }
+ child[c] = missing;
+ }
+ }
+
+ /*
+ * Put all of this pool's top-level vdevs into a root vdev.
+ */
+ if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0)
+ goto nomem;
+ if (nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_ROOT) != 0 ||
+ nvlist_add_uint64(nvroot, ZPOOL_CONFIG_ID, 0ULL) != 0 ||
+ nvlist_add_uint64(nvroot, ZPOOL_CONFIG_GUID, guid) != 0 ||
+ nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ child, children) != 0) {
+ nvlist_free(nvroot);
+ goto nomem;
+ }
+
+ for (c = 0; c < children; c++)
+ nvlist_free(child[c]);
+ free(child);
+ children = 0;
+ child = NULL;
+
+ /*
+ * Go through and fix up any paths and/or devids based on our
+ * known list of vdev GUID -> path mappings.
+ */
+ if (fix_paths(nvroot, pl->names) != 0) {
+ nvlist_free(nvroot);
+ goto nomem;
+ }
+
+ /*
+ * Add the root vdev to this pool's configuration.
+ */
+ if (nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ nvroot) != 0) {
+ nvlist_free(nvroot);
+ goto nomem;
+ }
+ nvlist_free(nvroot);
+
+ /*
+ * zdb uses this path to report on active pools that were
+ * imported or created using -R.
+ */
+ if (active_ok)
+ goto add_pool;
+
+ /*
+ * Determine if this pool is currently active, in which case we
+ * can't actually import it.
+ */
+ verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+ &name) == 0);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+ &guid) == 0);
+
+ if (pool_active(hdl, name, guid, &isactive) != 0)
+ goto error;
+
+ if (isactive) {
+ nvlist_free(config);
+ config = NULL;
+ continue;
+ }
+
+ if (policy != NULL) {
+ if (nvlist_add_nvlist(config, ZPOOL_LOAD_POLICY,
+ policy) != 0)
+ goto nomem;
+ }
+
+ if ((nvl = refresh_config(hdl, config)) == NULL) {
+ nvlist_free(config);
+ config = NULL;
+ continue;
+ }
+
+ nvlist_free(config);
+ config = nvl;
+
+ /*
+ * Go through and update the paths for spares, now that we have
+ * them.
+ */
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0) {
+ for (i = 0; i < nspares; i++) {
+ if (fix_paths(spares[i], pl->names) != 0)
+ goto nomem;
+ }
+ }
+
+ /*
+ * Update the paths for l2cache devices.
+ */
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+ &l2cache, &nl2cache) == 0) {
+ for (i = 0; i < nl2cache; i++) {
+ if (fix_paths(l2cache[i], pl->names) != 0)
+ goto nomem;
+ }
+ }
+
+ /*
+ * Restore the original information read from the actual label.
+ */
+ (void) nvlist_remove(config, ZPOOL_CONFIG_HOSTID,
+ DATA_TYPE_UINT64);
+ (void) nvlist_remove(config, ZPOOL_CONFIG_HOSTNAME,
+ DATA_TYPE_STRING);
+ if (hostid != 0) {
+ verify(nvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID,
+ hostid) == 0);
+ verify(nvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME,
+ hostname) == 0);
+ }
+
+add_pool:
+ /*
+ * Add this pool to the list of configs.
+ */
+ verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+ &name) == 0);
+ if (nvlist_add_nvlist(ret, name, config) != 0)
+ goto nomem;
+
+ found_one = B_TRUE;
+ nvlist_free(config);
+ config = NULL;
+ }
+
+ if (!found_one) {
+ nvlist_free(ret);
+ ret = NULL;
+ }
+
+ return (ret);
+
+nomem:
+ (void) no_memory(hdl);
+error:
+ nvlist_free(config);
+ nvlist_free(ret);
+ for (c = 0; c < children; c++)
+ nvlist_free(child[c]);
+ free(child);
+
+ return (NULL);
+}
+
+/*
+ * Return the offset of the given label.
+ */
+static uint64_t
+label_offset(uint64_t size, int l)
+{
+ ASSERT(P2PHASE_TYPED(size, sizeof (vdev_label_t), uint64_t) == 0);
+ return (l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ?
+ 0 : size - VDEV_LABELS * sizeof (vdev_label_t)));
+}
+
+/*
+ * Given a file descriptor, read the label information and return an nvlist
+ * describing the configuration, if there is one.
+ * Return 0 on success, or -1 on failure
+ */
+int
+zpool_read_label(int fd, nvlist_t **config)
+{
+ struct stat64 statbuf;
+ int l;
+ vdev_label_t *label;
+ uint64_t state, txg, size;
+
+ *config = NULL;
+
+ if (fstat64(fd, &statbuf) == -1)
+ return (-1);
+ size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
+
+ if ((label = malloc(sizeof (vdev_label_t))) == NULL)
+ return (-1);
+
+ for (l = 0; l < VDEV_LABELS; l++) {
+ if (pread64(fd, label, sizeof (vdev_label_t),
+ label_offset(size, l)) != sizeof (vdev_label_t))
+ continue;
+
+ if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist,
+ sizeof (label->vl_vdev_phys.vp_nvlist), config, 0) != 0)
+ continue;
+
+ if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_STATE,
+ &state) != 0 || state > POOL_STATE_L2CACHE) {
+ nvlist_free(*config);
+ continue;
+ }
+
+ if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE &&
+ (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_TXG,
+ &txg) != 0 || txg == 0)) {
+ nvlist_free(*config);
+ continue;
+ }
+
+ free(label);
+ return (0);
+ }
+
+ free(label);
+ *config = NULL;
+ errno = ENOENT;
+ return (-1);
+}
+
+/*
+ * Given a file descriptor, read the label information and return an nvlist
+ * describing the configuration, if there is one.
+ * returns the number of valid labels found
+ * If a label is found, returns it via config. The caller is responsible for
+ * freeing it.
+ */
+int
+zpool_read_all_labels(int fd, nvlist_t **config)
+{
+ struct stat64 statbuf;
+ struct aiocb aiocbs[VDEV_LABELS];
+ struct aiocb *aiocbps[VDEV_LABELS];
+ int l;
+ vdev_phys_t *labels;
+ uint64_t state, txg, size;
+ int nlabels = 0;
+
+ *config = NULL;
+
+ if (fstat64(fd, &statbuf) == -1)
+ return (0);
+ size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
+
+ if ((labels = calloc(VDEV_LABELS, sizeof (vdev_phys_t))) == NULL)
+ return (0);
+
+ memset(aiocbs, 0, sizeof(aiocbs));
+ for (l = 0; l < VDEV_LABELS; l++) {
+ aiocbs[l].aio_fildes = fd;
+ aiocbs[l].aio_offset = label_offset(size, l) + VDEV_SKIP_SIZE;
+ aiocbs[l].aio_buf = &labels[l];
+ aiocbs[l].aio_nbytes = sizeof(vdev_phys_t);
+ aiocbs[l].aio_lio_opcode = LIO_READ;
+ aiocbps[l] = &aiocbs[l];
+ }
+
+ if (lio_listio(LIO_WAIT, aiocbps, VDEV_LABELS, NULL) != 0) {
+ if (errno == EAGAIN || errno == EINTR || errno == EIO) {
+ for (l = 0; l < VDEV_LABELS; l++) {
+ errno = 0;
+ int r = aio_error(&aiocbs[l]);
+ if (r != EINVAL)
+ (void)aio_return(&aiocbs[l]);
+ }
+ }
+ free(labels);
+ return (0);
+ }
+
+ for (l = 0; l < VDEV_LABELS; l++) {
+ nvlist_t *temp = NULL;
+
+ if (aio_return(&aiocbs[l]) != sizeof(vdev_phys_t))
+ continue;
+
+ if (nvlist_unpack(labels[l].vp_nvlist,
+ sizeof (labels[l].vp_nvlist), &temp, 0) != 0)
+ continue;
+
+ if (nvlist_lookup_uint64(temp, ZPOOL_CONFIG_POOL_STATE,
+ &state) != 0 || state > POOL_STATE_L2CACHE) {
+ nvlist_free(temp);
+ temp = NULL;
+ continue;
+ }
+
+ if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE &&
+ (nvlist_lookup_uint64(temp, ZPOOL_CONFIG_POOL_TXG,
+ &txg) != 0 || txg == 0)) {
+ nvlist_free(temp);
+ temp = NULL;
+ continue;
+ }
+ if (temp)
+ *config = temp;
+
+ nlabels++;
+ }
+
+ free(labels);
+ return (nlabels);
+}
+
+typedef struct rdsk_node {
+ char *rn_name;
+ int rn_dfd;
+ libzfs_handle_t *rn_hdl;
+ nvlist_t *rn_config;
+ avl_tree_t *rn_avl;
+ avl_node_t rn_node;
+ boolean_t rn_nozpool;
+} rdsk_node_t;
+
+static int
+slice_cache_compare(const void *arg1, const void *arg2)
+{
+ const char *nm1 = ((rdsk_node_t *)arg1)->rn_name;
+ const char *nm2 = ((rdsk_node_t *)arg2)->rn_name;
+ char *nm1slice, *nm2slice;
+ int rv;
+
+ /*
+ * slices zero and two are the most likely to provide results,
+ * so put those first
+ */
+ nm1slice = strstr(nm1, "s0");
+ nm2slice = strstr(nm2, "s0");
+ if (nm1slice && !nm2slice) {
+ return (-1);
+ }
+ if (!nm1slice && nm2slice) {
+ return (1);
+ }
+ nm1slice = strstr(nm1, "s2");
+ nm2slice = strstr(nm2, "s2");
+ if (nm1slice && !nm2slice) {
+ return (-1);
+ }
+ if (!nm1slice && nm2slice) {
+ return (1);
+ }
+
+ rv = strcmp(nm1, nm2);
+ if (rv == 0)
+ return (0);
+ return (rv > 0 ? 1 : -1);
+}
+
+#ifdef illumos
+static void
+check_one_slice(avl_tree_t *r, char *diskname, uint_t partno,
+ diskaddr_t size, uint_t blksz)
+{
+ rdsk_node_t tmpnode;
+ rdsk_node_t *node;
+ char sname[MAXNAMELEN];
+
+ tmpnode.rn_name = &sname[0];
+ (void) snprintf(tmpnode.rn_name, MAXNAMELEN, "%s%u",
+ diskname, partno);
+ /*
+ * protect against division by zero for disk labels that
+ * contain a bogus sector size
+ */
+ if (blksz == 0)
+ blksz = DEV_BSIZE;
+ /* too small to contain a zpool? */
+ if ((size < (SPA_MINDEVSIZE / blksz)) &&
+ (node = avl_find(r, &tmpnode, NULL)))
+ node->rn_nozpool = B_TRUE;
+}
+#endif /* illumos */
+
+static void
+nozpool_all_slices(avl_tree_t *r, const char *sname)
+{
+#ifdef illumos
+ char diskname[MAXNAMELEN];
+ char *ptr;
+ int i;
+
+ (void) strncpy(diskname, sname, MAXNAMELEN);
+ if (((ptr = strrchr(diskname, 's')) == NULL) &&
+ ((ptr = strrchr(diskname, 'p')) == NULL))
+ return;
+ ptr[0] = 's';
+ ptr[1] = '\0';
+ for (i = 0; i < NDKMAP; i++)
+ check_one_slice(r, diskname, i, 0, 1);
+ ptr[0] = 'p';
+ for (i = 0; i <= FD_NUMPART; i++)
+ check_one_slice(r, diskname, i, 0, 1);
+#endif /* illumos */
+}
+
+#ifdef illumos
+static void
+check_slices(avl_tree_t *r, int fd, const char *sname)
+{
+ struct extvtoc vtoc;
+ struct dk_gpt *gpt;
+ char diskname[MAXNAMELEN];
+ char *ptr;
+ int i;
+
+ (void) strncpy(diskname, sname, MAXNAMELEN);
+ if ((ptr = strrchr(diskname, 's')) == NULL || !isdigit(ptr[1]))
+ return;
+ ptr[1] = '\0';
+
+ if (read_extvtoc(fd, &vtoc) >= 0) {
+ for (i = 0; i < NDKMAP; i++)
+ check_one_slice(r, diskname, i,
+ vtoc.v_part[i].p_size, vtoc.v_sectorsz);
+ } else if (efi_alloc_and_read(fd, &gpt) >= 0) {
+ /*
+ * on x86 we'll still have leftover links that point
+ * to slices s[9-15], so use NDKMAP instead
+ */
+ for (i = 0; i < NDKMAP; i++)
+ check_one_slice(r, diskname, i,
+ gpt->efi_parts[i].p_size, gpt->efi_lbasize);
+ /* nodes p[1-4] are never used with EFI labels */
+ ptr[0] = 'p';
+ for (i = 1; i <= FD_NUMPART; i++)
+ check_one_slice(r, diskname, i, 0, 1);
+ efi_free(gpt);
+ }
+}
+#endif /* illumos */
+
+static void
+zpool_open_func(void *arg)
+{
+ rdsk_node_t *rn = arg;
+ struct stat64 statbuf;
+ nvlist_t *config;
+ int fd;
+
+ if (rn->rn_nozpool)
+ return;
+ if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) {
+ /* symlink to a device that's no longer there */
+ if (errno == ENOENT)
+ nozpool_all_slices(rn->rn_avl, rn->rn_name);
+ return;
+ }
+ /*
+ * Ignore failed stats. We only want regular
+ * files, character devs and block devs.
+ */
+ if (fstat64(fd, &statbuf) != 0 ||
+ (!S_ISREG(statbuf.st_mode) &&
+ !S_ISCHR(statbuf.st_mode) &&
+ !S_ISBLK(statbuf.st_mode))) {
+ (void) close(fd);
+ return;
+ }
+ /* this file is too small to hold a zpool */
+#ifdef illumos
+ if (S_ISREG(statbuf.st_mode) &&
+ statbuf.st_size < SPA_MINDEVSIZE) {
+ (void) close(fd);
+ return;
+ } else if (!S_ISREG(statbuf.st_mode)) {
+ /*
+ * Try to read the disk label first so we don't have to
+ * open a bunch of minor nodes that can't have a zpool.
+ */
+ check_slices(rn->rn_avl, fd, rn->rn_name);
+ }
+#else /* !illumos */
+ if (statbuf.st_size < SPA_MINDEVSIZE) {
+ (void) close(fd);
+ return;
+ }
+#endif /* illumos */
+
+ if ((zpool_read_label(fd, &config)) != 0 && errno == ENOMEM) {
+ (void) close(fd);
+ (void) no_memory(rn->rn_hdl);
+ return;
+ }
+ (void) close(fd);
+
+ rn->rn_config = config;
+}
+
+/*
+ * Given a file descriptor, clear (zero) the label information.
+ */
+int
+zpool_clear_label(int fd)
+{
+ struct stat64 statbuf;
+ int l;
+ vdev_label_t *label;
+ uint64_t size;
+
+ if (fstat64(fd, &statbuf) == -1)
+ return (0);
+ size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
+
+ if ((label = calloc(sizeof (vdev_label_t), 1)) == NULL)
+ return (-1);
+
+ for (l = 0; l < VDEV_LABELS; l++) {
+ if (pwrite64(fd, label, sizeof (vdev_label_t),
+ label_offset(size, l)) != sizeof (vdev_label_t)) {
+ free(label);
+ return (-1);
+ }
+ }
+
+ free(label);
+ return (0);
+}
+
+/*
+ * Given a list of directories to search, find all pools stored on disk. This
+ * includes partial pools which are not available to import. If no args are
+ * given (argc is 0), then the default directory (/dev/dsk) is searched.
+ * poolname or guid (but not both) are provided by the caller when trying
+ * to import a specific pool.
+ */
+static nvlist_t *
+zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
+{
+ int i, dirs = iarg->paths;
+ struct dirent64 *dp;
+ char path[MAXPATHLEN];
+ char *end, **dir = iarg->path;
+ size_t pathleft;
+ nvlist_t *ret = NULL;
+ static char *default_dir = "/dev";
+ pool_list_t pools = { 0 };
+ pool_entry_t *pe, *penext;
+ vdev_entry_t *ve, *venext;
+ config_entry_t *ce, *cenext;
+ name_entry_t *ne, *nenext;
+ avl_tree_t slice_cache;
+ rdsk_node_t *slice;
+ void *cookie;
+
+ if (dirs == 0) {
+ dirs = 1;
+ dir = &default_dir;
+ }
+
+ /*
+ * Go through and read the label configuration information from every
+ * possible device, organizing the information according to pool GUID
+ * and toplevel GUID.
+ */
+ for (i = 0; i < dirs; i++) {
+ tpool_t *t;
+ char rdsk[MAXPATHLEN];
+ int dfd;
+ boolean_t config_failed = B_FALSE;
+ DIR *dirp;
+
+ /* use realpath to normalize the path */
+ if (realpath(dir[i], path) == 0) {
+ (void) zfs_error_fmt(hdl, EZFS_BADPATH,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"), dir[i]);
+ goto error;
+ }
+ end = &path[strlen(path)];
+ *end++ = '/';
+ *end = 0;
+ pathleft = &path[sizeof (path)] - end;
+
+#ifdef illumos
+ /*
+ * Using raw devices instead of block devices when we're
+ * reading the labels skips a bunch of slow operations during
+ * close(2) processing, so we replace /dev/dsk with /dev/rdsk.
+ */
+ if (strcmp(path, ZFS_DISK_ROOTD) == 0)
+ (void) strlcpy(rdsk, ZFS_RDISK_ROOTD, sizeof (rdsk));
+ else
+#endif
+ (void) strlcpy(rdsk, path, sizeof (rdsk));
+
+ if ((dfd = open64(rdsk, O_RDONLY)) < 0 ||
+ (dirp = fdopendir(dfd)) == NULL) {
+ if (dfd >= 0)
+ (void) close(dfd);
+ zfs_error_aux(hdl, strerror(errno));
+ (void) zfs_error_fmt(hdl, EZFS_BADPATH,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"),
+ rdsk);
+ goto error;
+ }
+
+ avl_create(&slice_cache, slice_cache_compare,
+ sizeof (rdsk_node_t), offsetof(rdsk_node_t, rn_node));
+
+ if (strcmp(rdsk, "/dev/") == 0) {
+ struct gmesh mesh;
+ struct gclass *mp;
+ struct ggeom *gp;
+ struct gprovider *pp;
+
+ errno = geom_gettree(&mesh);
+ if (errno != 0) {
+ zfs_error_aux(hdl, strerror(errno));
+ (void) zfs_error_fmt(hdl, EZFS_BADPATH,
+ dgettext(TEXT_DOMAIN, "cannot get GEOM tree"));
+ goto error;
+ }
+
+ LIST_FOREACH(mp, &mesh.lg_class, lg_class) {
+ LIST_FOREACH(gp, &mp->lg_geom, lg_geom) {
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
+ slice->rn_name = zfs_strdup(hdl, pp->lg_name);
+ slice->rn_avl = &slice_cache;
+ slice->rn_dfd = dfd;
+ slice->rn_hdl = hdl;
+ slice->rn_nozpool = B_FALSE;
+ avl_add(&slice_cache, slice);
+ }
+ }
+ }
+
+ geom_deletetree(&mesh);
+ goto skipdir;
+ }
+
+ /*
+ * This is not MT-safe, but we have no MT consumers of libzfs
+ */
+ while ((dp = readdir64(dirp)) != NULL) {
+ const char *name = dp->d_name;
+ if (name[0] == '.' &&
+ (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
+ continue;
+
+ slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
+ slice->rn_name = zfs_strdup(hdl, name);
+ slice->rn_avl = &slice_cache;
+ slice->rn_dfd = dfd;
+ slice->rn_hdl = hdl;
+ slice->rn_nozpool = B_FALSE;
+ avl_add(&slice_cache, slice);
+ }
+skipdir:
+ /*
+ * create a thread pool to do all of this in parallel;
+ * rn_nozpool is not protected, so this is racy in that
+ * multiple tasks could decide that the same slice can
+ * not hold a zpool, which is benign. Also choose
+ * double the number of processors; we hold a lot of
+ * locks in the kernel, so going beyond this doesn't
+ * buy us much.
+ */
+ t = tpool_create(1, 2 * sysconf(_SC_NPROCESSORS_ONLN),
+ 0, NULL);
+ for (slice = avl_first(&slice_cache); slice;
+ (slice = avl_walk(&slice_cache, slice,
+ AVL_AFTER)))
+ (void) tpool_dispatch(t, zpool_open_func, slice);
+ tpool_wait(t);
+ tpool_destroy(t);
+
+ cookie = NULL;
+ while ((slice = avl_destroy_nodes(&slice_cache,
+ &cookie)) != NULL) {
+ if (slice->rn_config != NULL && !config_failed) {
+ nvlist_t *config = slice->rn_config;
+ boolean_t matched = B_TRUE;
+
+ if (iarg->poolname != NULL) {
+ char *pname;
+
+ matched = nvlist_lookup_string(config,
+ ZPOOL_CONFIG_POOL_NAME,
+ &pname) == 0 &&
+ strcmp(iarg->poolname, pname) == 0;
+ } else if (iarg->guid != 0) {
+ uint64_t this_guid;
+
+ matched = nvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_POOL_GUID,
+ &this_guid) == 0 &&
+ iarg->guid == this_guid;
+ }
+ if (matched) {
+ /*
+ * use the non-raw path for the config
+ */
+ (void) strlcpy(end, slice->rn_name,
+ pathleft);
+ if (add_config(hdl, &pools, path,
+ config) != 0)
+ config_failed = B_TRUE;
+ }
+ nvlist_free(config);
+ }
+ free(slice->rn_name);
+ free(slice);
+ }
+ avl_destroy(&slice_cache);
+
+ (void) closedir(dirp);
+
+ if (config_failed)
+ goto error;
+ }
+
+ ret = get_configs(hdl, &pools, iarg->can_be_active, iarg->policy);
+
+error:
+ for (pe = pools.pools; pe != NULL; pe = penext) {
+ penext = pe->pe_next;
+ for (ve = pe->pe_vdevs; ve != NULL; ve = venext) {
+ venext = ve->ve_next;
+ for (ce = ve->ve_configs; ce != NULL; ce = cenext) {
+ cenext = ce->ce_next;
+ nvlist_free(ce->ce_config);
+ free(ce);
+ }
+ free(ve);
+ }
+ free(pe);
+ }
+
+ for (ne = pools.names; ne != NULL; ne = nenext) {
+ nenext = ne->ne_next;
+ free(ne->ne_name);
+ free(ne);
+ }
+
+ return (ret);
+}
+
+nvlist_t *
+zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv)
+{
+ importargs_t iarg = { 0 };
+
+ iarg.paths = argc;
+ iarg.path = argv;
+
+ return (zpool_find_import_impl(hdl, &iarg));
+}
+
+/*
+ * Given a cache file, return the contents as a list of importable pools.
+ * poolname or guid (but not both) are provided by the caller when trying
+ * to import a specific pool.
+ */
+nvlist_t *
+zpool_find_import_cached(libzfs_handle_t *hdl, const char *cachefile,
+ char *poolname, uint64_t guid)
+{
+ char *buf;
+ int fd;
+ struct stat64 statbuf;
+ nvlist_t *raw, *src, *dst;
+ nvlist_t *pools;
+ nvpair_t *elem;
+ char *name;
+ uint64_t this_guid;
+ boolean_t active;
+
+ verify(poolname == NULL || guid == 0);
+
+ if ((fd = open(cachefile, O_RDONLY)) < 0) {
+ zfs_error_aux(hdl, "%s", strerror(errno));
+ (void) zfs_error(hdl, EZFS_BADCACHE,
+ dgettext(TEXT_DOMAIN, "failed to open cache file"));
+ return (NULL);
+ }
+
+ if (fstat64(fd, &statbuf) != 0) {
+ zfs_error_aux(hdl, "%s", strerror(errno));
+ (void) close(fd);
+ (void) zfs_error(hdl, EZFS_BADCACHE,
+ dgettext(TEXT_DOMAIN, "failed to get size of cache file"));
+ return (NULL);
+ }
+
+ if ((buf = zfs_alloc(hdl, statbuf.st_size)) == NULL) {
+ (void) close(fd);
+ return (NULL);
+ }
+
+ if (read(fd, buf, statbuf.st_size) != statbuf.st_size) {
+ (void) close(fd);
+ free(buf);
+ (void) zfs_error(hdl, EZFS_BADCACHE,
+ dgettext(TEXT_DOMAIN,
+ "failed to read cache file contents"));
+ return (NULL);
+ }
+
+ (void) close(fd);
+
+ if (nvlist_unpack(buf, statbuf.st_size, &raw, 0) != 0) {
+ free(buf);
+ (void) zfs_error(hdl, EZFS_BADCACHE,
+ dgettext(TEXT_DOMAIN,
+ "invalid or corrupt cache file contents"));
+ return (NULL);
+ }
+
+ free(buf);
+
+ /*
+ * Go through and get the current state of the pools and refresh their
+ * state.
+ */
+ if (nvlist_alloc(&pools, 0, 0) != 0) {
+ (void) no_memory(hdl);
+ nvlist_free(raw);
+ return (NULL);
+ }
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(raw, elem)) != NULL) {
+ src = fnvpair_value_nvlist(elem);
+
+ name = fnvlist_lookup_string(src, ZPOOL_CONFIG_POOL_NAME);
+ if (poolname != NULL && strcmp(poolname, name) != 0)
+ continue;
+
+ this_guid = fnvlist_lookup_uint64(src, ZPOOL_CONFIG_POOL_GUID);
+ if (guid != 0 && guid != this_guid)
+ continue;
+
+ if (pool_active(hdl, name, this_guid, &active) != 0) {
+ nvlist_free(raw);
+ nvlist_free(pools);
+ return (NULL);
+ }
+
+ if (active)
+ continue;
+
+ if (nvlist_add_string(src, ZPOOL_CONFIG_CACHEFILE,
+ cachefile) != 0) {
+ (void) no_memory(hdl);
+ nvlist_free(raw);
+ nvlist_free(pools);
+ return (NULL);
+ }
+
+ if ((dst = refresh_config(hdl, src)) == NULL) {
+ nvlist_free(raw);
+ nvlist_free(pools);
+ return (NULL);
+ }
+
+ if (nvlist_add_nvlist(pools, nvpair_name(elem), dst) != 0) {
+ (void) no_memory(hdl);
+ nvlist_free(dst);
+ nvlist_free(raw);
+ nvlist_free(pools);
+ return (NULL);
+ }
+ nvlist_free(dst);
+ }
+
+ nvlist_free(raw);
+ return (pools);
+}
+
+static int
+name_or_guid_exists(zpool_handle_t *zhp, void *data)
+{
+ importargs_t *import = data;
+ int found = 0;
+
+ if (import->poolname != NULL) {
+ char *pool_name;
+
+ verify(nvlist_lookup_string(zhp->zpool_config,
+ ZPOOL_CONFIG_POOL_NAME, &pool_name) == 0);
+ if (strcmp(pool_name, import->poolname) == 0)
+ found = 1;
+ } else {
+ uint64_t pool_guid;
+
+ verify(nvlist_lookup_uint64(zhp->zpool_config,
+ ZPOOL_CONFIG_POOL_GUID, &pool_guid) == 0);
+ if (pool_guid == import->guid)
+ found = 1;
+ }
+
+ zpool_close(zhp);
+ return (found);
+}
+
+nvlist_t *
+zpool_search_import(libzfs_handle_t *hdl, importargs_t *import)
+{
+ nvlist_t *pools = NULL;
+
+ verify(import->poolname == NULL || import->guid == 0);
+
+ if (import->unique)
+ import->exists = zpool_iter(hdl, name_or_guid_exists, import);
+
+ if (import->cachefile != NULL)
+ pools = zpool_find_import_cached(hdl, import->cachefile,
+ import->poolname, import->guid);
+ else
+ pools = zpool_find_import_impl(hdl, import);
+
+ return (pools);
+}
+
+static boolean_t
+pool_match(nvlist_t *cfg, char *tgt)
+{
+ uint64_t v, guid = strtoull(tgt, NULL, 0);
+ char *s;
+
+ if (guid != 0) {
+ if (nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_POOL_GUID, &v) == 0)
+ return (v == guid);
+ } else {
+ if (nvlist_lookup_string(cfg, ZPOOL_CONFIG_POOL_NAME, &s) == 0)
+ return (strcmp(s, tgt) == 0);
+ }
+ return (B_FALSE);
+}
+
+int
+zpool_tryimport(libzfs_handle_t *hdl, char *target, nvlist_t **configp,
+ importargs_t *args)
+{
+ nvlist_t *pools;
+ nvlist_t *match = NULL;
+ nvlist_t *config = NULL;
+ char *sepp = NULL;
+ int count = 0;
+ char *targetdup = strdup(target);
+
+ *configp = NULL;
+
+ if ((sepp = strpbrk(targetdup, "/@")) != NULL) {
+ *sepp = '\0';
+ }
+
+ pools = zpool_search_import(hdl, args);
+
+ if (pools != NULL) {
+ nvpair_t *elem = NULL;
+ while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
+ VERIFY0(nvpair_value_nvlist(elem, &config));
+ if (pool_match(config, targetdup)) {
+ count++;
+ if (match != NULL) {
+ /* multiple matches found */
+ continue;
+ } else {
+ match = config;
+ }
+ }
+ }
+ }
+
+ if (count == 0) {
+ free(targetdup);
+ return (ENOENT);
+ }
+
+ if (count > 1) {
+ free(targetdup);
+ return (EINVAL);
+ }
+
+ *configp = match;
+ free(targetdup);
+
+ return (0);
+}
+
+boolean_t
+find_guid(nvlist_t *nv, uint64_t guid)
+{
+ uint64_t tmp;
+ nvlist_t **child;
+ uint_t c, children;
+
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &tmp) == 0);
+ if (tmp == guid)
+ return (B_TRUE);
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++)
+ if (find_guid(child[c], guid))
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+typedef struct aux_cbdata {
+ const char *cb_type;
+ uint64_t cb_guid;
+ zpool_handle_t *cb_zhp;
+} aux_cbdata_t;
+
+static int
+find_aux(zpool_handle_t *zhp, void *data)
+{
+ aux_cbdata_t *cbp = data;
+ nvlist_t **list;
+ uint_t i, count;
+ uint64_t guid;
+ nvlist_t *nvroot;
+
+ verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+
+ if (nvlist_lookup_nvlist_array(nvroot, cbp->cb_type,
+ &list, &count) == 0) {
+ for (i = 0; i < count; i++) {
+ verify(nvlist_lookup_uint64(list[i],
+ ZPOOL_CONFIG_GUID, &guid) == 0);
+ if (guid == cbp->cb_guid) {
+ cbp->cb_zhp = zhp;
+ return (1);
+ }
+ }
+ }
+
+ zpool_close(zhp);
+ return (0);
+}
+
+/*
+ * Determines if the pool is in use. If so, it returns true and the state of
+ * the pool as well as the name of the pool. Both strings are allocated and
+ * must be freed by the caller.
+ */
+int
+zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr,
+ boolean_t *inuse)
+{
+ nvlist_t *config;
+ char *name;
+ boolean_t ret;
+ uint64_t guid, vdev_guid;
+ zpool_handle_t *zhp;
+ nvlist_t *pool_config;
+ uint64_t stateval, isspare;
+ aux_cbdata_t cb = { 0 };
+ boolean_t isactive;
+
+ *inuse = B_FALSE;
+
+ if (zpool_read_label(fd, &config) != 0 && errno == ENOMEM) {
+ (void) no_memory(hdl);
+ return (-1);
+ }
+
+ if (config == NULL)
+ return (0);
+
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+ &stateval) == 0);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,
+ &vdev_guid) == 0);
+
+ if (stateval != POOL_STATE_SPARE && stateval != POOL_STATE_L2CACHE) {
+ verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+ &name) == 0);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+ &guid) == 0);
+ }
+
+ switch (stateval) {
+ case POOL_STATE_EXPORTED:
+ /*
+ * A pool with an exported state may in fact be imported
+ * read-only, so check the in-core state to see if it's
+ * active and imported read-only. If it is, set
+ * its state to active.
+ */
+ if (pool_active(hdl, name, guid, &isactive) == 0 && isactive &&
+ (zhp = zpool_open_canfail(hdl, name)) != NULL) {
+ if (zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL))
+ stateval = POOL_STATE_ACTIVE;
+
+ /*
+ * All we needed the zpool handle for is the
+ * readonly prop check.
+ */
+ zpool_close(zhp);
+ }
+
+ ret = B_TRUE;
+ break;
+
+ case POOL_STATE_ACTIVE:
+ /*
+ * For an active pool, we have to determine if it's really part
+ * of a currently active pool (in which case the pool will exist
+ * and the guid will be the same), or whether it's part of an
+ * active pool that was disconnected without being explicitly
+ * exported.
+ */
+ if (pool_active(hdl, name, guid, &isactive) != 0) {
+ nvlist_free(config);
+ return (-1);
+ }
+
+ if (isactive) {
+ /*
+ * Because the device may have been removed while
+ * offlined, we only report it as active if the vdev is
+ * still present in the config. Otherwise, pretend like
+ * it's not in use.
+ */
+ if ((zhp = zpool_open_canfail(hdl, name)) != NULL &&
+ (pool_config = zpool_get_config(zhp, NULL))
+ != NULL) {
+ nvlist_t *nvroot;
+
+ verify(nvlist_lookup_nvlist(pool_config,
+ ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+ ret = find_guid(nvroot, vdev_guid);
+ } else {
+ ret = B_FALSE;
+ }
+
+ /*
+ * If this is an active spare within another pool, we
+ * treat it like an unused hot spare. This allows the
+ * user to create a pool with a hot spare that currently
+ * in use within another pool. Since we return B_TRUE,
+ * libdiskmgt will continue to prevent generic consumers
+ * from using the device.
+ */
+ if (ret && nvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_IS_SPARE, &isspare) == 0 && isspare)
+ stateval = POOL_STATE_SPARE;
+
+ if (zhp != NULL)
+ zpool_close(zhp);
+ } else {
+ stateval = POOL_STATE_POTENTIALLY_ACTIVE;
+ ret = B_TRUE;
+ }
+ break;
+
+ case POOL_STATE_SPARE:
+ /*
+ * For a hot spare, it can be either definitively in use, or
+ * potentially active. To determine if it's in use, we iterate
+ * over all pools in the system and search for one with a spare
+ * with a matching guid.
+ *
+ * Due to the shared nature of spares, we don't actually report
+ * the potentially active case as in use. This means the user
+ * can freely create pools on the hot spares of exported pools,
+ * but to do otherwise makes the resulting code complicated, and
+ * we end up having to deal with this case anyway.
+ */
+ cb.cb_zhp = NULL;
+ cb.cb_guid = vdev_guid;
+ cb.cb_type = ZPOOL_CONFIG_SPARES;
+ if (zpool_iter(hdl, find_aux, &cb) == 1) {
+ name = (char *)zpool_get_name(cb.cb_zhp);
+ ret = B_TRUE;
+ } else {
+ ret = B_FALSE;
+ }
+ break;
+
+ case POOL_STATE_L2CACHE:
+
+ /*
+ * Check if any pool is currently using this l2cache device.
+ */
+ cb.cb_zhp = NULL;
+ cb.cb_guid = vdev_guid;
+ cb.cb_type = ZPOOL_CONFIG_L2CACHE;
+ if (zpool_iter(hdl, find_aux, &cb) == 1) {
+ name = (char *)zpool_get_name(cb.cb_zhp);
+ ret = B_TRUE;
+ } else {
+ ret = B_FALSE;
+ }
+ break;
+
+ default:
+ ret = B_FALSE;
+ }
+
+
+ if (ret) {
+ if ((*namestr = zfs_strdup(hdl, name)) == NULL) {
+ if (cb.cb_zhp)
+ zpool_close(cb.cb_zhp);
+ nvlist_free(config);
+ return (-1);
+ }
+ *state = (pool_state_t)stateval;
+ }
+
+ if (cb.cb_zhp)
+ zpool_close(cb.cb_zhp);
+
+ nvlist_free(config);
+ *inuse = ret;
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
new file mode 100644
index 000000000000..36138676e7db
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
@@ -0,0 +1,546 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2019 Datto Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <libintl.h>
+#include <libzfs.h>
+
+#include "libzfs_impl.h"
+
+int
+zfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+ nvlist_t *nvl = zfs_get_clones_nvl(zhp);
+ nvpair_t *pair;
+
+ if (nvl == NULL)
+ return (0);
+
+ for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(nvl, pair)) {
+ zfs_handle_t *clone = zfs_open(zhp->zfs_hdl, nvpair_name(pair),
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (clone != NULL) {
+ int err = func(clone, data);
+ if (err != 0)
+ return (err);
+ }
+ }
+ return (0);
+}
+
+static int
+zfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc)
+{
+ int rc;
+ uint64_t orig_cookie;
+
+ orig_cookie = zc->zc_cookie;
+top:
+ (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
+ rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc);
+
+ if (rc == -1) {
+ switch (errno) {
+ case ENOMEM:
+ /* expand nvlist memory and try again */
+ if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) {
+ zcmd_free_nvlists(zc);
+ return (-1);
+ }
+ zc->zc_cookie = orig_cookie;
+ goto top;
+ /*
+ * An errno value of ESRCH indicates normal completion.
+ * If ENOENT is returned, then the underlying dataset
+ * has been removed since we obtained the handle.
+ */
+ case ESRCH:
+ case ENOENT:
+ rc = 1;
+ break;
+ default:
+ rc = zfs_standard_error(zhp->zfs_hdl, errno,
+ dgettext(TEXT_DOMAIN,
+ "cannot iterate filesystems"));
+ break;
+ }
+ }
+ return (rc);
+}
+
+/*
+ * Iterate over all child filesystems
+ */
+int
+zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+ zfs_cmd_t zc = { 0 };
+ zfs_handle_t *nzhp;
+ int ret;
+
+ if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
+ return (0);
+
+ if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+ return (-1);
+
+ while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
+ &zc)) == 0) {
+ /*
+ * Silently ignore errors, as the only plausible explanation is
+ * that the pool has since been removed.
+ */
+ if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
+ &zc)) == NULL) {
+ continue;
+ }
+
+ if ((ret = func(nzhp, data)) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (ret);
+ }
+ }
+ zcmd_free_nvlists(&zc);
+ return ((ret < 0) ? ret : 0);
+}
+
+/*
+ * Iterate over all snapshots
+ */
+int
+zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
+ void *data, uint64_t min_txg, uint64_t max_txg)
+{
+ zfs_cmd_t zc = { 0 };
+ zfs_handle_t *nzhp;
+ int ret;
+ nvlist_t *range_nvl = NULL;
+
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
+ zhp->zfs_type == ZFS_TYPE_BOOKMARK)
+ return (0);
+
+ zc.zc_simple = simple;
+
+ if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+ return (-1);
+
+ if (min_txg != 0) {
+ range_nvl = fnvlist_alloc();
+ fnvlist_add_uint64(range_nvl, SNAP_ITER_MIN_TXG, min_txg);
+ }
+ if (max_txg != 0) {
+ if (range_nvl == NULL)
+ range_nvl = fnvlist_alloc();
+ fnvlist_add_uint64(range_nvl, SNAP_ITER_MAX_TXG, max_txg);
+ }
+
+ if (range_nvl != NULL &&
+ zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, range_nvl) != 0) {
+ zcmd_free_nvlists(&zc);
+ fnvlist_free(range_nvl);
+ return (-1);
+ }
+
+ while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
+ &zc)) == 0) {
+
+ if (simple)
+ nzhp = make_dataset_simple_handle_zc(zhp, &zc);
+ else
+ nzhp = make_dataset_handle_zc(zhp->zfs_hdl, &zc);
+ if (nzhp == NULL)
+ continue;
+
+ if ((ret = func(nzhp, data)) != 0) {
+ zcmd_free_nvlists(&zc);
+ fnvlist_free(range_nvl);
+ return (ret);
+ }
+ }
+ zcmd_free_nvlists(&zc);
+ fnvlist_free(range_nvl);
+ return ((ret < 0) ? ret : 0);
+}
+
+/*
+ * Iterate over all bookmarks
+ */
+int
+zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+ zfs_handle_t *nzhp;
+ nvlist_t *props = NULL;
+ nvlist_t *bmarks = NULL;
+ int err;
+
+ if ((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) != 0)
+ return (0);
+
+ /* Setup the requested properties nvlist. */
+ props = fnvlist_alloc();
+ fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_GUID));
+ fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATETXG));
+ fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATION));
+
+ if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0)
+ goto out;
+
+ for (nvpair_t *pair = nvlist_next_nvpair(bmarks, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) {
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ char *bmark_name;
+ nvlist_t *bmark_props;
+
+ bmark_name = nvpair_name(pair);
+ bmark_props = fnvpair_value_nvlist(pair);
+
+ (void) snprintf(name, sizeof (name), "%s#%s", zhp->zfs_name,
+ bmark_name);
+
+ nzhp = make_bookmark_handle(zhp, name, bmark_props);
+ if (nzhp == NULL)
+ continue;
+
+ if ((err = func(nzhp, data)) != 0)
+ goto out;
+ }
+
+out:
+ fnvlist_free(props);
+ fnvlist_free(bmarks);
+
+ return (err);
+}
+
+/*
+ * Routines for dealing with the sorted snapshot functionality
+ */
+typedef struct zfs_node {
+ zfs_handle_t *zn_handle;
+ avl_node_t zn_avlnode;
+} zfs_node_t;
+
+static int
+zfs_sort_snaps(zfs_handle_t *zhp, void *data)
+{
+ avl_tree_t *avl = data;
+ zfs_node_t *node;
+ zfs_node_t search;
+
+ search.zn_handle = zhp;
+ node = avl_find(avl, &search, NULL);
+ if (node) {
+ /*
+ * If this snapshot was renamed while we were creating the
+ * AVL tree, it's possible that we already inserted it under
+ * its old name. Remove the old handle before adding the new
+ * one.
+ */
+ zfs_close(node->zn_handle);
+ avl_remove(avl, node);
+ free(node);
+ }
+
+ node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t));
+ node->zn_handle = zhp;
+ avl_add(avl, node);
+
+ return (0);
+}
+
+static int
+zfs_snapshot_compare(const void *larg, const void *rarg)
+{
+ zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
+ zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
+ uint64_t lcreate, rcreate;
+
+ /*
+ * Sort them according to creation time. We use the hidden
+ * CREATETXG property to get an absolute ordering of snapshots.
+ */
+ lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
+ rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
+
+ return (AVL_CMP(lcreate, rcreate));
+}
+
+int
+zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data,
+ uint64_t min_txg, uint64_t max_txg)
+{
+ int ret = 0;
+ zfs_node_t *node;
+ avl_tree_t avl;
+ void *cookie = NULL;
+
+ avl_create(&avl, zfs_snapshot_compare,
+ sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode));
+
+ ret = zfs_iter_snapshots(zhp, B_FALSE, zfs_sort_snaps, &avl, min_txg,
+ max_txg);
+
+ for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
+ ret |= callback(node->zn_handle, data);
+
+ while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL)
+ free(node);
+
+ avl_destroy(&avl);
+
+ return (ret);
+}
+
+typedef struct {
+ char *ssa_first;
+ char *ssa_last;
+ boolean_t ssa_seenfirst;
+ boolean_t ssa_seenlast;
+ zfs_iter_f ssa_func;
+ void *ssa_arg;
+} snapspec_arg_t;
+
+static int
+snapspec_cb(zfs_handle_t *zhp, void *arg)
+{
+ snapspec_arg_t *ssa = arg;
+ const char *shortsnapname;
+ int err = 0;
+
+ if (ssa->ssa_seenlast)
+ return (0);
+
+ shortsnapname = strchr(zfs_get_name(zhp), '@') + 1;
+ if (!ssa->ssa_seenfirst && strcmp(shortsnapname, ssa->ssa_first) == 0)
+ ssa->ssa_seenfirst = B_TRUE;
+ if (strcmp(shortsnapname, ssa->ssa_last) == 0)
+ ssa->ssa_seenlast = B_TRUE;
+
+ if (ssa->ssa_seenfirst) {
+ err = ssa->ssa_func(zhp, ssa->ssa_arg);
+ } else {
+ zfs_close(zhp);
+ }
+
+ return (err);
+}
+
+/*
+ * spec is a string like "A,B%C,D"
+ *
+ * <snaps>, where <snaps> can be:
+ * <snap> (single snapshot)
+ * <snap>%<snap> (range of snapshots, inclusive)
+ * %<snap> (range of snapshots, starting with earliest)
+ * <snap>% (range of snapshots, ending with last)
+ * % (all snapshots)
+ * <snaps>[,...] (comma separated list of the above)
+ *
+ * If a snapshot can not be opened, continue trying to open the others, but
+ * return ENOENT at the end.
+ */
+int
+zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
+ zfs_iter_f func, void *arg)
+{
+ char *buf, *comma_separated, *cp;
+ int err = 0;
+ int ret = 0;
+
+ buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig);
+ cp = buf;
+
+ while ((comma_separated = strsep(&cp, ",")) != NULL) {
+ char *pct = strchr(comma_separated, '%');
+ if (pct != NULL) {
+ snapspec_arg_t ssa = { 0 };
+ ssa.ssa_func = func;
+ ssa.ssa_arg = arg;
+
+ if (pct == comma_separated)
+ ssa.ssa_seenfirst = B_TRUE;
+ else
+ ssa.ssa_first = comma_separated;
+ *pct = '\0';
+ ssa.ssa_last = pct + 1;
+
+ /*
+ * If there is a lastname specified, make sure it
+ * exists.
+ */
+ if (ssa.ssa_last[0] != '\0') {
+ char snapname[ZFS_MAX_DATASET_NAME_LEN];
+ (void) snprintf(snapname, sizeof (snapname),
+ "%s@%s", zfs_get_name(fs_zhp),
+ ssa.ssa_last);
+ if (!zfs_dataset_exists(fs_zhp->zfs_hdl,
+ snapname, ZFS_TYPE_SNAPSHOT)) {
+ ret = ENOENT;
+ continue;
+ }
+ }
+
+ err = zfs_iter_snapshots_sorted(fs_zhp,
+ snapspec_cb, &ssa, 0, 0);
+ if (ret == 0)
+ ret = err;
+ if (ret == 0 && (!ssa.ssa_seenfirst ||
+ (ssa.ssa_last[0] != '\0' && !ssa.ssa_seenlast))) {
+ ret = ENOENT;
+ }
+ } else {
+ char snapname[ZFS_MAX_DATASET_NAME_LEN];
+ zfs_handle_t *snap_zhp;
+ (void) snprintf(snapname, sizeof (snapname), "%s@%s",
+ zfs_get_name(fs_zhp), comma_separated);
+ snap_zhp = make_dataset_handle(fs_zhp->zfs_hdl,
+ snapname);
+ if (snap_zhp == NULL) {
+ ret = ENOENT;
+ continue;
+ }
+ err = func(snap_zhp, arg);
+ if (ret == 0)
+ ret = err;
+ }
+ }
+
+ free(buf);
+ return (ret);
+}
+
+/*
+ * Iterate over all children, snapshots and filesystems
+ * Process snapshots before filesystems because they are nearer the input
+ * handle: this is extremely important when used with zfs_iter_f functions
+ * looking for data, following the logic that we would like to find it as soon
+ * and as close as possible.
+ */
+int
+zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+ int ret;
+
+ if ((ret = zfs_iter_snapshots(zhp, B_FALSE, func, data, 0, 0)) != 0)
+ return (ret);
+
+ return (zfs_iter_filesystems(zhp, func, data));
+}
+
+
+typedef struct iter_stack_frame {
+ struct iter_stack_frame *next;
+ zfs_handle_t *zhp;
+} iter_stack_frame_t;
+
+typedef struct iter_dependents_arg {
+ boolean_t first;
+ boolean_t allowrecursion;
+ iter_stack_frame_t *stack;
+ zfs_iter_f func;
+ void *data;
+} iter_dependents_arg_t;
+
+static int
+iter_dependents_cb(zfs_handle_t *zhp, void *arg)
+{
+ iter_dependents_arg_t *ida = arg;
+ int err = 0;
+ boolean_t first = ida->first;
+ ida->first = B_FALSE;
+
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+ err = zfs_iter_clones(zhp, iter_dependents_cb, ida);
+ } else if (zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
+ iter_stack_frame_t isf;
+ iter_stack_frame_t *f;
+
+ /*
+ * check if there is a cycle by seeing if this fs is already
+ * on the stack.
+ */
+ for (f = ida->stack; f != NULL; f = f->next) {
+ if (f->zhp->zfs_dmustats.dds_guid ==
+ zhp->zfs_dmustats.dds_guid) {
+ if (ida->allowrecursion) {
+ zfs_close(zhp);
+ return (0);
+ } else {
+ zfs_error_aux(zhp->zfs_hdl,
+ dgettext(TEXT_DOMAIN,
+ "recursive dependency at '%s'"),
+ zfs_get_name(zhp));
+ err = zfs_error(zhp->zfs_hdl,
+ EZFS_RECURSIVE,
+ dgettext(TEXT_DOMAIN,
+ "cannot determine dependent "
+ "datasets"));
+ zfs_close(zhp);
+ return (err);
+ }
+ }
+ }
+
+ isf.zhp = zhp;
+ isf.next = ida->stack;
+ ida->stack = &isf;
+ err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida);
+ if (err == 0) {
+ err = zfs_iter_snapshots(zhp, B_FALSE,
+ iter_dependents_cb, ida, 0, 0);
+ }
+ ida->stack = isf.next;
+ }
+
+ if (!first && err == 0)
+ err = ida->func(zhp, ida->data);
+ else
+ zfs_close(zhp);
+
+ return (err);
+}
+
+int
+zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
+ zfs_iter_f func, void *data)
+{
+ iter_dependents_arg_t ida;
+ ida.allowrecursion = allowrecursion;
+ ida.stack = NULL;
+ ida.func = func;
+ ida.data = data;
+ ida.first = B_TRUE;
+ return (iter_dependents_cb(zfs_handle_dup(zhp), &ida));
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c
new file mode 100644
index 000000000000..0efeba631aff
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c
@@ -0,0 +1,1713 @@
+/*
+ * 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 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
+ * Copyright 2017 Joyent, Inc.
+ * Copyright 2017 RackTop Systems.
+ * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+/*
+ * Routines to manage ZFS mounts. We separate all the nasty routines that have
+ * to deal with the OS. The following functions are the main entry points --
+ * they are used by mount and unmount and when changing a filesystem's
+ * mountpoint.
+ *
+ * zfs_is_mounted()
+ * zfs_mount()
+ * zfs_unmount()
+ * zfs_unmountall()
+ *
+ * This file also contains the functions used to manage sharing filesystems via
+ * NFS and iSCSI:
+ *
+ * zfs_is_shared()
+ * zfs_share()
+ * zfs_unshare()
+ *
+ * zfs_is_shared_nfs()
+ * zfs_is_shared_smb()
+ * zfs_share_proto()
+ * zfs_shareall();
+ * zfs_unshare_nfs()
+ * zfs_unshare_smb()
+ * zfs_unshareall_nfs()
+ * zfs_unshareall_smb()
+ * zfs_unshareall()
+ * zfs_unshareall_bypath()
+ *
+ * The following functions are available for pool consumers, and will
+ * mount/unmount and share/unshare all datasets within pool:
+ *
+ * zpool_enable_datasets()
+ * zpool_disable_datasets()
+ */
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <zone.h>
+#include <sys/mntent.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+
+#include <libzfs.h>
+
+#include "libzfs_impl.h"
+#include <thread_pool.h>
+
+#include <libshare.h>
+#define MAXISALEN 257 /* based on sysinfo(2) man page */
+
+static int mount_tp_nthr = 512; /* tpool threads for multi-threaded mounting */
+
+static void zfs_mount_task(void *);
+static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
+zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
+ zfs_share_proto_t);
+
+/*
+ * The share protocols table must be in the same order as the zfs_share_proto_t
+ * enum in libzfs_impl.h
+ */
+typedef struct {
+ zfs_prop_t p_prop;
+ char *p_name;
+ int p_share_err;
+ int p_unshare_err;
+} proto_table_t;
+
+proto_table_t proto_table[PROTO_END] = {
+ {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
+ {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
+};
+
+zfs_share_proto_t nfs_only[] = {
+ PROTO_NFS,
+ PROTO_END
+};
+
+zfs_share_proto_t smb_only[] = {
+ PROTO_SMB,
+ PROTO_END
+};
+zfs_share_proto_t share_all_proto[] = {
+ PROTO_NFS,
+ PROTO_SMB,
+ PROTO_END
+};
+
+/*
+ * Search the sharetab for the given mountpoint and protocol, returning
+ * a zfs_share_type_t value.
+ */
+static zfs_share_type_t
+is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
+{
+ char buf[MAXPATHLEN], *tab;
+ char *ptr;
+
+ if (hdl->libzfs_sharetab == NULL)
+ return (SHARED_NOT_SHARED);
+
+ (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
+
+ while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
+
+ /* the mountpoint is the first entry on each line */
+ if ((tab = strchr(buf, '\t')) == NULL)
+ continue;
+
+ *tab = '\0';
+ if (strcmp(buf, mountpoint) == 0) {
+#ifdef illumos
+ /*
+ * the protocol field is the third field
+ * skip over second field
+ */
+ ptr = ++tab;
+ if ((tab = strchr(ptr, '\t')) == NULL)
+ continue;
+ ptr = ++tab;
+ if ((tab = strchr(ptr, '\t')) == NULL)
+ continue;
+ *tab = '\0';
+ if (strcmp(ptr,
+ proto_table[proto].p_name) == 0) {
+ switch (proto) {
+ case PROTO_NFS:
+ return (SHARED_NFS);
+ case PROTO_SMB:
+ return (SHARED_SMB);
+ default:
+ return (0);
+ }
+ }
+#else
+ if (proto == PROTO_NFS)
+ return (SHARED_NFS);
+#endif
+ }
+ }
+
+ return (SHARED_NOT_SHARED);
+}
+
+#ifdef illumos
+static boolean_t
+dir_is_empty_stat(const char *dirname)
+{
+ struct stat st;
+
+ /*
+ * We only want to return false if the given path is a non empty
+ * directory, all other errors are handled elsewhere.
+ */
+ if (stat(dirname, &st) < 0 || !S_ISDIR(st.st_mode)) {
+ return (B_TRUE);
+ }
+
+ /*
+ * An empty directory will still have two entries in it, one
+ * entry for each of "." and "..".
+ */
+ if (st.st_size > 2) {
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+static boolean_t
+dir_is_empty_readdir(const char *dirname)
+{
+ DIR *dirp;
+ struct dirent64 *dp;
+ int dirfd;
+
+ if ((dirfd = openat(AT_FDCWD, dirname,
+ O_RDONLY | O_NDELAY | O_LARGEFILE | O_CLOEXEC, 0)) < 0) {
+ return (B_TRUE);
+ }
+
+ if ((dirp = fdopendir(dirfd)) == NULL) {
+ (void) close(dirfd);
+ return (B_TRUE);
+ }
+
+ while ((dp = readdir64(dirp)) != NULL) {
+
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+
+ (void) closedir(dirp);
+ return (B_FALSE);
+ }
+
+ (void) closedir(dirp);
+ return (B_TRUE);
+}
+
+/*
+ * Returns true if the specified directory is empty. If we can't open the
+ * directory at all, return true so that the mount can fail with a more
+ * informative error message.
+ */
+static boolean_t
+dir_is_empty(const char *dirname)
+{
+ struct statvfs64 st;
+
+ /*
+ * If the statvfs call fails or the filesystem is not a ZFS
+ * filesystem, fall back to the slow path which uses readdir.
+ */
+ if ((statvfs64(dirname, &st) != 0) ||
+ (strcmp(st.f_basetype, "zfs") != 0)) {
+ return (dir_is_empty_readdir(dirname));
+ }
+
+ /*
+ * At this point, we know the provided path is on a ZFS
+ * filesystem, so we can use stat instead of readdir to
+ * determine if the directory is empty or not. We try to avoid
+ * using readdir because that requires opening "dirname"; this
+ * open file descriptor can potentially end up in a child
+ * process if there's a concurrent fork, thus preventing the
+ * zfs_mount() from otherwise succeeding (the open file
+ * descriptor inherited by the child process will cause the
+ * parent's mount to fail with EBUSY). The performance
+ * implications of replacing the open, read, and close with a
+ * single stat is nice; but is not the main motivation for the
+ * added complexity.
+ */
+ return (dir_is_empty_stat(dirname));
+}
+#endif
+
+/*
+ * Checks to see if the mount is active. If the filesystem is mounted, we fill
+ * in 'where' with the current mountpoint, and return 1. Otherwise, we return
+ * 0.
+ */
+boolean_t
+is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where)
+{
+ struct mnttab entry;
+
+ if (libzfs_mnttab_find(zfs_hdl, special, &entry) != 0)
+ return (B_FALSE);
+
+ if (where != NULL)
+ *where = zfs_strdup(zfs_hdl, entry.mnt_mountp);
+
+ return (B_TRUE);
+}
+
+boolean_t
+zfs_is_mounted(zfs_handle_t *zhp, char **where)
+{
+ return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where));
+}
+
+/*
+ * Returns true if the given dataset is mountable, false otherwise. Returns the
+ * mountpoint in 'buf'.
+ */
+static boolean_t
+zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
+ zprop_source_t *source)
+{
+ char sourceloc[MAXNAMELEN];
+ zprop_source_t sourcetype;
+
+ if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type))
+ return (B_FALSE);
+
+ verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen,
+ &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0);
+
+ if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 ||
+ strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0)
+ return (B_FALSE);
+
+ if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF)
+ return (B_FALSE);
+
+ if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
+ getzoneid() == GLOBAL_ZONEID)
+ return (B_FALSE);
+
+ if (source)
+ *source = sourcetype;
+
+ return (B_TRUE);
+}
+
+/*
+ * Mount the given filesystem.
+ */
+int
+zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
+{
+ struct stat buf;
+ char mountpoint[ZFS_MAXPROPLEN];
+ char mntopts[MNT_LINE_MAX];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+ if (options == NULL)
+ mntopts[0] = '\0';
+ else
+ (void) strlcpy(mntopts, options, sizeof (mntopts));
+
+ /*
+ * If the pool is imported read-only then all mounts must be read-only
+ */
+ if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
+ flags |= MS_RDONLY;
+
+ if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
+ return (0);
+
+ /* Create the directory if it doesn't already exist */
+ if (lstat(mountpoint, &buf) != 0) {
+ if (mkdirp(mountpoint, 0755) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "failed to create mountpoint"));
+ return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
+ dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
+ mountpoint));
+ }
+ }
+
+#ifdef illumos /* FreeBSD: overlay mounts are not checked. */
+ /*
+ * Determine if the mountpoint is empty. If so, refuse to perform the
+ * mount. We don't perform this check if MS_OVERLAY is specified, which
+ * would defeat the point. We also avoid this check if 'remount' is
+ * specified.
+ */
+ if ((flags & MS_OVERLAY) == 0 &&
+ strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
+ !dir_is_empty(mountpoint)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "directory is not empty"));
+ return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
+ dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
+ }
+#endif
+
+ /* perform the mount */
+ if (zmount(zfs_get_name(zhp), mountpoint, flags,
+ MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
+ /*
+ * Generic errors are nasty, but there are just way too many
+ * from mount(), and they're well-understood. We pick a few
+ * common ones to improve upon.
+ */
+ if (errno == EBUSY) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "mountpoint or dataset is busy"));
+ } else if (errno == EPERM) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Insufficient privileges"));
+ } else if (errno == ENOTSUP) {
+ char buf[256];
+ int spa_version;
+
+ VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
+ (void) snprintf(buf, sizeof (buf),
+ dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
+ "file system on a version %d pool. Pool must be"
+ " upgraded to mount this file system."),
+ (u_longlong_t)zfs_prop_get_int(zhp,
+ ZFS_PROP_VERSION), spa_version);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
+ } else {
+ zfs_error_aux(hdl, strerror(errno));
+ }
+ return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
+ dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
+ zhp->zfs_name));
+ }
+
+ /* add the mounted entry into our cache */
+ libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint,
+ mntopts);
+ return (0);
+}
+
+/*
+ * Unmount a single filesystem.
+ */
+static int
+unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
+{
+ if (umount2(mountpoint, flags) != 0) {
+ zfs_error_aux(hdl, strerror(errno));
+ return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
+ dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
+ mountpoint));
+ }
+
+ return (0);
+}
+
+/*
+ * Unmount the given filesystem.
+ */
+int
+zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ struct mnttab entry;
+ char *mntpt = NULL;
+
+ /* check to see if we need to unmount the filesystem */
+ if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
+ libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) {
+ /*
+ * mountpoint may have come from a call to
+ * getmnt/getmntany if it isn't NULL. If it is NULL,
+ * we know it comes from libzfs_mnttab_find which can
+ * then get freed later. We strdup it to play it safe.
+ */
+ if (mountpoint == NULL)
+ mntpt = zfs_strdup(hdl, entry.mnt_mountp);
+ else
+ mntpt = zfs_strdup(hdl, mountpoint);
+
+ /*
+ * Unshare and unmount the filesystem
+ */
+ if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
+ return (-1);
+
+ if (unmount_one(hdl, mntpt, flags) != 0) {
+ free(mntpt);
+ (void) zfs_shareall(zhp);
+ return (-1);
+ }
+ libzfs_mnttab_remove(hdl, zhp->zfs_name);
+ free(mntpt);
+ }
+
+ return (0);
+}
+
+/*
+ * Unmount this filesystem and any children inheriting the mountpoint property.
+ * To do this, just act like we're changing the mountpoint property, but don't
+ * remount the filesystems afterwards.
+ */
+int
+zfs_unmountall(zfs_handle_t *zhp, int flags)
+{
+ prop_changelist_t *clp;
+ int ret;
+
+ clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags);
+ if (clp == NULL)
+ return (-1);
+
+ ret = changelist_prefix(clp);
+ changelist_free(clp);
+
+ return (ret);
+}
+
+boolean_t
+zfs_is_shared(zfs_handle_t *zhp)
+{
+ zfs_share_type_t rc = 0;
+ zfs_share_proto_t *curr_proto;
+
+ if (ZFS_IS_VOLUME(zhp))
+ return (B_FALSE);
+
+ for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+ curr_proto++)
+ rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto);
+
+ return (rc ? B_TRUE : B_FALSE);
+}
+
+int
+zfs_share(zfs_handle_t *zhp)
+{
+ assert(!ZFS_IS_VOLUME(zhp));
+ return (zfs_share_proto(zhp, share_all_proto));
+}
+
+int
+zfs_unshare(zfs_handle_t *zhp)
+{
+ assert(!ZFS_IS_VOLUME(zhp));
+ return (zfs_unshareall(zhp));
+}
+
+/*
+ * Check to see if the filesystem is currently shared.
+ */
+zfs_share_type_t
+zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
+{
+ char *mountpoint;
+ zfs_share_type_t rc;
+
+ if (!zfs_is_mounted(zhp, &mountpoint))
+ return (SHARED_NOT_SHARED);
+
+ if ((rc = is_shared(zhp->zfs_hdl, mountpoint, proto))
+ != SHARED_NOT_SHARED) {
+ if (where != NULL)
+ *where = mountpoint;
+ else
+ free(mountpoint);
+ return (rc);
+ } else {
+ free(mountpoint);
+ return (SHARED_NOT_SHARED);
+ }
+}
+
+boolean_t
+zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
+{
+ return (zfs_is_shared_proto(zhp, where,
+ PROTO_NFS) != SHARED_NOT_SHARED);
+}
+
+boolean_t
+zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
+{
+ return (zfs_is_shared_proto(zhp, where,
+ PROTO_SMB) != SHARED_NOT_SHARED);
+}
+
+/*
+ * Make sure things will work if libshare isn't installed by using
+ * wrapper functions that check to see that the pointers to functions
+ * initialized in _zfs_init_libshare() are actually present.
+ */
+
+#ifdef illumos
+static sa_handle_t (*_sa_init)(int);
+static sa_handle_t (*_sa_init_arg)(int, void *);
+static void (*_sa_fini)(sa_handle_t);
+static sa_share_t (*_sa_find_share)(sa_handle_t, char *);
+static int (*_sa_enable_share)(sa_share_t, char *);
+static int (*_sa_disable_share)(sa_share_t, char *);
+static char *(*_sa_errorstr)(int);
+static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *);
+static boolean_t (*_sa_needs_refresh)(sa_handle_t *);
+static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t);
+static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t,
+ char *, char *, zprop_source_t, char *, char *, char *);
+static void (*_sa_update_sharetab_ts)(sa_handle_t);
+#endif
+
+/*
+ * _zfs_init_libshare()
+ *
+ * Find the libshare.so.1 entry points that we use here and save the
+ * values to be used later. This is triggered by the runtime loader.
+ * Make sure the correct ISA version is loaded.
+ */
+
+#pragma init(_zfs_init_libshare)
+static void
+_zfs_init_libshare(void)
+{
+#ifdef illumos
+ void *libshare;
+ char path[MAXPATHLEN];
+ char isa[MAXISALEN];
+
+#if defined(_LP64)
+ if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
+ isa[0] = '\0';
+#else
+ isa[0] = '\0';
+#endif
+ (void) snprintf(path, MAXPATHLEN,
+ "/usr/lib/%s/libshare.so.1", isa);
+
+ if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) {
+ _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init");
+ _sa_init_arg = (sa_handle_t (*)(int, void *))dlsym(libshare,
+ "sa_init_arg");
+ _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini");
+ _sa_find_share = (sa_share_t (*)(sa_handle_t, char *))
+ dlsym(libshare, "sa_find_share");
+ _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
+ "sa_enable_share");
+ _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
+ "sa_disable_share");
+ _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr");
+ _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *))
+ dlsym(libshare, "sa_parse_legacy_options");
+ _sa_needs_refresh = (boolean_t (*)(sa_handle_t *))
+ dlsym(libshare, "sa_needs_refresh");
+ _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t))
+ dlsym(libshare, "sa_get_zfs_handle");
+ _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t,
+ sa_share_t, char *, char *, zprop_source_t, char *,
+ char *, char *))dlsym(libshare, "sa_zfs_process_share");
+ _sa_update_sharetab_ts = (void (*)(sa_handle_t))
+ dlsym(libshare, "sa_update_sharetab_ts");
+ if (_sa_init == NULL || _sa_init_arg == NULL ||
+ _sa_fini == NULL || _sa_find_share == NULL ||
+ _sa_enable_share == NULL || _sa_disable_share == NULL ||
+ _sa_errorstr == NULL || _sa_parse_legacy_options == NULL ||
+ _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL ||
+ _sa_zfs_process_share == NULL ||
+ _sa_update_sharetab_ts == NULL) {
+ _sa_init = NULL;
+ _sa_init_arg = NULL;
+ _sa_fini = NULL;
+ _sa_disable_share = NULL;
+ _sa_enable_share = NULL;
+ _sa_errorstr = NULL;
+ _sa_parse_legacy_options = NULL;
+ (void) dlclose(libshare);
+ _sa_needs_refresh = NULL;
+ _sa_get_zfs_handle = NULL;
+ _sa_zfs_process_share = NULL;
+ _sa_update_sharetab_ts = NULL;
+ }
+ }
+#endif
+}
+
+/*
+ * zfs_init_libshare(zhandle, service)
+ *
+ * Initialize the libshare API if it hasn't already been initialized.
+ * In all cases it returns 0 if it succeeded and an error if not. The
+ * service value is which part(s) of the API to initialize and is a
+ * direct map to the libshare sa_init(service) interface.
+ */
+static int
+zfs_init_libshare_impl(libzfs_handle_t *zhandle, int service, void *arg)
+{
+#ifdef illumos
+ /*
+ * libshare is either not installed or we're in a branded zone. The
+ * rest of the wrapper functions around the libshare calls already
+ * handle NULL function pointers, but we don't want the callers of
+ * zfs_init_libshare() to fail prematurely if libshare is not available.
+ */
+ if (_sa_init == NULL)
+ return (SA_OK);
+
+ /*
+ * Attempt to refresh libshare. This is necessary if there was a cache
+ * miss for a new ZFS dataset that was just created, or if state of the
+ * sharetab file has changed since libshare was last initialized. We
+ * want to make sure so check timestamps to see if a different process
+ * has updated any of the configuration. If there was some non-ZFS
+ * change, we need to re-initialize the internal cache.
+ */
+ if (_sa_needs_refresh != NULL &&
+ _sa_needs_refresh(zhandle->libzfs_sharehdl)) {
+ zfs_uninit_libshare(zhandle);
+ zhandle->libzfs_sharehdl = _sa_init_arg(service, arg);
+ }
+
+ if (zhandle && zhandle->libzfs_sharehdl == NULL)
+ zhandle->libzfs_sharehdl = _sa_init_arg(service, arg);
+
+ if (zhandle->libzfs_sharehdl == NULL)
+ return (SA_NO_MEMORY);
+#endif
+
+ return (SA_OK);
+}
+int
+zfs_init_libshare(libzfs_handle_t *zhandle, int service)
+{
+ return (zfs_init_libshare_impl(zhandle, service, NULL));
+}
+
+int
+zfs_init_libshare_arg(libzfs_handle_t *zhandle, int service, void *arg)
+{
+ return (zfs_init_libshare_impl(zhandle, service, arg));
+}
+
+
+/*
+ * zfs_uninit_libshare(zhandle)
+ *
+ * Uninitialize the libshare API if it hasn't already been
+ * uninitialized. It is OK to call multiple times.
+ */
+void
+zfs_uninit_libshare(libzfs_handle_t *zhandle)
+{
+ if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
+#ifdef illumos
+ if (_sa_fini != NULL)
+ _sa_fini(zhandle->libzfs_sharehdl);
+#endif
+ zhandle->libzfs_sharehdl = NULL;
+ }
+}
+
+/*
+ * zfs_parse_options(options, proto)
+ *
+ * Call the legacy parse interface to get the protocol specific
+ * options using the NULL arg to indicate that this is a "parse" only.
+ */
+int
+zfs_parse_options(char *options, zfs_share_proto_t proto)
+{
+#ifdef illumos
+ if (_sa_parse_legacy_options != NULL) {
+ return (_sa_parse_legacy_options(NULL, options,
+ proto_table[proto].p_name));
+ }
+ return (SA_CONFIG_ERR);
+#else
+ return (SA_OK);
+#endif
+}
+
+#ifdef illumos
+/*
+ * zfs_sa_find_share(handle, path)
+ *
+ * wrapper around sa_find_share to find a share path in the
+ * configuration.
+ */
+static sa_share_t
+zfs_sa_find_share(sa_handle_t handle, char *path)
+{
+ if (_sa_find_share != NULL)
+ return (_sa_find_share(handle, path));
+ return (NULL);
+}
+
+/*
+ * zfs_sa_enable_share(share, proto)
+ *
+ * Wrapper for sa_enable_share which enables a share for a specified
+ * protocol.
+ */
+static int
+zfs_sa_enable_share(sa_share_t share, char *proto)
+{
+ if (_sa_enable_share != NULL)
+ return (_sa_enable_share(share, proto));
+ return (SA_CONFIG_ERR);
+}
+
+/*
+ * zfs_sa_disable_share(share, proto)
+ *
+ * Wrapper for sa_enable_share which disables a share for a specified
+ * protocol.
+ */
+static int
+zfs_sa_disable_share(sa_share_t share, char *proto)
+{
+ if (_sa_disable_share != NULL)
+ return (_sa_disable_share(share, proto));
+ return (SA_CONFIG_ERR);
+}
+#endif /* illumos */
+
+/*
+ * Share the given filesystem according to the options in the specified
+ * protocol specific properties (sharenfs, sharesmb). We rely
+ * on "libshare" to the dirty work for us.
+ */
+static int
+zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
+{
+ char mountpoint[ZFS_MAXPROPLEN];
+ char shareopts[ZFS_MAXPROPLEN];
+ char sourcestr[ZFS_MAXPROPLEN];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ zfs_share_proto_t *curr_proto;
+ zprop_source_t sourcetype;
+ int error, ret;
+
+ if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
+ return (0);
+
+ for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
+ /*
+ * Return success if there are no share options.
+ */
+ if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
+ shareopts, sizeof (shareopts), &sourcetype, sourcestr,
+ ZFS_MAXPROPLEN, B_FALSE) != 0 ||
+ strcmp(shareopts, "off") == 0)
+ continue;
+#ifdef illumos
+ ret = zfs_init_libshare_arg(hdl, SA_INIT_ONE_SHARE_FROM_HANDLE,
+ zhp);
+ if (ret != SA_OK) {
+ (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
+ dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
+ zfs_get_name(zhp), _sa_errorstr != NULL ?
+ _sa_errorstr(ret) : "");
+ return (-1);
+ }
+#endif
+
+ /*
+ * If the 'zoned' property is set, then zfs_is_mountable()
+ * will have already bailed out if we are in the global zone.
+ * But local zones cannot be NFS servers, so we ignore it for
+ * local zones as well.
+ */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
+ continue;
+
+#ifdef illumos
+ share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
+ if (share == NULL) {
+ /*
+ * This may be a new file system that was just
+ * created so isn't in the internal cache
+ * (second time through). Rather than
+ * reloading the entire configuration, we can
+ * assume ZFS has done the checking and it is
+ * safe to add this to the internal
+ * configuration.
+ */
+ if (_sa_zfs_process_share(hdl->libzfs_sharehdl,
+ NULL, NULL, mountpoint,
+ proto_table[*curr_proto].p_name, sourcetype,
+ shareopts, sourcestr, zhp->zfs_name) != SA_OK) {
+ (void) zfs_error_fmt(hdl,
+ proto_table[*curr_proto].p_share_err,
+ dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+ zfs_get_name(zhp));
+ return (-1);
+ }
+ share = zfs_sa_find_share(hdl->libzfs_sharehdl,
+ mountpoint);
+ }
+ if (share != NULL) {
+ int err;
+ err = zfs_sa_enable_share(share,
+ proto_table[*curr_proto].p_name);
+ if (err != SA_OK) {
+ (void) zfs_error_fmt(hdl,
+ proto_table[*curr_proto].p_share_err,
+ dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+ zfs_get_name(zhp));
+ return (-1);
+ }
+ } else
+#else
+ if (*curr_proto != PROTO_NFS) {
+ fprintf(stderr, "Unsupported share protocol: %d.\n",
+ *curr_proto);
+ continue;
+ }
+
+ if (strcmp(shareopts, "on") == 0)
+ error = fsshare(ZFS_EXPORTS_PATH, mountpoint, "");
+ else
+ error = fsshare(ZFS_EXPORTS_PATH, mountpoint, shareopts);
+ if (error != 0)
+#endif
+ {
+ (void) zfs_error_fmt(hdl,
+ proto_table[*curr_proto].p_share_err,
+ dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+ zfs_get_name(zhp));
+ return (-1);
+ }
+
+ }
+ return (0);
+}
+
+
+int
+zfs_share_nfs(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, nfs_only));
+}
+
+int
+zfs_share_smb(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, smb_only));
+}
+
+int
+zfs_shareall(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, share_all_proto));
+}
+
+/*
+ * Unshare a filesystem by mountpoint.
+ */
+static int
+unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
+ zfs_share_proto_t proto)
+{
+#ifdef illumos
+ sa_share_t share;
+ int err;
+ char *mntpt;
+
+ /*
+ * Mountpoint could get trashed if libshare calls getmntany
+ * which it does during API initialization, so strdup the
+ * value.
+ */
+ mntpt = zfs_strdup(hdl, mountpoint);
+
+ /*
+ * make sure libshare initialized, initialize everything because we
+ * don't know what other unsharing may happen later. Functions up the
+ * stack are allowed to initialize instead a subset of shares at the
+ * time the set is known.
+ */
+ if ((err = zfs_init_libshare_arg(hdl, SA_INIT_ONE_SHARE_FROM_NAME,
+ (void *)name)) != SA_OK) {
+ free(mntpt); /* don't need the copy anymore */
+ return (zfs_error_fmt(hdl, proto_table[proto].p_unshare_err,
+ dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
+ name, _sa_errorstr(err)));
+ }
+
+ share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt);
+ free(mntpt); /* don't need the copy anymore */
+
+ if (share != NULL) {
+ err = zfs_sa_disable_share(share, proto_table[proto].p_name);
+ if (err != SA_OK) {
+ return (zfs_error_fmt(hdl,
+ proto_table[proto].p_unshare_err,
+ dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
+ name, _sa_errorstr(err)));
+ }
+ } else {
+ return (zfs_error_fmt(hdl, proto_table[proto].p_unshare_err,
+ dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"),
+ name));
+ }
+#else
+ char buf[MAXPATHLEN];
+ FILE *fp;
+ int err;
+
+ if (proto != PROTO_NFS) {
+ fprintf(stderr, "No SMB support in FreeBSD yet.\n");
+ return (EOPNOTSUPP);
+ }
+
+ err = fsunshare(ZFS_EXPORTS_PATH, mountpoint);
+ if (err != 0) {
+ zfs_error_aux(hdl, "%s", strerror(err));
+ return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
+ dgettext(TEXT_DOMAIN,
+ "cannot unshare '%s'"), name));
+ }
+#endif
+ return (0);
+}
+
+/*
+ * Unshare the given filesystem.
+ */
+int
+zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
+ zfs_share_proto_t *proto)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ struct mnttab entry;
+ char *mntpt = NULL;
+
+ /* check to see if need to unmount the filesystem */
+ rewind(zhp->zfs_hdl->libzfs_mnttab);
+ if (mountpoint != NULL)
+ mountpoint = mntpt = zfs_strdup(hdl, mountpoint);
+
+ if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
+ libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) {
+ zfs_share_proto_t *curr_proto;
+
+ if (mountpoint == NULL)
+ mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
+
+ for (curr_proto = proto; *curr_proto != PROTO_END;
+ curr_proto++) {
+
+ if (is_shared(hdl, mntpt, *curr_proto) &&
+ unshare_one(hdl, zhp->zfs_name,
+ mntpt, *curr_proto) != 0) {
+ if (mntpt != NULL)
+ free(mntpt);
+ return (-1);
+ }
+ }
+ }
+ if (mntpt != NULL)
+ free(mntpt);
+
+ return (0);
+}
+
+int
+zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, nfs_only));
+}
+
+int
+zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, smb_only));
+}
+
+/*
+ * Same as zfs_unmountall(), but for NFS and SMB unshares.
+ */
+int
+zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
+{
+ prop_changelist_t *clp;
+ int ret;
+
+ clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0);
+ if (clp == NULL)
+ return (-1);
+
+ ret = changelist_unshare(clp, proto);
+ changelist_free(clp);
+
+ return (ret);
+}
+
+int
+zfs_unshareall_nfs(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, nfs_only));
+}
+
+int
+zfs_unshareall_smb(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, smb_only));
+}
+
+int
+zfs_unshareall(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, share_all_proto));
+}
+
+int
+zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
+}
+
+/*
+ * Remove the mountpoint associated with the current dataset, if necessary.
+ * We only remove the underlying directory if:
+ *
+ * - The mountpoint is not 'none' or 'legacy'
+ * - The mountpoint is non-empty
+ * - The mountpoint is the default or inherited
+ * - The 'zoned' property is set, or we're in a local zone
+ *
+ * Any other directories we leave alone.
+ */
+void
+remove_mountpoint(zfs_handle_t *zhp)
+{
+ char mountpoint[ZFS_MAXPROPLEN];
+ zprop_source_t source;
+
+ if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
+ &source))
+ return;
+
+ if (source == ZPROP_SRC_DEFAULT ||
+ source == ZPROP_SRC_INHERITED) {
+ /*
+ * Try to remove the directory, silently ignoring any errors.
+ * The filesystem may have since been removed or moved around,
+ * and this error isn't really useful to the administrator in
+ * any way.
+ */
+ (void) rmdir(mountpoint);
+ }
+}
+
+/*
+ * Add the given zfs handle to the cb_handles array, dynamically reallocating
+ * the array if it is out of space
+ */
+void
+libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp)
+{
+ if (cbp->cb_alloc == cbp->cb_used) {
+ size_t newsz;
+ zfs_handle_t **newhandles;
+
+ newsz = cbp->cb_alloc != 0 ? cbp->cb_alloc * 2 : 64;
+ newhandles = zfs_realloc(zhp->zfs_hdl,
+ cbp->cb_handles, cbp->cb_alloc * sizeof (zfs_handle_t *),
+ newsz * sizeof (zfs_handle_t *));
+ cbp->cb_handles = newhandles;
+ cbp->cb_alloc = newsz;
+ }
+ cbp->cb_handles[cbp->cb_used++] = zhp;
+}
+
+/*
+ * Recursive helper function used during file system enumeration
+ */
+static int
+zfs_iter_cb(zfs_handle_t *zhp, void *data)
+{
+ get_all_cb_t *cbp = data;
+
+ if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ /*
+ * If this filesystem is inconsistent and has a receive resume
+ * token, we can not mount it.
+ */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
+ zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+ NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ libzfs_add_handle(cbp, zhp);
+ if (zfs_iter_filesystems(zhp, zfs_iter_cb, cbp) != 0) {
+ zfs_close(zhp);
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Sort comparator that compares two mountpoint paths. We sort these paths so
+ * that subdirectories immediately follow their parents. This means that we
+ * effectively treat the '/' character as the lowest value non-nul char.
+ * Since filesystems from non-global zones can have the same mountpoint
+ * as other filesystems, the comparator sorts global zone filesystems to
+ * the top of the list. This means that the global zone will traverse the
+ * filesystem list in the correct order and can stop when it sees the
+ * first zoned filesystem. In a non-global zone, only the delegated
+ * filesystems are seen.
+ *
+ * An example sorted list using this comparator would look like:
+ *
+ * /foo
+ * /foo/bar
+ * /foo/bar/baz
+ * /foo/baz
+ * /foo.bar
+ * /foo (NGZ1)
+ * /foo (NGZ2)
+ *
+ * The mount code depend on this ordering to deterministically iterate
+ * over filesystems in order to spawn parallel mount tasks.
+ */
+static int
+mountpoint_cmp(const void *arga, const void *argb)
+{
+ zfs_handle_t *const *zap = arga;
+ zfs_handle_t *za = *zap;
+ zfs_handle_t *const *zbp = argb;
+ zfs_handle_t *zb = *zbp;
+ char mounta[MAXPATHLEN];
+ char mountb[MAXPATHLEN];
+ const char *a = mounta;
+ const char *b = mountb;
+ boolean_t gota, gotb;
+ uint64_t zoneda, zonedb;
+
+ zoneda = zfs_prop_get_int(za, ZFS_PROP_ZONED);
+ zonedb = zfs_prop_get_int(zb, ZFS_PROP_ZONED);
+ if (zoneda && !zonedb)
+ return (1);
+ if (!zoneda && zonedb)
+ return (-1);
+ gota = (zfs_get_type(za) == ZFS_TYPE_FILESYSTEM);
+ if (gota)
+ verify(zfs_prop_get(za, ZFS_PROP_MOUNTPOINT, mounta,
+ sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
+ gotb = (zfs_get_type(zb) == ZFS_TYPE_FILESYSTEM);
+ if (gotb)
+ verify(zfs_prop_get(zb, ZFS_PROP_MOUNTPOINT, mountb,
+ sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
+
+ if (gota && gotb) {
+ while (*a != '\0' && (*a == *b)) {
+ a++;
+ b++;
+ }
+ if (*a == *b)
+ return (0);
+ if (*a == '\0')
+ return (-1);
+ if (*b == '\0')
+ return (1);
+ if (*a == '/')
+ return (-1);
+ if (*b == '/')
+ return (1);
+ return (*a < *b ? -1 : *a > *b);
+ }
+
+ if (gota)
+ return (-1);
+ if (gotb)
+ return (1);
+
+ /*
+ * If neither filesystem has a mountpoint, revert to sorting by
+ * datset name.
+ */
+ return (strcmp(zfs_get_name(za), zfs_get_name(zb)));
+}
+
+/*
+ * Return true if path2 is a child of path1 or path2 equals path1 or
+ * path1 is "/" (path2 is always a child of "/").
+ */
+static boolean_t
+libzfs_path_contains(const char *path1, const char *path2)
+{
+ return (strcmp(path1, path2) == 0 || strcmp(path1, "/") == 0 ||
+ (strstr(path2, path1) == path2 && path2[strlen(path1)] == '/'));
+}
+
+
+static int
+non_descendant_idx(zfs_handle_t **handles, size_t num_handles, int idx)
+{
+ char parent[ZFS_MAXPROPLEN];
+ char child[ZFS_MAXPROPLEN];
+ int i;
+
+ verify(zfs_prop_get(handles[idx], ZFS_PROP_MOUNTPOINT, parent,
+ sizeof (parent), NULL, NULL, 0, B_FALSE) == 0);
+
+ for (i = idx + 1; i < num_handles; i++) {
+ verify(zfs_prop_get(handles[i], ZFS_PROP_MOUNTPOINT, child,
+ sizeof (child), NULL, NULL, 0, B_FALSE) == 0);
+ if (!libzfs_path_contains(parent, child))
+ break;
+ }
+ return (i);
+}
+
+typedef struct mnt_param {
+ libzfs_handle_t *mnt_hdl;
+ tpool_t *mnt_tp;
+ zfs_handle_t **mnt_zhps; /* filesystems to mount */
+ size_t mnt_num_handles;
+ int mnt_idx; /* Index of selected entry to mount */
+ zfs_iter_f mnt_func;
+ void *mnt_data;
+} mnt_param_t;
+
+/*
+ * Allocate and populate the parameter struct for mount function, and
+ * schedule mounting of the entry selected by idx.
+ */
+static void
+zfs_dispatch_mount(libzfs_handle_t *hdl, zfs_handle_t **handles,
+ size_t num_handles, int idx, zfs_iter_f func, void *data, tpool_t *tp)
+{
+ mnt_param_t *mnt_param = zfs_alloc(hdl, sizeof (mnt_param_t));
+
+ mnt_param->mnt_hdl = hdl;
+ mnt_param->mnt_tp = tp;
+ mnt_param->mnt_zhps = handles;
+ mnt_param->mnt_num_handles = num_handles;
+ mnt_param->mnt_idx = idx;
+ mnt_param->mnt_func = func;
+ mnt_param->mnt_data = data;
+
+ (void) tpool_dispatch(tp, zfs_mount_task, (void*)mnt_param);
+}
+
+/*
+ * This is the structure used to keep state of mounting or sharing operations
+ * during a call to zpool_enable_datasets().
+ */
+typedef struct mount_state {
+ /*
+ * ms_mntstatus is set to -1 if any mount fails. While multiple threads
+ * could update this variable concurrently, no synchronization is
+ * needed as it's only ever set to -1.
+ */
+ int ms_mntstatus;
+ int ms_mntflags;
+ const char *ms_mntopts;
+} mount_state_t;
+
+static int
+zfs_mount_one(zfs_handle_t *zhp, void *arg)
+{
+ mount_state_t *ms = arg;
+ int ret = 0;
+
+ if (zfs_mount(zhp, ms->ms_mntopts, ms->ms_mntflags) != 0)
+ ret = ms->ms_mntstatus = -1;
+ return (ret);
+}
+
+static int
+zfs_share_one(zfs_handle_t *zhp, void *arg)
+{
+ mount_state_t *ms = arg;
+ int ret = 0;
+
+ if (zfs_share(zhp) != 0)
+ ret = ms->ms_mntstatus = -1;
+ return (ret);
+}
+
+/*
+ * Thread pool function to mount one file system. On completion, it finds and
+ * schedules its children to be mounted. This depends on the sorting done in
+ * zfs_foreach_mountpoint(). Note that the degenerate case (chain of entries
+ * each descending from the previous) will have no parallelism since we always
+ * have to wait for the parent to finish mounting before we can schedule
+ * its children.
+ */
+static void
+zfs_mount_task(void *arg)
+{
+ mnt_param_t *mp = arg;
+ int idx = mp->mnt_idx;
+ zfs_handle_t **handles = mp->mnt_zhps;
+ size_t num_handles = mp->mnt_num_handles;
+ char mountpoint[ZFS_MAXPROPLEN];
+
+ verify(zfs_prop_get(handles[idx], ZFS_PROP_MOUNTPOINT, mountpoint,
+ sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
+
+ if (mp->mnt_func(handles[idx], mp->mnt_data) != 0)
+ return;
+
+ /*
+ * We dispatch tasks to mount filesystems with mountpoints underneath
+ * this one. We do this by dispatching the next filesystem with a
+ * descendant mountpoint of the one we just mounted, then skip all of
+ * its descendants, dispatch the next descendant mountpoint, and so on.
+ * The non_descendant_idx() function skips over filesystems that are
+ * descendants of the filesystem we just dispatched.
+ */
+ for (int i = idx + 1; i < num_handles;
+ i = non_descendant_idx(handles, num_handles, i)) {
+ char child[ZFS_MAXPROPLEN];
+ verify(zfs_prop_get(handles[i], ZFS_PROP_MOUNTPOINT,
+ child, sizeof (child), NULL, NULL, 0, B_FALSE) == 0);
+
+ if (!libzfs_path_contains(mountpoint, child))
+ break; /* not a descendant, return */
+ zfs_dispatch_mount(mp->mnt_hdl, handles, num_handles, i,
+ mp->mnt_func, mp->mnt_data, mp->mnt_tp);
+ }
+ free(mp);
+}
+
+/*
+ * Issue the func callback for each ZFS handle contained in the handles
+ * array. This function is used to mount all datasets, and so this function
+ * guarantees that filesystems for parent mountpoints are called before their
+ * children. As such, before issuing any callbacks, we first sort the array
+ * of handles by mountpoint.
+ *
+ * Callbacks are issued in one of two ways:
+ *
+ * 1. Sequentially: If the parallel argument is B_FALSE or the ZFS_SERIAL_MOUNT
+ * environment variable is set, then we issue callbacks sequentially.
+ *
+ * 2. In parallel: If the parallel argument is B_TRUE and the ZFS_SERIAL_MOUNT
+ * environment variable is not set, then we use a tpool to dispatch threads
+ * to mount filesystems in parallel. This function dispatches tasks to mount
+ * the filesystems at the top-level mountpoints, and these tasks in turn
+ * are responsible for recursively mounting filesystems in their children
+ * mountpoints.
+ */
+void
+zfs_foreach_mountpoint(libzfs_handle_t *hdl, zfs_handle_t **handles,
+ size_t num_handles, zfs_iter_f func, void *data, boolean_t parallel)
+{
+ zoneid_t zoneid = getzoneid();
+
+ /*
+ * The ZFS_SERIAL_MOUNT environment variable is an undocumented
+ * variable that can be used as a convenience to do a/b comparison
+ * of serial vs. parallel mounting.
+ */
+ boolean_t serial_mount = !parallel ||
+ (getenv("ZFS_SERIAL_MOUNT") != NULL);
+
+ /*
+ * Sort the datasets by mountpoint. See mountpoint_cmp for details
+ * of how these are sorted.
+ */
+ qsort(handles, num_handles, sizeof (zfs_handle_t *), mountpoint_cmp);
+
+ if (serial_mount) {
+ for (int i = 0; i < num_handles; i++) {
+ func(handles[i], data);
+ }
+ return;
+ }
+
+ /*
+ * Issue the callback function for each dataset using a parallel
+ * algorithm that uses a thread pool to manage threads.
+ */
+ tpool_t *tp = tpool_create(1, mount_tp_nthr, 0, NULL);
+
+ /*
+ * There may be multiple "top level" mountpoints outside of the pool's
+ * root mountpoint, e.g.: /foo /bar. Dispatch a mount task for each of
+ * these.
+ */
+ for (int i = 0; i < num_handles;
+ i = non_descendant_idx(handles, num_handles, i)) {
+ /*
+ * Since the mountpoints have been sorted so that the zoned
+ * filesystems are at the end, a zoned filesystem seen from
+ * the global zone means that we're done.
+ */
+ if (zoneid == GLOBAL_ZONEID &&
+ zfs_prop_get_int(handles[i], ZFS_PROP_ZONED))
+ break;
+ zfs_dispatch_mount(hdl, handles, num_handles, i, func, data,
+ tp);
+ }
+
+ tpool_wait(tp); /* wait for all scheduled mounts to complete */
+ tpool_destroy(tp);
+}
+
+/*
+ * Mount and share all datasets within the given pool. This assumes that no
+ * datasets within the pool are currently mounted.
+ */
+#pragma weak zpool_mount_datasets = zpool_enable_datasets
+int
+zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
+{
+ get_all_cb_t cb = { 0 };
+ mount_state_t ms = { 0 };
+ zfs_handle_t *zfsp;
+ int ret = 0;
+
+ if ((zfsp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
+ ZFS_TYPE_DATASET)) == NULL)
+ goto out;
+
+ /*
+ * Gather all non-snapshot datasets within the pool. Start by adding
+ * the root filesystem for this pool to the list, and then iterate
+ * over all child filesystems.
+ */
+ libzfs_add_handle(&cb, zfsp);
+ if (zfs_iter_filesystems(zfsp, zfs_iter_cb, &cb) != 0)
+ goto out;
+
+ /*
+ * Mount all filesystems
+ */
+ ms.ms_mntopts = mntopts;
+ ms.ms_mntflags = flags;
+ zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
+ zfs_mount_one, &ms, B_TRUE);
+ if (ms.ms_mntstatus != 0)
+ ret = ms.ms_mntstatus;
+
+ /*
+ * Share all filesystems that need to be shared. This needs to be
+ * a separate pass because libshare is not mt-safe, and so we need
+ * to share serially.
+ */
+ ms.ms_mntstatus = 0;
+ zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
+ zfs_share_one, &ms, B_FALSE);
+ if (ms.ms_mntstatus != 0)
+ ret = ms.ms_mntstatus;
+
+out:
+ for (int i = 0; i < cb.cb_used; i++)
+ zfs_close(cb.cb_handles[i]);
+ free(cb.cb_handles);
+
+ return (ret);
+}
+
+static int
+mountpoint_compare(const void *a, const void *b)
+{
+ const char *mounta = *((char **)a);
+ const char *mountb = *((char **)b);
+
+ return (strcmp(mountb, mounta));
+}
+
+/* alias for 2002/240 */
+#pragma weak zpool_unmount_datasets = zpool_disable_datasets
+/*
+ * Unshare and unmount all datasets within the given pool. We don't want to
+ * rely on traversing the DSL to discover the filesystems within the pool,
+ * because this may be expensive (if not all of them are mounted), and can fail
+ * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and
+ * gather all the filesystems that are currently mounted.
+ */
+int
+zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
+{
+ int used, alloc;
+ struct mnttab entry;
+ size_t namelen;
+ char **mountpoints = NULL;
+ zfs_handle_t **datasets = NULL;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ int i;
+ int ret = -1;
+ int flags = (force ? MS_FORCE : 0);
+#ifdef illumos
+ sa_init_selective_arg_t sharearg;
+#endif
+
+ namelen = strlen(zhp->zpool_name);
+
+ rewind(hdl->libzfs_mnttab);
+ used = alloc = 0;
+ while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
+ /*
+ * Ignore non-ZFS entries.
+ */
+ if (entry.mnt_fstype == NULL ||
+ strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
+ continue;
+
+ /*
+ * Ignore filesystems not within this pool.
+ */
+ if (entry.mnt_mountp == NULL ||
+ strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 ||
+ (entry.mnt_special[namelen] != '/' &&
+ entry.mnt_special[namelen] != '\0'))
+ continue;
+
+ /*
+ * At this point we've found a filesystem within our pool. Add
+ * it to our growing list.
+ */
+ if (used == alloc) {
+ if (alloc == 0) {
+ if ((mountpoints = zfs_alloc(hdl,
+ 8 * sizeof (void *))) == NULL)
+ goto out;
+
+ if ((datasets = zfs_alloc(hdl,
+ 8 * sizeof (void *))) == NULL)
+ goto out;
+
+ alloc = 8;
+ } else {
+ void *ptr;
+
+ if ((ptr = zfs_realloc(hdl, mountpoints,
+ alloc * sizeof (void *),
+ alloc * 2 * sizeof (void *))) == NULL)
+ goto out;
+ mountpoints = ptr;
+
+ if ((ptr = zfs_realloc(hdl, datasets,
+ alloc * sizeof (void *),
+ alloc * 2 * sizeof (void *))) == NULL)
+ goto out;
+ datasets = ptr;
+
+ alloc *= 2;
+ }
+ }
+
+ if ((mountpoints[used] = zfs_strdup(hdl,
+ entry.mnt_mountp)) == NULL)
+ goto out;
+
+ /*
+ * This is allowed to fail, in case there is some I/O error. It
+ * is only used to determine if we need to remove the underlying
+ * mountpoint, so failure is not fatal.
+ */
+ datasets[used] = make_dataset_handle(hdl, entry.mnt_special);
+
+ used++;
+ }
+
+ /*
+ * At this point, we have the entire list of filesystems, so sort it by
+ * mountpoint.
+ */
+#ifdef illumos
+ sharearg.zhandle_arr = datasets;
+ sharearg.zhandle_len = used;
+ ret = zfs_init_libshare_arg(hdl, SA_INIT_SHARE_API_SELECTIVE,
+ &sharearg);
+ if (ret != 0)
+ goto out;
+#endif
+ qsort(mountpoints, used, sizeof (char *), mountpoint_compare);
+
+ /*
+ * Walk through and first unshare everything.
+ */
+ for (i = 0; i < used; i++) {
+ zfs_share_proto_t *curr_proto;
+ for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+ curr_proto++) {
+ if (is_shared(hdl, mountpoints[i], *curr_proto) &&
+ unshare_one(hdl, mountpoints[i],
+ mountpoints[i], *curr_proto) != 0)
+ goto out;
+ }
+ }
+
+ /*
+ * Now unmount everything, removing the underlying directories as
+ * appropriate.
+ */
+ for (i = 0; i < used; i++) {
+ if (unmount_one(hdl, mountpoints[i], flags) != 0)
+ goto out;
+ }
+
+ for (i = 0; i < used; i++) {
+ if (datasets[i])
+ remove_mountpoint(datasets[i]);
+ }
+
+ ret = 0;
+out:
+ for (i = 0; i < used; i++) {
+ if (datasets[i])
+ zfs_close(datasets[i]);
+ free(mountpoints[i]);
+ }
+ free(datasets);
+ free(mountpoints);
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
new file mode 100644
index 000000000000..c2dac2362f10
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
@@ -0,0 +1,4631 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
+ * Copyright (c) 2017 Datto Inc.
+ * Copyright (c) 2017, Intel Corporation.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <devid.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <sys/zfs_ioctl.h>
+#include <dlfcn.h>
+
+#include "zfs_namecheck.h"
+#include "zfs_prop.h"
+#include "libzfs_impl.h"
+#include "zfs_comutil.h"
+#include "zfeature_common.h"
+
+static int read_efi_label(nvlist_t *, diskaddr_t *, boolean_t *);
+static boolean_t zpool_vdev_is_interior(const char *name);
+
+#define BACKUP_SLICE "s2"
+
+typedef struct prop_flags {
+ int create:1; /* Validate property on creation */
+ int import:1; /* Validate property on import */
+} prop_flags_t;
+
+/*
+ * ====================================================================
+ * zpool property functions
+ * ====================================================================
+ */
+
+static int
+zpool_get_all_props(zpool_handle_t *zhp)
+{
+ zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
+ return (-1);
+
+ while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
+ if (errno == ENOMEM) {
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ } else {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ }
+
+ if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+
+ zcmd_free_nvlists(&zc);
+
+ return (0);
+}
+
+static int
+zpool_props_refresh(zpool_handle_t *zhp)
+{
+ nvlist_t *old_props;
+
+ old_props = zhp->zpool_props;
+
+ if (zpool_get_all_props(zhp) != 0)
+ return (-1);
+
+ nvlist_free(old_props);
+ return (0);
+}
+
+static char *
+zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
+ zprop_source_t *src)
+{
+ nvlist_t *nv, *nvl;
+ uint64_t ival;
+ char *value;
+ zprop_source_t source;
+
+ nvl = zhp->zpool_props;
+ if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
+ verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
+ source = ival;
+ verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
+ } else {
+ source = ZPROP_SRC_DEFAULT;
+ if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
+ value = "-";
+ }
+
+ if (src)
+ *src = source;
+
+ return (value);
+}
+
+uint64_t
+zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
+{
+ nvlist_t *nv, *nvl;
+ uint64_t value;
+ zprop_source_t source;
+
+ if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
+ /*
+ * zpool_get_all_props() has most likely failed because
+ * the pool is faulted, but if all we need is the top level
+ * vdev's guid then get it from the zhp config nvlist.
+ */
+ if ((prop == ZPOOL_PROP_GUID) &&
+ (nvlist_lookup_nvlist(zhp->zpool_config,
+ ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
+ (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
+ == 0)) {
+ return (value);
+ }
+ return (zpool_prop_default_numeric(prop));
+ }
+
+ nvl = zhp->zpool_props;
+ if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
+ verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0);
+ source = value;
+ verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
+ } else {
+ source = ZPROP_SRC_DEFAULT;
+ value = zpool_prop_default_numeric(prop);
+ }
+
+ if (src)
+ *src = source;
+
+ return (value);
+}
+
+/*
+ * Map VDEV STATE to printed strings.
+ */
+const char *
+zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
+{
+ switch (state) {
+ case VDEV_STATE_CLOSED:
+ case VDEV_STATE_OFFLINE:
+ return (gettext("OFFLINE"));
+ case VDEV_STATE_REMOVED:
+ return (gettext("REMOVED"));
+ case VDEV_STATE_CANT_OPEN:
+ if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
+ return (gettext("FAULTED"));
+ else if (aux == VDEV_AUX_SPLIT_POOL)
+ return (gettext("SPLIT"));
+ else
+ return (gettext("UNAVAIL"));
+ case VDEV_STATE_FAULTED:
+ return (gettext("FAULTED"));
+ case VDEV_STATE_DEGRADED:
+ return (gettext("DEGRADED"));
+ case VDEV_STATE_HEALTHY:
+ return (gettext("ONLINE"));
+
+ default:
+ break;
+ }
+
+ return (gettext("UNKNOWN"));
+}
+
+/*
+ * Map POOL STATE to printed strings.
+ */
+const char *
+zpool_pool_state_to_name(pool_state_t state)
+{
+ switch (state) {
+ case POOL_STATE_ACTIVE:
+ return (gettext("ACTIVE"));
+ case POOL_STATE_EXPORTED:
+ return (gettext("EXPORTED"));
+ case POOL_STATE_DESTROYED:
+ return (gettext("DESTROYED"));
+ case POOL_STATE_SPARE:
+ return (gettext("SPARE"));
+ case POOL_STATE_L2CACHE:
+ return (gettext("L2CACHE"));
+ case POOL_STATE_UNINITIALIZED:
+ return (gettext("UNINITIALIZED"));
+ case POOL_STATE_UNAVAIL:
+ return (gettext("UNAVAIL"));
+ case POOL_STATE_POTENTIALLY_ACTIVE:
+ return (gettext("POTENTIALLY_ACTIVE"));
+ }
+
+ return (gettext("UNKNOWN"));
+}
+
+/*
+ * Get a zpool property value for 'prop' and return the value in
+ * a pre-allocated buffer.
+ */
+int
+zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
+ zprop_source_t *srctype, boolean_t literal)
+{
+ uint64_t intval;
+ const char *strval;
+ zprop_source_t src = ZPROP_SRC_NONE;
+ nvlist_t *nvroot;
+ vdev_stat_t *vs;
+ uint_t vsc;
+
+ if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
+ switch (prop) {
+ case ZPOOL_PROP_NAME:
+ (void) strlcpy(buf, zpool_get_name(zhp), len);
+ break;
+
+ case ZPOOL_PROP_HEALTH:
+ (void) strlcpy(buf,
+ zpool_pool_state_to_name(POOL_STATE_UNAVAIL), len);
+ break;
+
+ case ZPOOL_PROP_GUID:
+ intval = zpool_get_prop_int(zhp, prop, &src);
+ (void) snprintf(buf, len, "%llu", intval);
+ break;
+
+ case ZPOOL_PROP_ALTROOT:
+ case ZPOOL_PROP_CACHEFILE:
+ case ZPOOL_PROP_COMMENT:
+ if (zhp->zpool_props != NULL ||
+ zpool_get_all_props(zhp) == 0) {
+ (void) strlcpy(buf,
+ zpool_get_prop_string(zhp, prop, &src),
+ len);
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ (void) strlcpy(buf, "-", len);
+ break;
+ }
+
+ if (srctype != NULL)
+ *srctype = src;
+ return (0);
+ }
+
+ if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
+ prop != ZPOOL_PROP_NAME)
+ return (-1);
+
+ switch (zpool_prop_get_type(prop)) {
+ case PROP_TYPE_STRING:
+ (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
+ len);
+ break;
+
+ case PROP_TYPE_NUMBER:
+ intval = zpool_get_prop_int(zhp, prop, &src);
+
+ switch (prop) {
+ case ZPOOL_PROP_SIZE:
+ case ZPOOL_PROP_ALLOCATED:
+ case ZPOOL_PROP_FREE:
+ case ZPOOL_PROP_FREEING:
+ case ZPOOL_PROP_LEAKED:
+ if (literal) {
+ (void) snprintf(buf, len, "%llu",
+ (u_longlong_t)intval);
+ } else {
+ (void) zfs_nicenum(intval, buf, len);
+ }
+ break;
+ case ZPOOL_PROP_BOOTSIZE:
+ case ZPOOL_PROP_EXPANDSZ:
+ case ZPOOL_PROP_CHECKPOINT:
+ if (intval == 0) {
+ (void) strlcpy(buf, "-", len);
+ } else if (literal) {
+ (void) snprintf(buf, len, "%llu",
+ (u_longlong_t)intval);
+ } else {
+ (void) zfs_nicenum(intval, buf, len);
+ }
+ break;
+ case ZPOOL_PROP_CAPACITY:
+ if (literal) {
+ (void) snprintf(buf, len, "%llu",
+ (u_longlong_t)intval);
+ } else {
+ (void) snprintf(buf, len, "%llu%%",
+ (u_longlong_t)intval);
+ }
+ break;
+ case ZPOOL_PROP_FRAGMENTATION:
+ if (intval == UINT64_MAX) {
+ (void) strlcpy(buf, "-", len);
+ } else {
+ (void) snprintf(buf, len, "%llu%%",
+ (u_longlong_t)intval);
+ }
+ break;
+ case ZPOOL_PROP_DEDUPRATIO:
+ (void) snprintf(buf, len, "%llu.%02llux",
+ (u_longlong_t)(intval / 100),
+ (u_longlong_t)(intval % 100));
+ break;
+ case ZPOOL_PROP_HEALTH:
+ verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
+ ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+ verify(nvlist_lookup_uint64_array(nvroot,
+ ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
+ == 0);
+
+ (void) strlcpy(buf, zpool_state_to_name(intval,
+ vs->vs_aux), len);
+ break;
+ case ZPOOL_PROP_VERSION:
+ if (intval >= SPA_VERSION_FEATURES) {
+ (void) snprintf(buf, len, "-");
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ (void) snprintf(buf, len, "%llu", intval);
+ }
+ break;
+
+ case PROP_TYPE_INDEX:
+ intval = zpool_get_prop_int(zhp, prop, &src);
+ if (zpool_prop_index_to_string(prop, intval, &strval)
+ != 0)
+ return (-1);
+ (void) strlcpy(buf, strval, len);
+ break;
+
+ default:
+ abort();
+ }
+
+ if (srctype)
+ *srctype = src;
+
+ return (0);
+}
+
+/*
+ * Check if the bootfs name has the same pool name as it is set to.
+ * Assuming bootfs is a valid dataset name.
+ */
+static boolean_t
+bootfs_name_valid(const char *pool, char *bootfs)
+{
+ int len = strlen(pool);
+
+ if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
+ return (B_FALSE);
+
+ if (strncmp(pool, bootfs, len) == 0 &&
+ (bootfs[len] == '/' || bootfs[len] == '\0'))
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+boolean_t
+zpool_is_bootable(zpool_handle_t *zhp)
+{
+ char bootfs[ZFS_MAX_DATASET_NAME_LEN];
+
+ return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
+ sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
+ sizeof (bootfs)) != 0);
+}
+
+
+/*
+ * Given an nvlist of zpool properties to be set, validate that they are
+ * correct, and parse any numeric properties (index, boolean, etc) if they are
+ * specified as strings.
+ */
+static nvlist_t *
+zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
+ nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf)
+{
+ nvpair_t *elem;
+ nvlist_t *retprops;
+ zpool_prop_t prop;
+ char *strval;
+ uint64_t intval;
+ char *slash, *check;
+ struct stat64 statbuf;
+ zpool_handle_t *zhp;
+
+ if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
+ (void) no_memory(hdl);
+ return (NULL);
+ }
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
+ const char *propname = nvpair_name(elem);
+
+ prop = zpool_name_to_prop(propname);
+ if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
+ int err;
+ char *fname = strchr(propname, '@') + 1;
+
+ err = zfeature_lookup_name(fname, NULL);
+ if (err != 0) {
+ ASSERT3U(err, ==, ENOENT);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid feature '%s'"), fname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (nvpair_type(elem) != DATA_TYPE_STRING) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a string"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ (void) nvpair_value_string(elem, &strval);
+ if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' can only be set to "
+ "'enabled'"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (nvlist_add_uint64(retprops, propname, 0) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+ continue;
+ }
+
+ /*
+ * Make sure this property is valid and applies to this type.
+ */
+ if (prop == ZPOOL_PROP_INVAL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid property '%s'"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (zpool_prop_readonly(prop)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
+ "is readonly"), propname);
+ (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
+ goto error;
+ }
+
+ if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
+ &strval, &intval, errbuf) != 0)
+ goto error;
+
+ /*
+ * Perform additional checking for specific properties.
+ */
+ switch (prop) {
+ case ZPOOL_PROP_VERSION:
+ if (intval < version ||
+ !SPA_VERSION_IS_SUPPORTED(intval)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' number %d is invalid."),
+ propname, intval);
+ (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ goto error;
+ }
+ break;
+
+ case ZPOOL_PROP_BOOTSIZE:
+ if (!flags.create) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' can only be set during pool "
+ "creation"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+
+ case ZPOOL_PROP_BOOTFS:
+ if (flags.create || flags.import) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' cannot be set at creation "
+ "or import time"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (version < SPA_VERSION_BOOTFS) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded to support "
+ "'%s' property"), propname);
+ (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ goto error;
+ }
+
+ /*
+ * bootfs property value has to be a dataset name and
+ * the dataset has to be in the same pool as it sets to.
+ */
+ if (strval[0] != '\0' && !bootfs_name_valid(poolname,
+ strval)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
+ "is an invalid name"), strval);
+ (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
+ goto error;
+ }
+
+ if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "could not open pool '%s'"), poolname);
+ (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
+ goto error;
+ }
+ zpool_close(zhp);
+ break;
+
+ case ZPOOL_PROP_ALTROOT:
+ if (!flags.create && !flags.import) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' can only be set during pool "
+ "creation or import"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (strval[0] != '/') {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "bad alternate root '%s'"), strval);
+ (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
+ goto error;
+ }
+ break;
+
+ case ZPOOL_PROP_CACHEFILE:
+ if (strval[0] == '\0')
+ break;
+
+ if (strcmp(strval, "none") == 0)
+ break;
+
+ if (strval[0] != '/') {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' must be empty, an "
+ "absolute path, or 'none'"), propname);
+ (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
+ goto error;
+ }
+
+ slash = strrchr(strval, '/');
+
+ if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
+ strcmp(slash, "/..") == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is not a valid file"), strval);
+ (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
+ goto error;
+ }
+
+ *slash = '\0';
+
+ if (strval[0] != '\0' &&
+ (stat64(strval, &statbuf) != 0 ||
+ !S_ISDIR(statbuf.st_mode))) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is not a valid directory"),
+ strval);
+ (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
+ goto error;
+ }
+
+ *slash = '/';
+ break;
+
+ case ZPOOL_PROP_COMMENT:
+ for (check = strval; *check != '\0'; check++) {
+ if (!isprint(*check)) {
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN,
+ "comment may only have printable "
+ "characters"));
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+ }
+ if (strlen(strval) > ZPROP_MAX_COMMENT) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "comment must not exceed %d characters"),
+ ZPROP_MAX_COMMENT);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+
+ case ZPOOL_PROP_READONLY:
+ if (!flags.import) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' can only be set at "
+ "import time"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+
+ case ZPOOL_PROP_TNAME:
+ if (!flags.create) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' can only be set at "
+ "creation time"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+
+ case ZPOOL_PROP_MULTIHOST:
+ if (get_system_hostid() == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "requires a non-zero system hostid"));
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+
+ default:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s'(%d) not defined"), propname, prop);
+ break;
+ }
+ }
+
+ return (retprops);
+error:
+ nvlist_free(retprops);
+ return (NULL);
+}
+
+/*
+ * Set zpool property : propname=propval.
+ */
+int
+zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
+{
+ zfs_cmd_t zc = { 0 };
+ int ret = -1;
+ char errbuf[1024];
+ nvlist_t *nvl = NULL;
+ nvlist_t *realprops;
+ uint64_t version;
+ prop_flags_t flags = { 0 };
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
+ zhp->zpool_name);
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+ return (no_memory(zhp->zpool_hdl));
+
+ if (nvlist_add_string(nvl, propname, propval) != 0) {
+ nvlist_free(nvl);
+ return (no_memory(zhp->zpool_hdl));
+ }
+
+ version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
+ if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
+ zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) {
+ nvlist_free(nvl);
+ return (-1);
+ }
+
+ nvlist_free(nvl);
+ nvl = realprops;
+
+ /*
+ * Execute the corresponding ioctl() to set this property.
+ */
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+
+ if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
+ nvlist_free(nvl);
+ return (-1);
+ }
+
+ ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
+
+ zcmd_free_nvlists(&zc);
+ nvlist_free(nvl);
+
+ if (ret)
+ (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
+ else
+ (void) zpool_props_refresh(zhp);
+
+ return (ret);
+}
+
+int
+zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
+{
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ zprop_list_t *entry;
+ char buf[ZFS_MAXPROPLEN];
+ nvlist_t *features = NULL;
+ zprop_list_t **last;
+ boolean_t firstexpand = (NULL == *plp);
+
+ if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
+ return (-1);
+
+ last = plp;
+ while (*last != NULL)
+ last = &(*last)->pl_next;
+
+ if ((*plp)->pl_all)
+ features = zpool_get_features(zhp);
+
+ if ((*plp)->pl_all && firstexpand) {
+ for (int i = 0; i < SPA_FEATURES; i++) {
+ zprop_list_t *entry = zfs_alloc(hdl,
+ sizeof (zprop_list_t));
+ entry->pl_prop = ZPROP_INVAL;
+ entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s",
+ spa_feature_table[i].fi_uname);
+ entry->pl_width = strlen(entry->pl_user_prop);
+ entry->pl_all = B_TRUE;
+
+ *last = entry;
+ last = &entry->pl_next;
+ }
+ }
+
+ /* add any unsupported features */
+ for (nvpair_t *nvp = nvlist_next_nvpair(features, NULL);
+ nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) {
+ char *propname;
+ boolean_t found;
+ zprop_list_t *entry;
+
+ if (zfeature_is_supported(nvpair_name(nvp)))
+ continue;
+
+ propname = zfs_asprintf(hdl, "unsupported@%s",
+ nvpair_name(nvp));
+
+ /*
+ * Before adding the property to the list make sure that no
+ * other pool already added the same property.
+ */
+ found = B_FALSE;
+ entry = *plp;
+ while (entry != NULL) {
+ if (entry->pl_user_prop != NULL &&
+ strcmp(propname, entry->pl_user_prop) == 0) {
+ found = B_TRUE;
+ break;
+ }
+ entry = entry->pl_next;
+ }
+ if (found) {
+ free(propname);
+ continue;
+ }
+
+ entry = zfs_alloc(hdl, sizeof (zprop_list_t));
+ entry->pl_prop = ZPROP_INVAL;
+ entry->pl_user_prop = propname;
+ entry->pl_width = strlen(entry->pl_user_prop);
+ entry->pl_all = B_TRUE;
+
+ *last = entry;
+ last = &entry->pl_next;
+ }
+
+ for (entry = *plp; entry != NULL; entry = entry->pl_next) {
+
+ if (entry->pl_fixed)
+ continue;
+
+ if (entry->pl_prop != ZPROP_INVAL &&
+ zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
+ NULL, B_FALSE) == 0) {
+ if (strlen(buf) > entry->pl_width)
+ entry->pl_width = strlen(buf);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Get the state for the given feature on the given ZFS pool.
+ */
+int
+zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf,
+ size_t len)
+{
+ uint64_t refcount;
+ boolean_t found = B_FALSE;
+ nvlist_t *features = zpool_get_features(zhp);
+ boolean_t supported;
+ const char *feature = strchr(propname, '@') + 1;
+
+ supported = zpool_prop_feature(propname);
+ ASSERT(supported || zpool_prop_unsupported(propname));
+
+ /*
+ * Convert from feature name to feature guid. This conversion is
+ * unecessary for unsupported@... properties because they already
+ * use guids.
+ */
+ if (supported) {
+ int ret;
+ spa_feature_t fid;
+
+ ret = zfeature_lookup_name(feature, &fid);
+ if (ret != 0) {
+ (void) strlcpy(buf, "-", len);
+ return (ENOTSUP);
+ }
+ feature = spa_feature_table[fid].fi_guid;
+ }
+
+ if (nvlist_lookup_uint64(features, feature, &refcount) == 0)
+ found = B_TRUE;
+
+ if (supported) {
+ if (!found) {
+ (void) strlcpy(buf, ZFS_FEATURE_DISABLED, len);
+ } else {
+ if (refcount == 0)
+ (void) strlcpy(buf, ZFS_FEATURE_ENABLED, len);
+ else
+ (void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len);
+ }
+ } else {
+ if (found) {
+ if (refcount == 0) {
+ (void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE);
+ } else {
+ (void) strcpy(buf, ZFS_UNSUPPORTED_READONLY);
+ }
+ } else {
+ (void) strlcpy(buf, "-", len);
+ return (ENOTSUP);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Don't start the slice at the default block of 34; many storage
+ * devices will use a stripe width of 128k, so start there instead.
+ */
+#define NEW_START_BLOCK 256
+
+/*
+ * Validate the given pool name, optionally putting an extended error message in
+ * 'buf'.
+ */
+boolean_t
+zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
+{
+ namecheck_err_t why;
+ char what;
+ int ret;
+
+ ret = pool_namecheck(pool, &why, &what);
+
+ /*
+ * The rules for reserved pool names were extended at a later point.
+ * But we need to support users with existing pools that may now be
+ * invalid. So we only check for this expanded set of names during a
+ * create (or import), and only in userland.
+ */
+ if (ret == 0 && !isopen &&
+ (strncmp(pool, "mirror", 6) == 0 ||
+ strncmp(pool, "raidz", 5) == 0 ||
+ strncmp(pool, "spare", 5) == 0 ||
+ strcmp(pool, "log") == 0)) {
+ if (hdl != NULL)
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "name is reserved"));
+ return (B_FALSE);
+ }
+
+
+ if (ret != 0) {
+ if (hdl != NULL) {
+ switch (why) {
+ case NAME_ERR_TOOLONG:
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "name is too long"));
+ break;
+
+ case NAME_ERR_INVALCHAR:
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "invalid character "
+ "'%c' in pool name"), what);
+ break;
+
+ case NAME_ERR_NOLETTER:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "name must begin with a letter"));
+ break;
+
+ case NAME_ERR_RESERVED:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "name is reserved"));
+ break;
+
+ case NAME_ERR_DISKLIKE:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool name is reserved"));
+ break;
+
+ case NAME_ERR_LEADING_SLASH:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "leading slash in name"));
+ break;
+
+ case NAME_ERR_EMPTY_COMPONENT:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "empty component in name"));
+ break;
+
+ case NAME_ERR_TRAILING_SLASH:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "trailing slash in name"));
+ break;
+
+ case NAME_ERR_MULTIPLE_DELIMITERS:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "multiple '@' and/or '#' delimiters in "
+ "name"));
+ break;
+
+ default:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "(%d) not defined"), why);
+ break;
+ }
+ }
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * Open a handle to the given pool, even if the pool is currently in the FAULTED
+ * state.
+ */
+zpool_handle_t *
+zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
+{
+ zpool_handle_t *zhp;
+ boolean_t missing;
+
+ /*
+ * Make sure the pool name is valid.
+ */
+ if (!zpool_name_valid(hdl, B_TRUE, pool)) {
+ (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"),
+ pool);
+ return (NULL);
+ }
+
+ if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
+ return (NULL);
+
+ zhp->zpool_hdl = hdl;
+ (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
+
+ if (zpool_refresh_stats(zhp, &missing) != 0) {
+ zpool_close(zhp);
+ return (NULL);
+ }
+
+ if (missing) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool"));
+ (void) zfs_error_fmt(hdl, EZFS_NOENT,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool);
+ zpool_close(zhp);
+ return (NULL);
+ }
+
+ return (zhp);
+}
+
+/*
+ * Like the above, but silent on error. Used when iterating over pools (because
+ * the configuration cache may be out of date).
+ */
+int
+zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret)
+{
+ zpool_handle_t *zhp;
+ boolean_t missing;
+
+ if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
+ return (-1);
+
+ zhp->zpool_hdl = hdl;
+ (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
+
+ if (zpool_refresh_stats(zhp, &missing) != 0) {
+ zpool_close(zhp);
+ return (-1);
+ }
+
+ if (missing) {
+ zpool_close(zhp);
+ *ret = NULL;
+ return (0);
+ }
+
+ *ret = zhp;
+ return (0);
+}
+
+/*
+ * Similar to zpool_open_canfail(), but refuses to open pools in the faulted
+ * state.
+ */
+zpool_handle_t *
+zpool_open(libzfs_handle_t *hdl, const char *pool)
+{
+ zpool_handle_t *zhp;
+
+ if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
+ return (NULL);
+
+ if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
+ (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
+ zpool_close(zhp);
+ return (NULL);
+ }
+
+ return (zhp);
+}
+
+/*
+ * Close the handle. Simply frees the memory associated with the handle.
+ */
+void
+zpool_close(zpool_handle_t *zhp)
+{
+ nvlist_free(zhp->zpool_config);
+ nvlist_free(zhp->zpool_old_config);
+ nvlist_free(zhp->zpool_props);
+ free(zhp);
+}
+
+/*
+ * Return the name of the pool.
+ */
+const char *
+zpool_get_name(zpool_handle_t *zhp)
+{
+ return (zhp->zpool_name);
+}
+
+
+/*
+ * Return the state of the pool (ACTIVE or UNAVAILABLE)
+ */
+int
+zpool_get_state(zpool_handle_t *zhp)
+{
+ return (zhp->zpool_state);
+}
+
+/*
+ * Check if vdev list contains a special vdev
+ */
+static boolean_t
+zpool_has_special_vdev(nvlist_t *nvroot)
+{
+ nvlist_t **child;
+ uint_t children;
+
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, &child,
+ &children) == 0) {
+ for (uint_t c = 0; c < children; c++) {
+ char *bias;
+
+ if (nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, &bias) == 0 &&
+ strcmp(bias, VDEV_ALLOC_BIAS_SPECIAL) == 0) {
+ return (B_TRUE);
+ }
+ }
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Create the named pool, using the provided vdev list. It is assumed
+ * that the consumer has already validated the contents of the nvlist, so we
+ * don't have to worry about error semantics.
+ */
+int
+zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
+ nvlist_t *props, nvlist_t *fsprops)
+{
+ zfs_cmd_t zc = { 0 };
+ nvlist_t *zc_fsprops = NULL;
+ nvlist_t *zc_props = NULL;
+ char msg[1024];
+ int ret = -1;
+
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot create '%s'"), pool);
+
+ if (!zpool_name_valid(hdl, B_FALSE, pool))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
+
+ if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
+ return (-1);
+
+ if (props) {
+ prop_flags_t flags = { .create = B_TRUE, .import = B_FALSE };
+
+ if ((zc_props = zpool_valid_proplist(hdl, pool, props,
+ SPA_VERSION_1, flags, msg)) == NULL) {
+ goto create_failed;
+ }
+ }
+
+ if (fsprops) {
+ uint64_t zoned;
+ char *zonestr;
+
+ zoned = ((nvlist_lookup_string(fsprops,
+ zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
+ strcmp(zonestr, "on") == 0);
+
+ if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
+ fsprops, zoned, NULL, NULL, msg)) == NULL) {
+ goto create_failed;
+ }
+
+ if (nvlist_exists(zc_fsprops,
+ zfs_prop_to_name(ZFS_PROP_SPECIAL_SMALL_BLOCKS)) &&
+ !zpool_has_special_vdev(nvroot)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "%s property requires a special vdev"),
+ zfs_prop_to_name(ZFS_PROP_SPECIAL_SMALL_BLOCKS));
+ (void) zfs_error(hdl, EZFS_BADPROP, msg);
+ goto create_failed;
+ }
+
+ if (!zc_props &&
+ (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
+ goto create_failed;
+ }
+ if (nvlist_add_nvlist(zc_props,
+ ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
+ goto create_failed;
+ }
+ }
+
+ if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
+ goto create_failed;
+
+ (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
+
+ if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) {
+
+ zcmd_free_nvlists(&zc);
+ nvlist_free(zc_props);
+ nvlist_free(zc_fsprops);
+
+ switch (errno) {
+ case EBUSY:
+ /*
+ * This can happen if the user has specified the same
+ * device multiple times. We can't reliably detect this
+ * until we try to add it and see we already have a
+ * label.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more vdevs refer to the same device"));
+ return (zfs_error(hdl, EZFS_BADDEV, msg));
+
+ case ERANGE:
+ /*
+ * This happens if the record size is smaller or larger
+ * than the allowed size range, or not a power of 2.
+ *
+ * NOTE: although zfs_valid_proplist is called earlier,
+ * this case may have slipped through since the
+ * pool does not exist yet and it is therefore
+ * impossible to read properties e.g. max blocksize
+ * from the pool.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "record size invalid"));
+ return (zfs_error(hdl, EZFS_BADPROP, msg));
+
+ case EOVERFLOW:
+ /*
+ * This occurs when one of the devices is below
+ * SPA_MINDEVSIZE. Unfortunately, we can't detect which
+ * device was the problem device since there's no
+ * reliable way to determine device size from userland.
+ */
+ {
+ char buf[64];
+
+ zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
+
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more devices is less than the "
+ "minimum size (%s)"), buf);
+ }
+ return (zfs_error(hdl, EZFS_BADDEV, msg));
+
+ case ENOSPC:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more devices is out of space"));
+ return (zfs_error(hdl, EZFS_BADDEV, msg));
+
+ case ENOTBLK:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cache device must be a disk or disk slice"));
+ return (zfs_error(hdl, EZFS_BADDEV, msg));
+
+ default:
+ return (zpool_standard_error(hdl, errno, msg));
+ }
+ }
+
+create_failed:
+ zcmd_free_nvlists(&zc);
+ nvlist_free(zc_props);
+ nvlist_free(zc_fsprops);
+ return (ret);
+}
+
+/*
+ * Destroy the given pool. It is up to the caller to ensure that there are no
+ * datasets left in the pool.
+ */
+int
+zpool_destroy(zpool_handle_t *zhp, const char *log_str)
+{
+ zfs_cmd_t zc = { 0 };
+ zfs_handle_t *zfp = NULL;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ char msg[1024];
+
+ if (zhp->zpool_state == POOL_STATE_ACTIVE &&
+ (zfp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_FILESYSTEM)) == NULL)
+ return (-1);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_history = (uint64_t)(uintptr_t)log_str;
+
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot destroy '%s'"), zhp->zpool_name);
+
+ if (errno == EROFS) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more devices is read only"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ } else {
+ (void) zpool_standard_error(hdl, errno, msg);
+ }
+
+ if (zfp)
+ zfs_close(zfp);
+ return (-1);
+ }
+
+ if (zfp) {
+ remove_mountpoint(zfp);
+ zfs_close(zfp);
+ }
+
+ return (0);
+}
+
+/*
+ * Create a checkpoint in the given pool.
+ */
+int
+zpool_checkpoint(zpool_handle_t *zhp)
+{
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ char msg[1024];
+ int error;
+
+ error = lzc_pool_checkpoint(zhp->zpool_name);
+ if (error != 0) {
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot checkpoint '%s'"), zhp->zpool_name);
+ (void) zpool_standard_error(hdl, error, msg);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Discard the checkpoint from the given pool.
+ */
+int
+zpool_discard_checkpoint(zpool_handle_t *zhp)
+{
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ char msg[1024];
+ int error;
+
+ error = lzc_pool_checkpoint_discard(zhp->zpool_name);
+ if (error != 0) {
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot discard checkpoint in '%s'"), zhp->zpool_name);
+ (void) zpool_standard_error(hdl, error, msg);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Add the given vdevs to the pool. The caller must have already performed the
+ * necessary verification to ensure that the vdev specification is well-formed.
+ */
+int
+zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
+{
+ zfs_cmd_t zc = { 0 };
+ int ret;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ char msg[1024];
+ nvlist_t **spares, **l2cache;
+ uint_t nspares, nl2cache;
+
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot add to '%s'"), zhp->zpool_name);
+
+ if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
+ SPA_VERSION_SPARES &&
+ nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
+ "upgraded to add hot spares"));
+ return (zfs_error(hdl, EZFS_BADVERSION, msg));
+ }
+
+ if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
+ SPA_VERSION_L2CACHE &&
+ nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+ &l2cache, &nl2cache) == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
+ "upgraded to add cache devices"));
+ return (zfs_error(hdl, EZFS_BADVERSION, msg));
+ }
+
+ if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
+ return (-1);
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+
+ if (zfs_ioctl(hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
+ switch (errno) {
+ case EBUSY:
+ /*
+ * This can happen if the user has specified the same
+ * device multiple times. We can't reliably detect this
+ * until we try to add it and see we already have a
+ * label.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more vdevs refer to the same device"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ break;
+
+ case EINVAL:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid config; a pool with removing/removed "
+ "vdevs does not support adding raidz vdevs"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ break;
+
+ case EOVERFLOW:
+ /*
+ * This occurrs when one of the devices is below
+ * SPA_MINDEVSIZE. Unfortunately, we can't detect which
+ * device was the problem device since there's no
+ * reliable way to determine device size from userland.
+ */
+ {
+ char buf[64];
+
+ zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
+
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "device is less than the minimum "
+ "size (%s)"), buf);
+ }
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ break;
+
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded to add these vdevs"));
+ (void) zfs_error(hdl, EZFS_BADVERSION, msg);
+ break;
+
+ case EDOM:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "root pool can not have multiple vdevs"
+ " or separate logs"));
+ (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg);
+ break;
+
+ case ENOTBLK:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cache device must be a disk or disk slice"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ break;
+
+ default:
+ (void) zpool_standard_error(hdl, errno, msg);
+ }
+
+ ret = -1;
+ } else {
+ ret = 0;
+ }
+
+ zcmd_free_nvlists(&zc);
+
+ return (ret);
+}
+
+/*
+ * Exports the pool from the system. The caller must ensure that there are no
+ * mounted datasets in the pool.
+ */
+static int
+zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
+ const char *log_str)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot export '%s'"), zhp->zpool_name);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_cookie = force;
+ zc.zc_guid = hardforce;
+ zc.zc_history = (uint64_t)(uintptr_t)log_str;
+
+ if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
+ switch (errno) {
+ case EXDEV:
+ zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
+ "use '-f' to override the following errors:\n"
+ "'%s' has an active shared spare which could be"
+ " used by other pools once '%s' is exported."),
+ zhp->zpool_name, zhp->zpool_name);
+ return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
+ msg));
+ default:
+ return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
+ msg));
+ }
+ }
+
+ return (0);
+}
+
+int
+zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str)
+{
+ return (zpool_export_common(zhp, force, B_FALSE, log_str));
+}
+
+int
+zpool_export_force(zpool_handle_t *zhp, const char *log_str)
+{
+ return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str));
+}
+
+static void
+zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun,
+ nvlist_t *config)
+{
+ nvlist_t *nv = NULL;
+ uint64_t rewindto;
+ int64_t loss = -1;
+ struct tm t;
+ char timestr[128];
+
+ if (!hdl->libzfs_printerr || config == NULL)
+ return;
+
+ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
+ nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) {
+ return;
+ }
+
+ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
+ return;
+ (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
+
+ if (localtime_r((time_t *)&rewindto, &t) != NULL &&
+ strftime(timestr, 128, 0, &t) != 0) {
+ if (dryrun) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "Would be able to return %s "
+ "to its state as of %s.\n"),
+ name, timestr);
+ } else {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "Pool %s returned to its state as of %s.\n"),
+ name, timestr);
+ }
+ if (loss > 120) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "%s approximately %lld "),
+ dryrun ? "Would discard" : "Discarded",
+ (loss + 30) / 60);
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "minutes of transactions.\n"));
+ } else if (loss > 0) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "%s approximately %lld "),
+ dryrun ? "Would discard" : "Discarded", loss);
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "seconds of transactions.\n"));
+ }
+ }
+}
+
+void
+zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason,
+ nvlist_t *config)
+{
+ nvlist_t *nv = NULL;
+ int64_t loss = -1;
+ uint64_t edata = UINT64_MAX;
+ uint64_t rewindto;
+ struct tm t;
+ char timestr[128];
+
+ if (!hdl->libzfs_printerr)
+ return;
+
+ if (reason >= 0)
+ (void) printf(dgettext(TEXT_DOMAIN, "action: "));
+ else
+ (void) printf(dgettext(TEXT_DOMAIN, "\t"));
+
+ /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
+ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
+ nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 ||
+ nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
+ goto no_info;
+
+ (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
+ (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS,
+ &edata);
+
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "Recovery is possible, but will result in some data loss.\n"));
+
+ if (localtime_r((time_t *)&rewindto, &t) != NULL &&
+ strftime(timestr, 128, 0, &t) != 0) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "\tReturning the pool to its state as of %s\n"
+ "\tshould correct the problem. "),
+ timestr);
+ } else {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "\tReverting the pool to an earlier state "
+ "should correct the problem.\n\t"));
+ }
+
+ if (loss > 120) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "Approximately %lld minutes of data\n"
+ "\tmust be discarded, irreversibly. "), (loss + 30) / 60);
+ } else if (loss > 0) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "Approximately %lld seconds of data\n"
+ "\tmust be discarded, irreversibly. "), loss);
+ }
+ if (edata != 0 && edata != UINT64_MAX) {
+ if (edata == 1) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "After rewind, at least\n"
+ "\tone persistent user-data error will remain. "));
+ } else {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "After rewind, several\n"
+ "\tpersistent user-data errors will remain. "));
+ }
+ }
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "Recovery can be attempted\n\tby executing 'zpool %s -F %s'. "),
+ reason >= 0 ? "clear" : "import", name);
+
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "A scrub of the pool\n"
+ "\tis strongly recommended after recovery.\n"));
+ return;
+
+no_info:
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "Destroy and re-create the pool from\n\ta backup source.\n"));
+}
+
+/*
+ * zpool_import() is a contracted interface. Should be kept the same
+ * if possible.
+ *
+ * Applications should use zpool_import_props() to import a pool with
+ * new properties value to be set.
+ */
+int
+zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
+ char *altroot)
+{
+ nvlist_t *props = NULL;
+ int ret;
+
+ if (altroot != NULL) {
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
+ return (zfs_error_fmt(hdl, EZFS_NOMEM,
+ dgettext(TEXT_DOMAIN, "cannot import '%s'"),
+ newname));
+ }
+
+ if (nvlist_add_string(props,
+ zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 ||
+ nvlist_add_string(props,
+ zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) {
+ nvlist_free(props);
+ return (zfs_error_fmt(hdl, EZFS_NOMEM,
+ dgettext(TEXT_DOMAIN, "cannot import '%s'"),
+ newname));
+ }
+ }
+
+ ret = zpool_import_props(hdl, config, newname, props,
+ ZFS_IMPORT_NORMAL);
+ nvlist_free(props);
+ return (ret);
+}
+
+static void
+print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv,
+ int indent)
+{
+ nvlist_t **child;
+ uint_t c, children;
+ char *vname;
+ uint64_t is_log = 0;
+
+ (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG,
+ &is_log);
+
+ if (name != NULL)
+ (void) printf("\t%*s%s%s\n", indent, "", name,
+ is_log ? " [log]" : "");
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0)
+ return;
+
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(hdl, NULL, child[c], VDEV_NAME_TYPE_ID);
+ print_vdev_tree(hdl, vname, child[c], indent + 2);
+ free(vname);
+ }
+}
+
+void
+zpool_print_unsup_feat(nvlist_t *config)
+{
+ nvlist_t *nvinfo, *unsup_feat;
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) ==
+ 0);
+ verify(nvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT,
+ &unsup_feat) == 0);
+
+ for (nvpair_t *nvp = nvlist_next_nvpair(unsup_feat, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(unsup_feat, nvp)) {
+ char *desc;
+
+ verify(nvpair_type(nvp) == DATA_TYPE_STRING);
+ verify(nvpair_value_string(nvp, &desc) == 0);
+
+ if (strlen(desc) > 0)
+ (void) printf("\t%s (%s)\n", nvpair_name(nvp), desc);
+ else
+ (void) printf("\t%s\n", nvpair_name(nvp));
+ }
+}
+
+/*
+ * Import the given pool using the known configuration and a list of
+ * properties to be set. The configuration should have come from
+ * zpool_find_import(). The 'newname' parameters control whether the pool
+ * is imported with a different name.
+ */
+int
+zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
+ nvlist_t *props, int flags)
+{
+ zfs_cmd_t zc = { 0 };
+ zpool_load_policy_t policy;
+ nvlist_t *nv = NULL;
+ nvlist_t *nvinfo = NULL;
+ nvlist_t *missing = NULL;
+ char *thename;
+ char *origname;
+ int ret;
+ int error = 0;
+ char errbuf[1024];
+
+ verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+ &origname) == 0);
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot import pool '%s'"), origname);
+
+ if (newname != NULL) {
+ if (!zpool_name_valid(hdl, B_FALSE, newname))
+ return (zfs_error_fmt(hdl, EZFS_INVALIDNAME,
+ dgettext(TEXT_DOMAIN, "cannot import '%s'"),
+ newname));
+ thename = (char *)newname;
+ } else {
+ thename = origname;
+ }
+
+ if (props != NULL) {
+ uint64_t version;
+ prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE };
+
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+ &version) == 0);
+
+ if ((props = zpool_valid_proplist(hdl, origname,
+ props, version, flags, errbuf)) == NULL)
+ return (-1);
+ if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
+ nvlist_free(props);
+ return (-1);
+ }
+ nvlist_free(props);
+ }
+
+ (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
+
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+ &zc.zc_guid) == 0);
+
+ if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, zc.zc_nvlist_conf_size * 2) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+
+ zc.zc_cookie = flags;
+ while ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc)) != 0 &&
+ errno == ENOMEM) {
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ }
+ if (ret != 0)
+ error = errno;
+
+ (void) zcmd_read_dst_nvlist(hdl, &zc, &nv);
+
+ zcmd_free_nvlists(&zc);
+
+ zpool_get_load_policy(config, &policy);
+
+ if (error) {
+ char desc[1024];
+ char aux[256];
+
+ /*
+ * Dry-run failed, but we print out what success
+ * looks like if we found a best txg
+ */
+ if (policy.zlp_rewind & ZPOOL_TRY_REWIND) {
+ zpool_rewind_exclaim(hdl, newname ? origname : thename,
+ B_TRUE, nv);
+ nvlist_free(nv);
+ return (-1);
+ }
+
+ if (newname == NULL)
+ (void) snprintf(desc, sizeof (desc),
+ dgettext(TEXT_DOMAIN, "cannot import '%s'"),
+ thename);
+ else
+ (void) snprintf(desc, sizeof (desc),
+ dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
+ origname, thename);
+
+ switch (error) {
+ case ENOTSUP:
+ if (nv != NULL && nvlist_lookup_nvlist(nv,
+ ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
+ nvlist_exists(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT)) {
+ (void) printf(dgettext(TEXT_DOMAIN, "This "
+ "pool uses the following feature(s) not "
+ "supported by this system:\n"));
+ zpool_print_unsup_feat(nv);
+ if (nvlist_exists(nvinfo,
+ ZPOOL_CONFIG_CAN_RDONLY)) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "All unsupported features are only "
+ "required for writing to the pool."
+ "\nThe pool can be imported using "
+ "'-o readonly=on'.\n"));
+ }
+ }
+ /*
+ * Unsupported version.
+ */
+ (void) zfs_error(hdl, EZFS_BADVERSION, desc);
+ break;
+
+ case EREMOTEIO:
+ if (nv != NULL && nvlist_lookup_nvlist(nv,
+ ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0) {
+ char *hostname = "<unknown>";
+ uint64_t hostid = 0;
+ mmp_state_t mmp_state;
+
+ mmp_state = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_STATE);
+
+ if (nvlist_exists(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME))
+ hostname = fnvlist_lookup_string(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME);
+
+ if (nvlist_exists(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID))
+ hostid = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID);
+
+ if (mmp_state == MMP_STATE_ACTIVE) {
+ (void) snprintf(aux, sizeof (aux),
+ dgettext(TEXT_DOMAIN, "pool is imp"
+ "orted on host '%s' (hostid=%lx).\n"
+ "Export the pool on the other "
+ "system, then run 'zpool import'."),
+ hostname, (unsigned long) hostid);
+ } else if (mmp_state == MMP_STATE_NO_HOSTID) {
+ (void) snprintf(aux, sizeof (aux),
+ dgettext(TEXT_DOMAIN, "pool has "
+ "the multihost property on and "
+ "the\nsystem's hostid is not "
+ "set.\n"));
+ }
+
+ (void) zfs_error_aux(hdl, aux);
+ }
+ (void) zfs_error(hdl, EZFS_ACTIVE_POOL, desc);
+ break;
+
+ case EINVAL:
+ (void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
+ break;
+
+ case EROFS:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more devices is read only"));
+ (void) zfs_error(hdl, EZFS_BADDEV, desc);
+ break;
+
+ case ENXIO:
+ if (nv && nvlist_lookup_nvlist(nv,
+ ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
+ nvlist_lookup_nvlist(nvinfo,
+ ZPOOL_CONFIG_MISSING_DEVICES, &missing) == 0) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "The devices below are missing or "
+ "corrupted, use '-m' to import the pool "
+ "anyway:\n"));
+ print_vdev_tree(hdl, NULL, missing, 2);
+ (void) printf("\n");
+ }
+ (void) zpool_standard_error(hdl, error, desc);
+ break;
+
+ case EEXIST:
+ (void) zpool_standard_error(hdl, error, desc);
+ break;
+ case ENAMETOOLONG:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "new name of at least one dataset is longer than "
+ "the maximum allowable length"));
+ (void) zfs_error(hdl, EZFS_NAMETOOLONG, desc);
+ break;
+ default:
+ (void) zpool_standard_error(hdl, error, desc);
+ zpool_explain_recover(hdl,
+ newname ? origname : thename, -error, nv);
+ break;
+ }
+
+ nvlist_free(nv);
+ ret = -1;
+ } else {
+ zpool_handle_t *zhp;
+
+ /*
+ * This should never fail, but play it safe anyway.
+ */
+ if (zpool_open_silent(hdl, thename, &zhp) != 0)
+ ret = -1;
+ else if (zhp != NULL)
+ zpool_close(zhp);
+ if (policy.zlp_rewind &
+ (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
+ zpool_rewind_exclaim(hdl, newname ? origname : thename,
+ ((policy.zlp_rewind & ZPOOL_TRY_REWIND) != 0), nv);
+ }
+ nvlist_free(nv);
+ return (0);
+ }
+
+ return (ret);
+}
+
+/*
+ * Scan the pool.
+ */
+int
+zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ int err;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_cookie = func;
+ zc.zc_flags = cmd;
+
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_SCAN, &zc) == 0)
+ return (0);
+
+ err = errno;
+
+ /* ECANCELED on a scrub means we resumed a paused scrub */
+ if (err == ECANCELED && func == POOL_SCAN_SCRUB &&
+ cmd == POOL_SCRUB_NORMAL)
+ return (0);
+
+ if (err == ENOENT && func != POOL_SCAN_NONE && cmd == POOL_SCRUB_NORMAL)
+ return (0);
+
+ if (func == POOL_SCAN_SCRUB) {
+ if (cmd == POOL_SCRUB_PAUSE) {
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot pause scrubbing %s"), zc.zc_name);
+ } else {
+ assert(cmd == POOL_SCRUB_NORMAL);
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot scrub %s"), zc.zc_name);
+ }
+ } else if (func == POOL_SCAN_NONE) {
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot cancel scrubbing %s"),
+ zc.zc_name);
+ } else {
+ assert(!"unexpected result");
+ }
+
+ if (err == EBUSY) {
+ nvlist_t *nvroot;
+ pool_scan_stat_t *ps = NULL;
+ uint_t psc;
+
+ verify(nvlist_lookup_nvlist(zhp->zpool_config,
+ ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+ (void) nvlist_lookup_uint64_array(nvroot,
+ ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &psc);
+ if (ps && ps->pss_func == POOL_SCAN_SCRUB) {
+ if (cmd == POOL_SCRUB_PAUSE)
+ return (zfs_error(hdl, EZFS_SCRUB_PAUSED, msg));
+ else
+ return (zfs_error(hdl, EZFS_SCRUBBING, msg));
+ } else {
+ return (zfs_error(hdl, EZFS_RESILVERING, msg));
+ }
+ } else if (err == ENOENT) {
+ return (zfs_error(hdl, EZFS_NO_SCRUB, msg));
+ } else {
+ return (zpool_standard_error(hdl, err, msg));
+ }
+}
+
+static int
+xlate_init_err(int err)
+{
+ switch (err) {
+ case ENODEV:
+ return (EZFS_NODEVICE);
+ case EINVAL:
+ case EROFS:
+ return (EZFS_BADDEV);
+ case EBUSY:
+ return (EZFS_INITIALIZING);
+ case ESRCH:
+ return (EZFS_NO_INITIALIZE);
+ }
+ return (err);
+}
+
+/*
+ * Begin, suspend, or cancel the initialization (initializing of all free
+ * blocks) for the given vdevs in the given pool.
+ */
+int
+zpool_initialize(zpool_handle_t *zhp, pool_initialize_func_t cmd_type,
+ nvlist_t *vds)
+{
+ char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ nvlist_t *errlist;
+
+ /* translate vdev names to guids */
+ nvlist_t *vdev_guids = fnvlist_alloc();
+ nvlist_t *guids_to_paths = fnvlist_alloc();
+ boolean_t spare, cache;
+ nvlist_t *tgt;
+ nvpair_t *elem;
+
+ for (elem = nvlist_next_nvpair(vds, NULL); elem != NULL;
+ elem = nvlist_next_nvpair(vds, elem)) {
+ char *vd_path = nvpair_name(elem);
+ tgt = zpool_find_vdev(zhp, vd_path, &spare, &cache, NULL);
+
+ if ((tgt == NULL) || cache || spare) {
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot initialize '%s'"),
+ vd_path);
+ int err = (tgt == NULL) ? EZFS_NODEVICE :
+ (spare ? EZFS_ISSPARE : EZFS_ISL2CACHE);
+ fnvlist_free(vdev_guids);
+ fnvlist_free(guids_to_paths);
+ return (zfs_error(hdl, err, msg));
+ }
+
+ uint64_t guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID);
+ fnvlist_add_uint64(vdev_guids, vd_path, guid);
+
+ (void) snprintf(msg, sizeof (msg), "%llu", guid);
+ fnvlist_add_string(guids_to_paths, msg, vd_path);
+ }
+
+ int err = lzc_initialize(zhp->zpool_name, cmd_type, vdev_guids,
+ &errlist);
+ fnvlist_free(vdev_guids);
+
+ if (err == 0) {
+ fnvlist_free(guids_to_paths);
+ return (0);
+ }
+
+ nvlist_t *vd_errlist = NULL;
+ if (errlist != NULL) {
+ vd_errlist = fnvlist_lookup_nvlist(errlist,
+ ZPOOL_INITIALIZE_VDEVS);
+ }
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "operation failed"));
+
+ for (elem = nvlist_next_nvpair(vd_errlist, NULL); elem != NULL;
+ elem = nvlist_next_nvpair(vd_errlist, elem)) {
+ int64_t vd_error = xlate_init_err(fnvpair_value_int64(elem));
+ char *path = fnvlist_lookup_string(guids_to_paths,
+ nvpair_name(elem));
+ (void) zfs_error_fmt(hdl, vd_error, "cannot initialize '%s'",
+ path);
+ }
+
+ fnvlist_free(guids_to_paths);
+ if (vd_errlist != NULL)
+ return (-1);
+
+ return (zpool_standard_error(hdl, err, msg));
+}
+
+#ifdef illumos
+/*
+ * This provides a very minimal check whether a given string is likely a
+ * c#t#d# style string. Users of this are expected to do their own
+ * verification of the s# part.
+ */
+#define CTD_CHECK(str) (str && str[0] == 'c' && isdigit(str[1]))
+
+/*
+ * More elaborate version for ones which may start with "/dev/dsk/"
+ * and the like.
+ */
+static int
+ctd_check_path(char *str)
+{
+ /*
+ * If it starts with a slash, check the last component.
+ */
+ if (str && str[0] == '/') {
+ char *tmp = strrchr(str, '/');
+
+ /*
+ * If it ends in "/old", check the second-to-last
+ * component of the string instead.
+ */
+ if (tmp != str && strcmp(tmp, "/old") == 0) {
+ for (tmp--; *tmp != '/'; tmp--)
+ ;
+ }
+ str = tmp + 1;
+ }
+ return (CTD_CHECK(str));
+}
+#endif
+
+/*
+ * Find a vdev that matches the search criteria specified. We use the
+ * the nvpair name to determine how we should look for the device.
+ * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
+ * spare; but FALSE if its an INUSE spare.
+ */
+static nvlist_t *
+vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
+ boolean_t *l2cache, boolean_t *log)
+{
+ uint_t c, children;
+ nvlist_t **child;
+ nvlist_t *ret;
+ uint64_t is_log;
+ char *srchkey;
+ nvpair_t *pair = nvlist_next_nvpair(search, NULL);
+
+ /* Nothing to look for */
+ if (search == NULL || pair == NULL)
+ return (NULL);
+
+ /* Obtain the key we will use to search */
+ srchkey = nvpair_name(pair);
+
+ switch (nvpair_type(pair)) {
+ case DATA_TYPE_UINT64:
+ if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) {
+ uint64_t srchval, theguid;
+
+ verify(nvpair_value_uint64(pair, &srchval) == 0);
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
+ &theguid) == 0);
+ if (theguid == srchval)
+ return (nv);
+ }
+ break;
+
+ case DATA_TYPE_STRING: {
+ char *srchval, *val;
+
+ verify(nvpair_value_string(pair, &srchval) == 0);
+ if (nvlist_lookup_string(nv, srchkey, &val) != 0)
+ break;
+
+ /*
+ * Search for the requested value. Special cases:
+ *
+ * - ZPOOL_CONFIG_PATH for whole disk entries. To support
+ * UEFI boot, these end in "s0" or "s0/old" or "s1" or
+ * "s1/old". The "s0" or "s1" part is hidden from the user,
+ * but included in the string, so this matches around it.
+ * - looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE).
+ *
+ * Otherwise, all other searches are simple string compares.
+ */
+#ifdef illumos
+ if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 &&
+ ctd_check_path(val)) {
+ uint64_t wholedisk = 0;
+
+ (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
+ &wholedisk);
+ if (wholedisk) {
+ int slen = strlen(srchval);
+ int vlen = strlen(val);
+
+ if (slen != vlen - 2)
+ break;
+
+ /*
+ * make_leaf_vdev() should only set
+ * wholedisk for ZPOOL_CONFIG_PATHs which
+ * will include "/dev/dsk/", giving plenty of
+ * room for the indices used next.
+ */
+ ASSERT(vlen >= 6);
+
+ /*
+ * strings identical except trailing "s0"
+ */
+ if ((strcmp(&val[vlen - 2], "s0") == 0 ||
+ strcmp(&val[vlen - 2], "s1") == 0) &&
+ strncmp(srchval, val, slen) == 0)
+ return (nv);
+
+ /*
+ * strings identical except trailing "s0/old"
+ */
+ if ((strcmp(&val[vlen - 6], "s0/old") == 0 ||
+ strcmp(&val[vlen - 6], "s1/old") == 0) &&
+ strcmp(&srchval[slen - 4], "/old") == 0 &&
+ strncmp(srchval, val, slen - 4) == 0)
+ return (nv);
+
+ break;
+ }
+ } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) {
+#else
+ if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) {
+#endif
+ char *type, *idx, *end, *p;
+ uint64_t id, vdev_id;
+
+ /*
+ * Determine our vdev type, keeping in mind
+ * that the srchval is composed of a type and
+ * vdev id pair (i.e. mirror-4).
+ */
+ if ((type = strdup(srchval)) == NULL)
+ return (NULL);
+
+ if ((p = strrchr(type, '-')) == NULL) {
+ free(type);
+ break;
+ }
+ idx = p + 1;
+ *p = '\0';
+
+ /*
+ * If the types don't match then keep looking.
+ */
+ if (strncmp(val, type, strlen(val)) != 0) {
+ free(type);
+ break;
+ }
+
+ verify(zpool_vdev_is_interior(type));
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
+ &id) == 0);
+
+ errno = 0;
+ vdev_id = strtoull(idx, &end, 10);
+
+ free(type);
+ if (errno != 0)
+ return (NULL);
+
+ /*
+ * Now verify that we have the correct vdev id.
+ */
+ if (vdev_id == id)
+ return (nv);
+ }
+
+ /*
+ * Common case
+ */
+ if (strcmp(srchval, val) == 0)
+ return (nv);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0)
+ return (NULL);
+
+ for (c = 0; c < children; c++) {
+ if ((ret = vdev_to_nvlist_iter(child[c], search,
+ avail_spare, l2cache, NULL)) != NULL) {
+ /*
+ * The 'is_log' value is only set for the toplevel
+ * vdev, not the leaf vdevs. So we always lookup the
+ * log device from the root of the vdev tree (where
+ * 'log' is non-NULL).
+ */
+ if (log != NULL &&
+ nvlist_lookup_uint64(child[c],
+ ZPOOL_CONFIG_IS_LOG, &is_log) == 0 &&
+ is_log) {
+ *log = B_TRUE;
+ }
+ return (ret);
+ }
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++) {
+ if ((ret = vdev_to_nvlist_iter(child[c], search,
+ avail_spare, l2cache, NULL)) != NULL) {
+ *avail_spare = B_TRUE;
+ return (ret);
+ }
+ }
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++) {
+ if ((ret = vdev_to_nvlist_iter(child[c], search,
+ avail_spare, l2cache, NULL)) != NULL) {
+ *l2cache = B_TRUE;
+ return (ret);
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * Given a physical path (minus the "/devices" prefix), find the
+ * associated vdev.
+ */
+nvlist_t *
+zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath,
+ boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log)
+{
+ nvlist_t *search, *nvroot, *ret;
+
+ verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+ verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0);
+
+ verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+
+ *avail_spare = B_FALSE;
+ *l2cache = B_FALSE;
+ if (log != NULL)
+ *log = B_FALSE;
+ ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
+ nvlist_free(search);
+
+ return (ret);
+}
+
+/*
+ * Determine if we have an "interior" top-level vdev (i.e mirror/raidz).
+ */
+static boolean_t
+zpool_vdev_is_interior(const char *name)
+{
+ if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 ||
+ strncmp(name, VDEV_TYPE_SPARE, strlen(VDEV_TYPE_SPARE)) == 0 ||
+ strncmp(name,
+ VDEV_TYPE_REPLACING, strlen(VDEV_TYPE_REPLACING)) == 0 ||
+ strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0)
+ return (B_TRUE);
+ return (B_FALSE);
+}
+
+nvlist_t *
+zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
+ boolean_t *l2cache, boolean_t *log)
+{
+ char buf[MAXPATHLEN];
+ char *end;
+ nvlist_t *nvroot, *search, *ret;
+ uint64_t guid;
+
+ verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+ guid = strtoull(path, &end, 10);
+ if (guid != 0 && *end == '\0') {
+ verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0);
+ } else if (zpool_vdev_is_interior(path)) {
+ verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0);
+ } else if (path[0] != '/') {
+ (void) snprintf(buf, sizeof (buf), "%s%s", _PATH_DEV, path);
+ verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0);
+ } else {
+ verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0);
+ }
+
+ verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+
+ *avail_spare = B_FALSE;
+ *l2cache = B_FALSE;
+ if (log != NULL)
+ *log = B_FALSE;
+ ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
+ nvlist_free(search);
+
+ return (ret);
+}
+
+static int
+vdev_is_online(nvlist_t *nv)
+{
+ uint64_t ival;
+
+ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 ||
+ nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 ||
+ nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * Helper function for zpool_get_physpaths().
+ */
+static int
+vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size,
+ size_t *bytes_written)
+{
+ size_t bytes_left, pos, rsz;
+ char *tmppath;
+ const char *format;
+
+ if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH,
+ &tmppath) != 0)
+ return (EZFS_NODEVICE);
+
+ pos = *bytes_written;
+ bytes_left = physpath_size - pos;
+ format = (pos == 0) ? "%s" : " %s";
+
+ rsz = snprintf(physpath + pos, bytes_left, format, tmppath);
+ *bytes_written += rsz;
+
+ if (rsz >= bytes_left) {
+ /* if physpath was not copied properly, clear it */
+ if (bytes_left != 0) {
+ physpath[pos] = 0;
+ }
+ return (EZFS_NOSPC);
+ }
+ return (0);
+}
+
+static int
+vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size,
+ size_t *rsz, boolean_t is_spare)
+{
+ char *type;
+ int ret;
+
+ if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
+ return (EZFS_INVALCONFIG);
+
+ if (strcmp(type, VDEV_TYPE_DISK) == 0) {
+ /*
+ * An active spare device has ZPOOL_CONFIG_IS_SPARE set.
+ * For a spare vdev, we only want to boot from the active
+ * spare device.
+ */
+ if (is_spare) {
+ uint64_t spare = 0;
+ (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE,
+ &spare);
+ if (!spare)
+ return (EZFS_INVALCONFIG);
+ }
+
+ if (vdev_is_online(nv)) {
+ if ((ret = vdev_get_one_physpath(nv, physpath,
+ phypath_size, rsz)) != 0)
+ return (ret);
+ }
+ } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 ||
+ strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
+ strcmp(type, VDEV_TYPE_REPLACING) == 0 ||
+ (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) {
+ nvlist_t **child;
+ uint_t count;
+ int i, ret;
+
+ if (nvlist_lookup_nvlist_array(nv,
+ ZPOOL_CONFIG_CHILDREN, &child, &count) != 0)
+ return (EZFS_INVALCONFIG);
+
+ for (i = 0; i < count; i++) {
+ ret = vdev_get_physpaths(child[i], physpath,
+ phypath_size, rsz, is_spare);
+ if (ret == EZFS_NOSPC)
+ return (ret);
+ }
+ }
+
+ return (EZFS_POOL_INVALARG);
+}
+
+/*
+ * Get phys_path for a root pool config.
+ * Return 0 on success; non-zero on failure.
+ */
+static int
+zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size)
+{
+ size_t rsz;
+ nvlist_t *vdev_root;
+ nvlist_t **child;
+ uint_t count;
+ char *type;
+
+ rsz = 0;
+
+ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &vdev_root) != 0)
+ return (EZFS_INVALCONFIG);
+
+ if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 ||
+ nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN,
+ &child, &count) != 0)
+ return (EZFS_INVALCONFIG);
+
+ /*
+ * root pool can only have a single top-level vdev.
+ */
+ if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1)
+ return (EZFS_POOL_INVALARG);
+
+ (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
+ B_FALSE);
+
+ /* No online devices */
+ if (rsz == 0)
+ return (EZFS_NODEVICE);
+
+ return (0);
+}
+
+/*
+ * Get phys_path for a root pool
+ * Return 0 on success; non-zero on failure.
+ */
+int
+zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size)
+{
+ return (zpool_get_config_physpath(zhp->zpool_config, physpath,
+ phypath_size));
+}
+
+/*
+ * If the device has being dynamically expanded then we need to relabel
+ * the disk to use the new unallocated space.
+ */
+static int
+zpool_relabel_disk(libzfs_handle_t *hdl, const char *name)
+{
+#ifdef illumos
+ char path[MAXPATHLEN];
+ char errbuf[1024];
+ int fd, error;
+ int (*_efi_use_whole_disk)(int);
+
+ if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT,
+ "efi_use_whole_disk")) == NULL)
+ return (-1);
+
+ (void) snprintf(path, sizeof (path), "%s/%s", ZFS_RDISK_ROOT, name);
+
+ if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
+ "relabel '%s': unable to open device"), name);
+ return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
+ }
+
+ /*
+ * It's possible that we might encounter an error if the device
+ * does not have any unallocated space left. If so, we simply
+ * ignore that error and continue on.
+ */
+ error = _efi_use_whole_disk(fd);
+ (void) close(fd);
+ if (error && error != VT_ENOSPC) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
+ "relabel '%s': unable to read disk capacity"), name);
+ return (zfs_error(hdl, EZFS_NOCAP, errbuf));
+ }
+#endif /* illumos */
+ return (0);
+}
+
+/*
+ * Bring the specified vdev online. The 'flags' parameter is a set of the
+ * ZFS_ONLINE_* flags.
+ */
+int
+zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
+ vdev_state_t *newstate)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ char *pathname;
+ nvlist_t *tgt;
+ boolean_t avail_spare, l2cache, islog;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ if (flags & ZFS_ONLINE_EXPAND) {
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot expand %s"), path);
+ } else {
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot online %s"), path);
+ }
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
+ &islog)) == NULL)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+
+ if (avail_spare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+ if ((flags & ZFS_ONLINE_EXPAND ||
+ zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) &&
+ nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &pathname) == 0) {
+ uint64_t wholedisk = 0;
+
+ (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
+ &wholedisk);
+
+ /*
+ * XXX - L2ARC 1.0 devices can't support expansion.
+ */
+ if (l2cache) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cannot expand cache devices"));
+ return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg));
+ }
+
+ if (wholedisk) {
+ pathname += strlen(ZFS_DISK_ROOT) + 1;
+ (void) zpool_relabel_disk(hdl, pathname);
+ }
+ }
+
+ zc.zc_cookie = VDEV_STATE_ONLINE;
+ zc.zc_obj = flags;
+
+ if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) {
+ if (errno == EINVAL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "was split "
+ "from this pool into a new one. Use '%s' "
+ "instead"), "zpool detach");
+ return (zfs_error(hdl, EZFS_POSTSPLIT_ONLINE, msg));
+ }
+ return (zpool_standard_error(hdl, errno, msg));
+ }
+
+ *newstate = zc.zc_cookie;
+ return (0);
+}
+
+/*
+ * Take the specified vdev offline
+ */
+int
+zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ nvlist_t *tgt;
+ boolean_t avail_spare, l2cache;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
+ NULL)) == NULL)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+
+ if (avail_spare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+ zc.zc_cookie = VDEV_STATE_OFFLINE;
+ zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
+
+ if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+ return (0);
+
+ switch (errno) {
+ case EBUSY:
+
+ /*
+ * There are no other replicas of this device.
+ */
+ return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
+
+ case EEXIST:
+ /*
+ * The log device has unplayed logs
+ */
+ return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg));
+
+ default:
+ return (zpool_standard_error(hdl, errno, msg));
+ }
+}
+
+/*
+ * Mark the given vdev faulted.
+ */
+int
+zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_guid = guid;
+ zc.zc_cookie = VDEV_STATE_FAULTED;
+ zc.zc_obj = aux;
+
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+ return (0);
+
+ switch (errno) {
+ case EBUSY:
+
+ /*
+ * There are no other replicas of this device.
+ */
+ return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
+
+ default:
+ return (zpool_standard_error(hdl, errno, msg));
+ }
+
+}
+
+/*
+ * Mark the given vdev degraded.
+ */
+int
+zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_guid = guid;
+ zc.zc_cookie = VDEV_STATE_DEGRADED;
+ zc.zc_obj = aux;
+
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+ return (0);
+
+ return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
+ * Returns TRUE if the given nvlist is a vdev that was originally swapped in as
+ * a hot spare.
+ */
+static boolean_t
+is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which)
+{
+ nvlist_t **child;
+ uint_t c, children;
+ char *type;
+
+ if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child,
+ &children) == 0) {
+ verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE,
+ &type) == 0);
+
+ if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
+ children == 2 && child[which] == tgt)
+ return (B_TRUE);
+
+ for (c = 0; c < children; c++)
+ if (is_replacing_spare(child[c], tgt, which))
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Attach new_disk (fully described by nvroot) to old_disk.
+ * If 'replacing' is specified, the new disk will replace the old one.
+ */
+int
+zpool_vdev_attach(zpool_handle_t *zhp,
+ const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ int ret;
+ nvlist_t *tgt;
+ boolean_t avail_spare, l2cache, islog;
+ uint64_t val;
+ char *newname;
+ nvlist_t **child;
+ uint_t children;
+ nvlist_t *config_root;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ boolean_t rootpool = zpool_is_bootable(zhp);
+
+ if (replacing)
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot replace %s with %s"), old_disk, new_disk);
+ else
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot attach %s to %s"), new_disk, old_disk);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
+ &islog)) == NULL)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ if (avail_spare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+ if (l2cache)
+ return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+ zc.zc_cookie = replacing;
+
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0 || children != 1) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "new device must be a single disk"));
+ return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
+ }
+
+ verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
+ ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
+
+ if ((newname = zpool_vdev_name(NULL, NULL, child[0], 0)) == NULL)
+ return (-1);
+
+ /*
+ * If the target is a hot spare that has been swapped in, we can only
+ * replace it with another hot spare.
+ */
+ if (replacing &&
+ nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
+ (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache,
+ NULL) == NULL || !avail_spare) &&
+ is_replacing_spare(config_root, tgt, 1)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "can only be replaced by another hot spare"));
+ free(newname);
+ return (zfs_error(hdl, EZFS_BADTARGET, msg));
+ }
+
+ free(newname);
+
+ if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
+ return (-1);
+
+ ret = zfs_ioctl(hdl, ZFS_IOC_VDEV_ATTACH, &zc);
+
+ zcmd_free_nvlists(&zc);
+
+ if (ret == 0) {
+ if (rootpool) {
+ /*
+ * XXX need a better way to prevent user from
+ * booting up a half-baked vdev.
+ */
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make "
+ "sure to wait until resilver is done "
+ "before rebooting.\n"));
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "If "
+ "you boot from pool '%s', you may need to update\n"
+ "boot code on newly attached disk '%s'.\n\n"
+ "Assuming you use GPT partitioning and 'da0' is "
+ "your new boot disk\n"
+ "you may use the following command:\n\n"
+ "\tgpart bootcode -b /boot/pmbr -p "
+ "/boot/gptzfsboot -i 1 da0\n\n"),
+ zhp->zpool_name, new_disk);
+ }
+ return (0);
+ }
+
+ switch (errno) {
+ case ENOTSUP:
+ /*
+ * Can't attach to or replace this type of vdev.
+ */
+ if (replacing) {
+ uint64_t version = zpool_get_prop_int(zhp,
+ ZPOOL_PROP_VERSION, NULL);
+
+ if (islog)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cannot replace a log with a spare"));
+ else if (version >= SPA_VERSION_MULTI_REPLACE)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "already in replacing/spare config; wait "
+ "for completion or use 'zpool detach'"));
+ else
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cannot replace a replacing device"));
+ } else {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "can only attach to mirrors and top-level "
+ "disks"));
+ }
+ (void) zfs_error(hdl, EZFS_BADTARGET, msg);
+ break;
+
+ case EINVAL:
+ /*
+ * The new device must be a single disk.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "new device must be a single disk"));
+ (void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
+ break;
+
+ case EBUSY:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy, "
+ "or device removal is in progress"),
+ new_disk);
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ break;
+
+ case EOVERFLOW:
+ /*
+ * The new device is too small.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "device is too small"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ break;
+
+ case EDOM:
+ /*
+ * The new device has a different alignment requirement.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "devices have different sector alignment"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ break;
+
+ case ENAMETOOLONG:
+ /*
+ * The resulting top-level vdev spec won't fit in the label.
+ */
+ (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
+ break;
+
+ default:
+ (void) zpool_standard_error(hdl, errno, msg);
+ }
+
+ return (-1);
+}
+
+/*
+ * Detach the specified device.
+ */
+int
+zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ nvlist_t *tgt;
+ boolean_t avail_spare, l2cache;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
+ NULL)) == NULL)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ if (avail_spare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+ if (l2cache)
+ return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+
+ if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0)
+ return (0);
+
+ switch (errno) {
+
+ case ENOTSUP:
+ /*
+ * Can't detach from this type of vdev.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
+ "applicable to mirror and replacing vdevs"));
+ (void) zfs_error(hdl, EZFS_BADTARGET, msg);
+ break;
+
+ case EBUSY:
+ /*
+ * There are no other replicas of this device.
+ */
+ (void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
+ break;
+
+ default:
+ (void) zpool_standard_error(hdl, errno, msg);
+ }
+
+ return (-1);
+}
+
+/*
+ * Find a mirror vdev in the source nvlist.
+ *
+ * The mchild array contains a list of disks in one of the top-level mirrors
+ * of the source pool. The schild array contains a list of disks that the
+ * user specified on the command line. We loop over the mchild array to
+ * see if any entry in the schild array matches.
+ *
+ * If a disk in the mchild array is found in the schild array, we return
+ * the index of that entry. Otherwise we return -1.
+ */
+static int
+find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren,
+ nvlist_t **schild, uint_t schildren)
+{
+ uint_t mc;
+
+ for (mc = 0; mc < mchildren; mc++) {
+ uint_t sc;
+ char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp,
+ mchild[mc], 0);
+
+ for (sc = 0; sc < schildren; sc++) {
+ char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp,
+ schild[sc], 0);
+ boolean_t result = (strcmp(mpath, spath) == 0);
+
+ free(spath);
+ if (result) {
+ free(mpath);
+ return (mc);
+ }
+ }
+
+ free(mpath);
+ }
+
+ return (-1);
+}
+
+/*
+ * Split a mirror pool. If newroot points to null, then a new nvlist
+ * is generated and it is the responsibility of the caller to free it.
+ */
+int
+zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot,
+ nvlist_t *props, splitflags_t flags)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL;
+ nvlist_t **varray = NULL, *zc_props = NULL;
+ uint_t c, children, newchildren, lastlog = 0, vcount, found = 0;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ uint64_t vers;
+ boolean_t freelist = B_FALSE, memory_err = B_TRUE;
+ int retval = 0;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "Unable to split %s"), zhp->zpool_name);
+
+ if (!zpool_name_valid(hdl, B_FALSE, newname))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
+
+ if ((config = zpool_get_config(zhp, NULL)) == NULL) {
+ (void) fprintf(stderr, gettext("Internal error: unable to "
+ "retrieve pool configuration\n"));
+ return (-1);
+ }
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree)
+ == 0);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &vers) == 0);
+
+ if (props) {
+ prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE };
+ if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name,
+ props, vers, flags, msg)) == NULL)
+ return (-1);
+ }
+
+ if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child,
+ &children) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Source pool is missing vdev tree"));
+ nvlist_free(zc_props);
+ return (-1);
+ }
+
+ varray = zfs_alloc(hdl, children * sizeof (nvlist_t *));
+ vcount = 0;
+
+ if (*newroot == NULL ||
+ nvlist_lookup_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN,
+ &newchild, &newchildren) != 0)
+ newchildren = 0;
+
+ for (c = 0; c < children; c++) {
+ uint64_t is_log = B_FALSE, is_hole = B_FALSE;
+ char *type;
+ nvlist_t **mchild, *vdev;
+ uint_t mchildren;
+ int entry;
+
+ /*
+ * Unlike cache & spares, slogs are stored in the
+ * ZPOOL_CONFIG_CHILDREN array. We filter them out here.
+ */
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &is_log);
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
+ &is_hole);
+ if (is_log || is_hole) {
+ /*
+ * Create a hole vdev and put it in the config.
+ */
+ if (nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) != 0)
+ goto out;
+ if (nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_HOLE) != 0)
+ goto out;
+ if (nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_HOLE,
+ 1) != 0)
+ goto out;
+ if (lastlog == 0)
+ lastlog = vcount;
+ varray[vcount++] = vdev;
+ continue;
+ }
+ lastlog = 0;
+ verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type)
+ == 0);
+ if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Source pool must be composed only of mirrors\n"));
+ retval = zfs_error(hdl, EZFS_INVALCONFIG, msg);
+ goto out;
+ }
+
+ verify(nvlist_lookup_nvlist_array(child[c],
+ ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0);
+
+ /* find or add an entry for this top-level vdev */
+ if (newchildren > 0 &&
+ (entry = find_vdev_entry(zhp, mchild, mchildren,
+ newchild, newchildren)) >= 0) {
+ /* We found a disk that the user specified. */
+ vdev = mchild[entry];
+ ++found;
+ } else {
+ /* User didn't specify a disk for this vdev. */
+ vdev = mchild[mchildren - 1];
+ }
+
+ if (nvlist_dup(vdev, &varray[vcount++], 0) != 0)
+ goto out;
+ }
+
+ /* did we find every disk the user specified? */
+ if (found != newchildren) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Device list must "
+ "include at most one disk from each mirror"));
+ retval = zfs_error(hdl, EZFS_INVALCONFIG, msg);
+ goto out;
+ }
+
+ /* Prepare the nvlist for populating. */
+ if (*newroot == NULL) {
+ if (nvlist_alloc(newroot, NV_UNIQUE_NAME, 0) != 0)
+ goto out;
+ freelist = B_TRUE;
+ if (nvlist_add_string(*newroot, ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_ROOT) != 0)
+ goto out;
+ } else {
+ verify(nvlist_remove_all(*newroot, ZPOOL_CONFIG_CHILDREN) == 0);
+ }
+
+ /* Add all the children we found */
+ if (nvlist_add_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, varray,
+ lastlog == 0 ? vcount : lastlog) != 0)
+ goto out;
+
+ /*
+ * If we're just doing a dry run, exit now with success.
+ */
+ if (flags.dryrun) {
+ memory_err = B_FALSE;
+ freelist = B_FALSE;
+ goto out;
+ }
+
+ /* now build up the config list & call the ioctl */
+ if (nvlist_alloc(&newconfig, NV_UNIQUE_NAME, 0) != 0)
+ goto out;
+
+ if (nvlist_add_nvlist(newconfig,
+ ZPOOL_CONFIG_VDEV_TREE, *newroot) != 0 ||
+ nvlist_add_string(newconfig,
+ ZPOOL_CONFIG_POOL_NAME, newname) != 0 ||
+ nvlist_add_uint64(newconfig, ZPOOL_CONFIG_VERSION, vers) != 0)
+ goto out;
+
+ /*
+ * The new pool is automatically part of the namespace unless we
+ * explicitly export it.
+ */
+ if (!flags.import)
+ zc.zc_cookie = ZPOOL_EXPORT_AFTER_SPLIT;
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_string, newname, sizeof (zc.zc_string));
+ if (zcmd_write_conf_nvlist(hdl, &zc, newconfig) != 0)
+ goto out;
+ if (zc_props != NULL && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
+ goto out;
+
+ if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SPLIT, &zc) != 0) {
+ retval = zpool_standard_error(hdl, errno, msg);
+ goto out;
+ }
+
+ freelist = B_FALSE;
+ memory_err = B_FALSE;
+
+out:
+ if (varray != NULL) {
+ int v;
+
+ for (v = 0; v < vcount; v++)
+ nvlist_free(varray[v]);
+ free(varray);
+ }
+ zcmd_free_nvlists(&zc);
+ nvlist_free(zc_props);
+ nvlist_free(newconfig);
+ if (freelist) {
+ nvlist_free(*newroot);
+ *newroot = NULL;
+ }
+
+ if (retval != 0)
+ return (retval);
+
+ if (memory_err)
+ return (no_memory(hdl));
+
+ return (0);
+}
+
+/*
+ * Remove the given device.
+ */
+int
+zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ nvlist_t *tgt;
+ boolean_t avail_spare, l2cache, islog;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ uint64_t version;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
+ &islog)) == NULL)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
+ if (islog && version < SPA_VERSION_HOLES) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded to support log removal"));
+ return (zfs_error(hdl, EZFS_BADVERSION, msg));
+ }
+
+ zc.zc_guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID);
+
+ if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
+ return (0);
+
+ switch (errno) {
+
+ case EINVAL:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid config; all top-level vdevs must "
+ "have the same sector size and not be raidz."));
+ (void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
+ break;
+
+ case EBUSY:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Pool busy; removal may already be in progress"));
+ (void) zfs_error(hdl, EZFS_BUSY, msg);
+ break;
+
+ default:
+ (void) zpool_standard_error(hdl, errno, msg);
+ }
+ return (-1);
+}
+
+int
+zpool_vdev_remove_cancel(zpool_handle_t *zhp)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot cancel removal"));
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_cookie = 1;
+
+ if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
+ return (0);
+
+ return (zpool_standard_error(hdl, errno, msg));
+}
+
+int
+zpool_vdev_indirect_size(zpool_handle_t *zhp, const char *path,
+ uint64_t *sizep)
+{
+ char msg[1024];
+ nvlist_t *tgt;
+ boolean_t avail_spare, l2cache, islog;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot determine indirect size of %s"),
+ path);
+
+ if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
+ &islog)) == NULL)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ if (avail_spare || l2cache || islog) {
+ *sizep = 0;
+ return (0);
+ }
+
+ if (nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_INDIRECT_SIZE, sizep) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "indirect size not available"));
+ return (zfs_error(hdl, EINVAL, msg));
+ }
+ return (0);
+}
+
+/*
+ * Clear the errors for the pool, or the particular device if specified.
+ */
+int
+zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ nvlist_t *tgt;
+ zpool_load_policy_t policy;
+ boolean_t avail_spare, l2cache;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ nvlist_t *nvi = NULL;
+ int error;
+
+ if (path)
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
+ path);
+ else
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
+ zhp->zpool_name);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if (path) {
+ if ((tgt = zpool_find_vdev(zhp, path, &avail_spare,
+ &l2cache, NULL)) == NULL)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ /*
+ * Don't allow error clearing for hot spares. Do allow
+ * error clearing for l2cache devices.
+ */
+ if (avail_spare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
+ &zc.zc_guid) == 0);
+ }
+
+ zpool_get_load_policy(rewindnvl, &policy);
+ zc.zc_cookie = policy.zlp_rewind;
+
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size * 2) != 0)
+ return (-1);
+
+ if (zcmd_write_src_nvlist(hdl, &zc, rewindnvl) != 0)
+ return (-1);
+
+ while ((error = zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc)) != 0 &&
+ errno == ENOMEM) {
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ }
+
+ if (!error || ((policy.zlp_rewind & ZPOOL_TRY_REWIND) &&
+ errno != EPERM && errno != EACCES)) {
+ if (policy.zlp_rewind &
+ (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
+ (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
+ zpool_rewind_exclaim(hdl, zc.zc_name,
+ ((policy.zlp_rewind & ZPOOL_TRY_REWIND) != 0),
+ nvi);
+ nvlist_free(nvi);
+ }
+ zcmd_free_nvlists(&zc);
+ return (0);
+ }
+
+ zcmd_free_nvlists(&zc);
+ return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
+ * Similar to zpool_clear(), but takes a GUID (used by fmd).
+ */
+int
+zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"),
+ guid);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_guid = guid;
+ zc.zc_cookie = ZPOOL_NO_REWIND;
+
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
+ return (0);
+
+ return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
+ * Change the GUID for a pool.
+ */
+int
+zpool_reguid(zpool_handle_t *zhp)
+{
+ char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ zfs_cmd_t zc = { 0 };
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_REGUID, &zc) == 0)
+ return (0);
+
+ return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
+ * Reopen the pool.
+ */
+int
+zpool_reopen(zpool_handle_t *zhp)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot reopen '%s'"),
+ zhp->zpool_name);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_REOPEN, &zc) == 0)
+ return (0);
+ return (zpool_standard_error(hdl, errno, msg));
+}
+
+/* call into libzfs_core to execute the sync IOCTL per pool */
+int
+zpool_sync_one(zpool_handle_t *zhp, void *data)
+{
+ int ret;
+ libzfs_handle_t *hdl = zpool_get_handle(zhp);
+ const char *pool_name = zpool_get_name(zhp);
+ boolean_t *force = data;
+ nvlist_t *innvl = fnvlist_alloc();
+
+ fnvlist_add_boolean_value(innvl, "force", *force);
+ if ((ret = lzc_sync(pool_name, innvl, NULL)) != 0) {
+ nvlist_free(innvl);
+ return (zpool_standard_error_fmt(hdl, ret,
+ dgettext(TEXT_DOMAIN, "sync '%s' failed"), pool_name));
+ }
+ nvlist_free(innvl);
+
+ return (0);
+}
+
+/*
+ * Convert from a devid string to a path.
+ */
+static char *
+devid_to_path(char *devid_str)
+{
+ ddi_devid_t devid;
+ char *minor;
+ char *path;
+ devid_nmlist_t *list = NULL;
+ int ret;
+
+ if (devid_str_decode(devid_str, &devid, &minor) != 0)
+ return (NULL);
+
+ ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list);
+
+ devid_str_free(minor);
+ devid_free(devid);
+
+ if (ret != 0)
+ return (NULL);
+
+ /*
+ * In a case the strdup() fails, we will just return NULL below.
+ */
+ path = strdup(list[0].devname);
+
+ devid_free_nmlist(list);
+
+ return (path);
+}
+
+/*
+ * Convert from a path to a devid string.
+ */
+static char *
+path_to_devid(const char *path)
+{
+#ifdef have_devid
+ int fd;
+ ddi_devid_t devid;
+ char *minor, *ret;
+
+ if ((fd = open(path, O_RDONLY)) < 0)
+ return (NULL);
+
+ minor = NULL;
+ ret = NULL;
+ if (devid_get(fd, &devid) == 0) {
+ if (devid_get_minor_name(fd, &minor) == 0)
+ ret = devid_str_encode(devid, minor);
+ if (minor != NULL)
+ devid_str_free(minor);
+ devid_free(devid);
+ }
+ (void) close(fd);
+
+ return (ret);
+#else
+ return (NULL);
+#endif
+}
+
+/*
+ * Issue the necessary ioctl() to update the stored path value for the vdev. We
+ * ignore any failure here, since a common case is for an unprivileged user to
+ * type 'zpool status', and we'll display the correct information anyway.
+ */
+static void
+set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
+{
+ zfs_cmd_t zc = { 0 };
+
+ (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
+ &zc.zc_guid) == 0);
+
+ (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
+}
+
+/*
+ * Given a vdev, return the name to display in iostat. If the vdev has a path,
+ * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
+ * We also check if this is a whole disk, in which case we strip off the
+ * trailing 's0' slice name.
+ *
+ * This routine is also responsible for identifying when disks have been
+ * reconfigured in a new location. The kernel will have opened the device by
+ * devid, but the path will still refer to the old location. To catch this, we
+ * first do a path -> devid translation (which is fast for the common case). If
+ * the devid matches, we're done. If not, we do a reverse devid -> path
+ * translation and issue the appropriate ioctl() to update the path of the vdev.
+ * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any
+ * of these checks.
+ */
+char *
+zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
+ int name_flags)
+{
+ char *path, *devid, *env;
+ uint64_t value;
+ char buf[64];
+ vdev_stat_t *vs;
+ uint_t vsc;
+ int have_stats;
+ int have_path;
+
+ env = getenv("ZPOOL_VDEV_NAME_PATH");
+ if (env && (strtoul(env, NULL, 0) > 0 ||
+ !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
+ name_flags |= VDEV_NAME_PATH;
+
+ env = getenv("ZPOOL_VDEV_NAME_GUID");
+ if (env && (strtoul(env, NULL, 0) > 0 ||
+ !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
+ name_flags |= VDEV_NAME_GUID;
+
+ env = getenv("ZPOOL_VDEV_NAME_FOLLOW_LINKS");
+ if (env && (strtoul(env, NULL, 0) > 0 ||
+ !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
+ name_flags |= VDEV_NAME_FOLLOW_LINKS;
+
+ have_stats = nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &vsc) == 0;
+ have_path = nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0;
+
+ /*
+ * If the device is not currently present, assume it will not
+ * come back at the same device path. Display the device by GUID.
+ */
+ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &value) == 0 ||
+ (name_flags & VDEV_NAME_GUID) != 0 ||
+ have_path && have_stats && vs->vs_state <= VDEV_STATE_CANT_OPEN) {
+ nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value);
+ (void) snprintf(buf, sizeof (buf), "%llu", (u_longlong_t)value);
+ path = buf;
+ } else if (have_path) {
+
+ /*
+ * If the device is dead (faulted, offline, etc) then don't
+ * bother opening it. Otherwise we may be forcing the user to
+ * open a misbehaving device, which can have undesirable
+ * effects.
+ */
+ if ((have_stats == 0 ||
+ vs->vs_state >= VDEV_STATE_DEGRADED) &&
+ zhp != NULL &&
+ nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
+ /*
+ * Determine if the current path is correct.
+ */
+ char *newdevid = path_to_devid(path);
+
+ if (newdevid == NULL ||
+ strcmp(devid, newdevid) != 0) {
+ char *newpath;
+
+ if ((newpath = devid_to_path(devid)) != NULL) {
+ /*
+ * Update the path appropriately.
+ */
+ set_path(zhp, nv, newpath);
+ if (nvlist_add_string(nv,
+ ZPOOL_CONFIG_PATH, newpath) == 0)
+ verify(nvlist_lookup_string(nv,
+ ZPOOL_CONFIG_PATH,
+ &path) == 0);
+ free(newpath);
+ }
+ }
+
+ if (newdevid)
+ devid_str_free(newdevid);
+ }
+
+#ifdef illumos
+ if (name_flags & VDEV_NAME_FOLLOW_LINKS) {
+ char *rp = realpath(path, NULL);
+ if (rp) {
+ strlcpy(buf, rp, sizeof (buf));
+ path = buf;
+ free(rp);
+ }
+ }
+
+ if (strncmp(path, ZFS_DISK_ROOTD, strlen(ZFS_DISK_ROOTD)) == 0)
+ path += strlen(ZFS_DISK_ROOTD);
+
+ /*
+ * Remove the partition from the path it this is a whole disk.
+ */
+ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, &value)
+ == 0 && value && !(name_flags & VDEV_NAME_PATH)) {
+ int pathlen = strlen(path);
+ char *tmp = zfs_strdup(hdl, path);
+
+ /*
+ * If it starts with c#, and ends with "s0" or "s1",
+ * chop the slice off, or if it ends with "s0/old" or
+ * "s1/old", remove the slice from the middle.
+ */
+ if (CTD_CHECK(tmp)) {
+ if (strcmp(&tmp[pathlen - 2], "s0") == 0 ||
+ strcmp(&tmp[pathlen - 2], "s1") == 0) {
+ tmp[pathlen - 2] = '\0';
+ } else if (pathlen > 6 &&
+ (strcmp(&tmp[pathlen - 6], "s0/old") == 0 ||
+ strcmp(&tmp[pathlen - 6], "s1/old") == 0)) {
+ (void) strcpy(&tmp[pathlen - 6],
+ "/old");
+ }
+ }
+ return (tmp);
+ }
+#else /* !illumos */
+ if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ path += sizeof(_PATH_DEV) - 1;
+#endif /* illumos */
+ } else {
+ verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
+
+ /*
+ * If it's a raidz device, we need to stick in the parity level.
+ */
+ if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
+ &value) == 0);
+ (void) snprintf(buf, sizeof (buf), "%s%llu", path,
+ (u_longlong_t)value);
+ path = buf;
+ }
+
+ /*
+ * We identify each top-level vdev by using a <type-id>
+ * naming convention.
+ */
+ if (name_flags & VDEV_NAME_TYPE_ID) {
+ uint64_t id;
+
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
+ &id) == 0);
+ (void) snprintf(buf, sizeof (buf), "%s-%llu", path,
+ (u_longlong_t)id);
+ path = buf;
+ }
+ }
+
+ return (zfs_strdup(hdl, path));
+}
+
+static int
+zbookmark_mem_compare(const void *a, const void *b)
+{
+ return (memcmp(a, b, sizeof (zbookmark_phys_t)));
+}
+
+/*
+ * Retrieve the persistent error log, uniquify the members, and return to the
+ * caller.
+ */
+int
+zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
+{
+ zfs_cmd_t zc = { 0 };
+ uint64_t count;
+ zbookmark_phys_t *zb = NULL;
+ int i;
+
+ /*
+ * Retrieve the raw error list from the kernel. If the number of errors
+ * has increased, allocate more space and continue until we get the
+ * entire list.
+ */
+ verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
+ &count) == 0);
+ if (count == 0)
+ return (0);
+ if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
+ count * sizeof (zbookmark_phys_t))) == (uintptr_t)NULL)
+ return (-1);
+ zc.zc_nvlist_dst_size = count;
+ (void) strcpy(zc.zc_name, zhp->zpool_name);
+ for (;;) {
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
+ &zc) != 0) {
+ free((void *)(uintptr_t)zc.zc_nvlist_dst);
+ if (errno == ENOMEM) {
+ void *dst;
+
+ count = zc.zc_nvlist_dst_size;
+ dst = zfs_alloc(zhp->zpool_hdl, count *
+ sizeof (zbookmark_phys_t));
+ if (dst == NULL)
+ return (-1);
+ zc.zc_nvlist_dst = (uintptr_t)dst;
+ } else {
+ return (-1);
+ }
+ } else {
+ break;
+ }
+ }
+
+ /*
+ * Sort the resulting bookmarks. This is a little confusing due to the
+ * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last
+ * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks
+ * _not_ copied as part of the process. So we point the start of our
+ * array appropriate and decrement the total number of elements.
+ */
+ zb = ((zbookmark_phys_t *)(uintptr_t)zc.zc_nvlist_dst) +
+ zc.zc_nvlist_dst_size;
+ count -= zc.zc_nvlist_dst_size;
+
+ qsort(zb, count, sizeof (zbookmark_phys_t), zbookmark_mem_compare);
+
+ verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0);
+
+ /*
+ * Fill in the nverrlistp with nvlist's of dataset and object numbers.
+ */
+ for (i = 0; i < count; i++) {
+ nvlist_t *nv;
+
+ /* ignoring zb_blkid and zb_level for now */
+ if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
+ zb[i-1].zb_object == zb[i].zb_object)
+ continue;
+
+ if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0)
+ goto nomem;
+ if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET,
+ zb[i].zb_objset) != 0) {
+ nvlist_free(nv);
+ goto nomem;
+ }
+ if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT,
+ zb[i].zb_object) != 0) {
+ nvlist_free(nv);
+ goto nomem;
+ }
+ if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
+ nvlist_free(nv);
+ goto nomem;
+ }
+ nvlist_free(nv);
+ }
+
+ free((void *)(uintptr_t)zc.zc_nvlist_dst);
+ return (0);
+
+nomem:
+ free((void *)(uintptr_t)zc.zc_nvlist_dst);
+ return (no_memory(zhp->zpool_hdl));
+}
+
+/*
+ * Upgrade a ZFS pool to the latest on-disk version.
+ */
+int
+zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
+{
+ zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) strcpy(zc.zc_name, zhp->zpool_name);
+ zc.zc_cookie = new_version;
+
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
+ return (zpool_standard_error_fmt(hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
+ zhp->zpool_name));
+ return (0);
+}
+
+void
+zfs_save_arguments(int argc, char **argv, char *string, int len)
+{
+ (void) strlcpy(string, basename(argv[0]), len);
+ for (int i = 1; i < argc; i++) {
+ (void) strlcat(string, " ", len);
+ (void) strlcat(string, argv[i], len);
+ }
+}
+
+int
+zpool_log_history(libzfs_handle_t *hdl, const char *message)
+{
+ zfs_cmd_t zc = { 0 };
+ nvlist_t *args;
+ int err;
+
+ args = fnvlist_alloc();
+ fnvlist_add_string(args, "message", message);
+ err = zcmd_write_src_nvlist(hdl, &zc, args);
+ if (err == 0)
+ err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc);
+ nvlist_free(args);
+ zcmd_free_nvlists(&zc);
+ return (err);
+}
+
+/*
+ * Perform ioctl to get some command history of a pool.
+ *
+ * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the
+ * logical offset of the history buffer to start reading from.
+ *
+ * Upon return, 'off' is the next logical offset to read from and
+ * 'len' is the actual amount of bytes read into 'buf'.
+ */
+static int
+get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len)
+{
+ zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+
+ zc.zc_history = (uint64_t)(uintptr_t)buf;
+ zc.zc_history_len = *len;
+ zc.zc_history_offset = *off;
+
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) {
+ switch (errno) {
+ case EPERM:
+ return (zfs_error_fmt(hdl, EZFS_PERM,
+ dgettext(TEXT_DOMAIN,
+ "cannot show history for pool '%s'"),
+ zhp->zpool_name));
+ case ENOENT:
+ return (zfs_error_fmt(hdl, EZFS_NOHISTORY,
+ dgettext(TEXT_DOMAIN, "cannot get history for pool "
+ "'%s'"), zhp->zpool_name));
+ case ENOTSUP:
+ return (zfs_error_fmt(hdl, EZFS_BADVERSION,
+ dgettext(TEXT_DOMAIN, "cannot get history for pool "
+ "'%s', pool must be upgraded"), zhp->zpool_name));
+ default:
+ return (zpool_standard_error_fmt(hdl, errno,
+ dgettext(TEXT_DOMAIN,
+ "cannot get history for '%s'"), zhp->zpool_name));
+ }
+ }
+
+ *len = zc.zc_history_len;
+ *off = zc.zc_history_offset;
+
+ return (0);
+}
+
+/*
+ * Process the buffer of nvlists, unpacking and storing each nvlist record
+ * into 'records'. 'leftover' is set to the number of bytes that weren't
+ * processed as there wasn't a complete record.
+ */
+int
+zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
+ nvlist_t ***records, uint_t *numrecords)
+{
+ uint64_t reclen;
+ nvlist_t *nv;
+ int i;
+
+ while (bytes_read > sizeof (reclen)) {
+
+ /* get length of packed record (stored as little endian) */
+ for (i = 0, reclen = 0; i < sizeof (reclen); i++)
+ reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i);
+
+ if (bytes_read < sizeof (reclen) + reclen)
+ break;
+
+ /* unpack record */
+ if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0)
+ return (ENOMEM);
+ bytes_read -= sizeof (reclen) + reclen;
+ buf += sizeof (reclen) + reclen;
+
+ /* add record to nvlist array */
+ (*numrecords)++;
+ if (ISP2(*numrecords + 1)) {
+ *records = realloc(*records,
+ *numrecords * 2 * sizeof (nvlist_t *));
+ }
+ (*records)[*numrecords - 1] = nv;
+ }
+
+ *leftover = bytes_read;
+ return (0);
+}
+
+/* from spa_history.c: spa_history_create_obj() */
+#define HIS_BUF_LEN_DEF (128 << 10)
+#define HIS_BUF_LEN_MAX (1 << 30)
+
+/*
+ * Retrieve the command history of a pool.
+ */
+int
+zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
+{
+ char *buf;
+ uint64_t buflen = HIS_BUF_LEN_DEF;
+ uint64_t off = 0;
+ nvlist_t **records = NULL;
+ uint_t numrecords = 0;
+ int err, i;
+
+ buf = malloc(buflen);
+ if (buf == NULL)
+ return (ENOMEM);
+ do {
+ uint64_t bytes_read = buflen;
+ uint64_t leftover;
+
+ if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
+ break;
+
+ /* if nothing else was read in, we're at EOF, just return */
+ if (bytes_read == 0)
+ break;
+
+ if ((err = zpool_history_unpack(buf, bytes_read,
+ &leftover, &records, &numrecords)) != 0)
+ break;
+ off -= leftover;
+ if (leftover == bytes_read) {
+ /*
+ * no progress made, because buffer is not big enough
+ * to hold this record; resize and retry.
+ */
+ buflen *= 2;
+ free(buf);
+ buf = NULL;
+ if ((buflen >= HIS_BUF_LEN_MAX) ||
+ ((buf = malloc(buflen)) == NULL)) {
+ err = ENOMEM;
+ break;
+ }
+ }
+
+ /* CONSTCOND */
+ } while (1);
+
+ free(buf);
+
+ if (!err) {
+ verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
+ verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD,
+ records, numrecords) == 0);
+ }
+ for (i = 0; i < numrecords; i++)
+ nvlist_free(records[i]);
+ free(records);
+
+ return (err);
+}
+
+void
+zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
+ char *pathname, size_t len)
+{
+ zfs_cmd_t zc = { 0 };
+ boolean_t mounted = B_FALSE;
+ char *mntpnt = NULL;
+ char dsname[ZFS_MAX_DATASET_NAME_LEN];
+
+ if (dsobj == 0) {
+ /* special case for the MOS */
+ (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj);
+ return;
+ }
+
+ /* get the dataset's name */
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_obj = dsobj;
+ if (ioctl(zhp->zpool_hdl->libzfs_fd,
+ ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) {
+ /* just write out a path of two object numbers */
+ (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>",
+ dsobj, obj);
+ return;
+ }
+ (void) strlcpy(dsname, zc.zc_value, sizeof (dsname));
+
+ /* find out if the dataset is mounted */
+ mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt);
+
+ /* get the corrupted object's path */
+ (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
+ zc.zc_obj = obj;
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH,
+ &zc) == 0) {
+ if (mounted) {
+ (void) snprintf(pathname, len, "%s%s", mntpnt,
+ zc.zc_value);
+ } else {
+ (void) snprintf(pathname, len, "%s:%s",
+ dsname, zc.zc_value);
+ }
+ } else {
+ (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj);
+ }
+ free(mntpnt);
+}
+
+#ifdef illumos
+/*
+ * Read the EFI label from the config, if a label does not exist then
+ * pass back the error to the caller. If the caller has passed a non-NULL
+ * diskaddr argument then we set it to the starting address of the EFI
+ * partition. If the caller has passed a non-NULL boolean argument, then
+ * we set it to indicate if the disk does have efi system partition.
+ */
+static int
+read_efi_label(nvlist_t *config, diskaddr_t *sb, boolean_t *system)
+{
+ char *path;
+ int fd;
+ char diskname[MAXPATHLEN];
+ boolean_t boot = B_FALSE;
+ int err = -1;
+ int slice;
+
+ if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0)
+ return (err);
+
+ (void) snprintf(diskname, sizeof (diskname), "%s%s", ZFS_RDISK_ROOT,
+ strrchr(path, '/'));
+ if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) {
+ struct dk_gpt *vtoc;
+
+ if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) {
+ for (slice = 0; slice < vtoc->efi_nparts; slice++) {
+ if (vtoc->efi_parts[slice].p_tag == V_SYSTEM)
+ boot = B_TRUE;
+ if (vtoc->efi_parts[slice].p_tag == V_USR)
+ break;
+ }
+ if (sb != NULL && vtoc->efi_parts[slice].p_tag == V_USR)
+ *sb = vtoc->efi_parts[slice].p_start;
+ if (system != NULL)
+ *system = boot;
+ efi_free(vtoc);
+ }
+ (void) close(fd);
+ }
+ return (err);
+}
+
+/*
+ * determine where a partition starts on a disk in the current
+ * configuration
+ */
+static diskaddr_t
+find_start_block(nvlist_t *config)
+{
+ nvlist_t **child;
+ uint_t c, children;
+ diskaddr_t sb = MAXOFFSET_T;
+ uint64_t wholedisk;
+
+ if (nvlist_lookup_nvlist_array(config,
+ ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) {
+ if (nvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_WHOLE_DISK,
+ &wholedisk) != 0 || !wholedisk) {
+ return (MAXOFFSET_T);
+ }
+ if (read_efi_label(config, &sb, NULL) < 0)
+ sb = MAXOFFSET_T;
+ return (sb);
+ }
+
+ for (c = 0; c < children; c++) {
+ sb = find_start_block(child[c]);
+ if (sb != MAXOFFSET_T) {
+ return (sb);
+ }
+ }
+ return (MAXOFFSET_T);
+}
+#endif /* illumos */
+
+/*
+ * Label an individual disk. The name provided is the short name,
+ * stripped of any leading /dev path.
+ */
+int
+zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name,
+ zpool_boot_label_t boot_type, uint64_t boot_size, int *slice)
+{
+#ifdef illumos
+ char path[MAXPATHLEN];
+ struct dk_gpt *vtoc;
+ int fd;
+ size_t resv = EFI_MIN_RESV_SIZE;
+ uint64_t slice_size;
+ diskaddr_t start_block;
+ char errbuf[1024];
+
+ /* prepare an error message just in case */
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot label '%s'"), name);
+
+ if (zhp) {
+ nvlist_t *nvroot;
+
+ verify(nvlist_lookup_nvlist(zhp->zpool_config,
+ ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+
+ if (zhp->zpool_start_block == 0)
+ start_block = find_start_block(nvroot);
+ else
+ start_block = zhp->zpool_start_block;
+ zhp->zpool_start_block = start_block;
+ } else {
+ /* new pool */
+ start_block = NEW_START_BLOCK;
+ }
+
+ (void) snprintf(path, sizeof (path), "%s/%s%s", ZFS_RDISK_ROOT, name,
+ BACKUP_SLICE);
+
+ if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
+ /*
+ * This shouldn't happen. We've long since verified that this
+ * is a valid device.
+ */
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "unable to open device"));
+ return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
+ }
+
+ if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) {
+ /*
+ * The only way this can fail is if we run out of memory, or we
+ * were unable to read the disk's capacity
+ */
+ if (errno == ENOMEM)
+ (void) no_memory(hdl);
+
+ (void) close(fd);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "unable to read disk capacity"), name);
+
+ return (zfs_error(hdl, EZFS_NOCAP, errbuf));
+ }
+
+ /*
+ * Why we use V_USR: V_BACKUP confuses users, and is considered
+ * disposable by some EFI utilities (since EFI doesn't have a backup
+ * slice). V_UNASSIGNED is supposed to be used only for zero size
+ * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT,
+ * etc. were all pretty specific. V_USR is as close to reality as we
+ * can get, in the absence of V_OTHER.
+ */
+ /* first fix the partition start block */
+ if (start_block == MAXOFFSET_T)
+ start_block = NEW_START_BLOCK;
+
+ /*
+ * EFI System partition is using slice 0.
+ * ZFS is on slice 1 and slice 8 is reserved.
+ * We assume the GPT partition table without system
+ * partition has zfs p_start == NEW_START_BLOCK.
+ * If start_block != NEW_START_BLOCK, it means we have
+ * system partition. Correct solution would be to query/cache vtoc
+ * from existing vdev member.
+ */
+ if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
+ if (boot_size % vtoc->efi_lbasize != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "boot partition size must be a multiple of %d"),
+ vtoc->efi_lbasize);
+ (void) close(fd);
+ efi_free(vtoc);
+ return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
+ }
+ /*
+ * System partition size checks.
+ * Note the 1MB is quite arbitrary value, since we
+ * are creating dedicated pool, it should be enough
+ * to hold fat + efi bootloader. May need to be
+ * adjusted if the bootloader size will grow.
+ */
+ if (boot_size < 1024 * 1024) {
+ char buf[64];
+ zfs_nicenum(boot_size, buf, sizeof (buf));
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Specified size %s for EFI System partition is too "
+ "small, the minimum size is 1MB."), buf);
+ (void) close(fd);
+ efi_free(vtoc);
+ return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
+ }
+ /* 33MB is tested with mkfs -F pcfs */
+ if (hdl->libzfs_printerr &&
+ ((vtoc->efi_lbasize == 512 &&
+ boot_size < 33 * 1024 * 1024) ||
+ (vtoc->efi_lbasize == 4096 &&
+ boot_size < 256 * 1024 * 1024))) {
+ char buf[64];
+ zfs_nicenum(boot_size, buf, sizeof (buf));
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "Warning: EFI System partition size %s is "
+ "not allowing to create FAT32 file\nsystem, which "
+ "may result in unbootable system.\n"), buf);
+ }
+ /* Adjust zfs partition start by size of system partition. */
+ start_block += boot_size / vtoc->efi_lbasize;
+ }
+
+ if (start_block == NEW_START_BLOCK) {
+ /*
+ * Use default layout.
+ * ZFS is on slice 0 and slice 8 is reserved.
+ */
+ slice_size = vtoc->efi_last_u_lba + 1;
+ slice_size -= EFI_MIN_RESV_SIZE;
+ slice_size -= start_block;
+ if (slice != NULL)
+ *slice = 0;
+
+ vtoc->efi_parts[0].p_start = start_block;
+ vtoc->efi_parts[0].p_size = slice_size;
+
+ vtoc->efi_parts[0].p_tag = V_USR;
+ (void) strcpy(vtoc->efi_parts[0].p_name, "zfs");
+
+ vtoc->efi_parts[8].p_start = slice_size + start_block;
+ vtoc->efi_parts[8].p_size = resv;
+ vtoc->efi_parts[8].p_tag = V_RESERVED;
+ } else {
+ slice_size = start_block - NEW_START_BLOCK;
+ vtoc->efi_parts[0].p_start = NEW_START_BLOCK;
+ vtoc->efi_parts[0].p_size = slice_size;
+ vtoc->efi_parts[0].p_tag = V_SYSTEM;
+ (void) strcpy(vtoc->efi_parts[0].p_name, "loader");
+ if (slice != NULL)
+ *slice = 1;
+ /* prepare slice 1 */
+ slice_size = vtoc->efi_last_u_lba + 1 - slice_size;
+ slice_size -= resv;
+ slice_size -= NEW_START_BLOCK;
+ vtoc->efi_parts[1].p_start = start_block;
+ vtoc->efi_parts[1].p_size = slice_size;
+ vtoc->efi_parts[1].p_tag = V_USR;
+ (void) strcpy(vtoc->efi_parts[1].p_name, "zfs");
+
+ vtoc->efi_parts[8].p_start = slice_size + start_block;
+ vtoc->efi_parts[8].p_size = resv;
+ vtoc->efi_parts[8].p_tag = V_RESERVED;
+ }
+
+ if (efi_write(fd, vtoc) != 0) {
+ /*
+ * Some block drivers (like pcata) may not support EFI
+ * GPT labels. Print out a helpful error message dir-
+ * ecting the user to manually label the disk and give
+ * a specific slice.
+ */
+ (void) close(fd);
+ efi_free(vtoc);
+
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "try using fdisk(1M) and then provide a specific slice"));
+ return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
+ }
+
+ (void) close(fd);
+ efi_free(vtoc);
+#endif /* illumos */
+ return (0);
+}
+
+static boolean_t
+supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf)
+{
+ char *type;
+ nvlist_t **child;
+ uint_t children, c;
+
+ verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0);
+ if (strcmp(type, VDEV_TYPE_FILE) == 0 ||
+ strcmp(type, VDEV_TYPE_HOLE) == 0 ||
+ strcmp(type, VDEV_TYPE_MISSING) == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "vdev type '%s' is not supported"), type);
+ (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf);
+ return (B_FALSE);
+ }
+ if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++) {
+ if (!supported_dump_vdev_type(hdl, child[c], errbuf))
+ return (B_FALSE);
+ }
+ }
+ return (B_TRUE);
+}
+
+/*
+ * Check if this zvol is allowable for use as a dump device; zero if
+ * it is, > 0 if it isn't, < 0 if it isn't a zvol.
+ *
+ * Allowable storage configurations include mirrors, all raidz variants, and
+ * pools with log, cache, and spare devices. Pools which are backed by files or
+ * have missing/hole vdevs are not suitable.
+ */
+int
+zvol_check_dump_config(char *arg)
+{
+ zpool_handle_t *zhp = NULL;
+ nvlist_t *config, *nvroot;
+ char *p, *volname;
+ nvlist_t **top;
+ uint_t toplevels;
+ libzfs_handle_t *hdl;
+ char errbuf[1024];
+ char poolname[ZFS_MAX_DATASET_NAME_LEN];
+ int pathlen = strlen(ZVOL_FULL_DEV_DIR);
+ int ret = 1;
+
+ if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) {
+ return (-1);
+ }
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "dump is not supported on device '%s'"), arg);
+
+ if ((hdl = libzfs_init()) == NULL)
+ return (1);
+ libzfs_print_on_error(hdl, B_TRUE);
+
+ volname = arg + pathlen;
+
+ /* check the configuration of the pool */
+ if ((p = strchr(volname, '/')) == NULL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "malformed dataset name"));
+ (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
+ return (1);
+ } else if (p - volname >= ZFS_MAX_DATASET_NAME_LEN) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset name is too long"));
+ (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf);
+ return (1);
+ } else {
+ (void) strncpy(poolname, volname, p - volname);
+ poolname[p - volname] = '\0';
+ }
+
+ if ((zhp = zpool_open(hdl, poolname)) == NULL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "could not open pool '%s'"), poolname);
+ (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
+ goto out;
+ }
+ config = zpool_get_config(zhp, NULL);
+ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "could not obtain vdev configuration for '%s'"), poolname);
+ (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf);
+ goto out;
+ }
+
+ verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &top, &toplevels) == 0);
+
+ if (!supported_dump_vdev_type(hdl, top[0], errbuf)) {
+ goto out;
+ }
+ ret = 0;
+
+out:
+ if (zhp)
+ zpool_close(zhp);
+ libzfs_fini(hdl);
+ return (ret);
+}
+
+int
+zpool_nextboot(libzfs_handle_t *hdl, uint64_t pool_guid, uint64_t dev_guid,
+ const char *command)
+{
+ zfs_cmd_t zc = { 0 };
+ nvlist_t *args;
+ char *packed;
+ size_t size;
+ int error;
+
+ args = fnvlist_alloc();
+ fnvlist_add_uint64(args, ZPOOL_CONFIG_POOL_GUID, pool_guid);
+ fnvlist_add_uint64(args, ZPOOL_CONFIG_GUID, dev_guid);
+ fnvlist_add_string(args, "command", command);
+ error = zcmd_write_src_nvlist(hdl, &zc, args);
+ if (error == 0)
+ error = ioctl(hdl->libzfs_fd, ZFS_IOC_NEXTBOOT, &zc);
+ zcmd_free_nvlists(&zc);
+ nvlist_free(args);
+ return (error);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
new file mode 100644
index 000000000000..a4539f6d6e4b
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
@@ -0,0 +1,3882 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
+ * Copyright (c) 2019 Datto Inc.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <pthread.h>
+#include <umem.h>
+#include <time.h>
+
+#include <libzfs.h>
+#include <libzfs_core.h>
+
+#include "zfs_namecheck.h"
+#include "zfs_prop.h"
+#include "zfs_fletcher.h"
+#include "libzfs_impl.h"
+#include <zlib.h>
+#include <sha2.h>
+#include <sys/zio_checksum.h>
+#include <sys/ddt.h>
+
+#ifdef __FreeBSD__
+extern int zfs_ioctl_version;
+#endif
+
+/* in libzfs_dataset.c */
+extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
+/* We need to use something for ENODATA. */
+#define ENODATA EIDRM
+
+static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
+ recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
+ uint64_t *, const char *);
+static int guid_to_name(libzfs_handle_t *, const char *,
+ uint64_t, boolean_t, char *);
+
+static const zio_cksum_t zero_cksum = { 0 };
+
+typedef struct dedup_arg {
+ int inputfd;
+ int outputfd;
+ libzfs_handle_t *dedup_hdl;
+} dedup_arg_t;
+
+typedef struct progress_arg {
+ zfs_handle_t *pa_zhp;
+ int pa_fd;
+ boolean_t pa_parsable;
+ boolean_t pa_astitle;
+ uint64_t pa_size;
+} progress_arg_t;
+
+typedef struct dataref {
+ uint64_t ref_guid;
+ uint64_t ref_object;
+ uint64_t ref_offset;
+} dataref_t;
+
+typedef struct dedup_entry {
+ struct dedup_entry *dde_next;
+ zio_cksum_t dde_chksum;
+ uint64_t dde_prop;
+ dataref_t dde_ref;
+} dedup_entry_t;
+
+#define MAX_DDT_PHYSMEM_PERCENT 20
+#define SMALLEST_POSSIBLE_MAX_DDT_MB 128
+
+typedef struct dedup_table {
+ dedup_entry_t **dedup_hash_array;
+ umem_cache_t *ddecache;
+ uint64_t max_ddt_size; /* max dedup table size in bytes */
+ uint64_t cur_ddt_size; /* current dedup table size in bytes */
+ uint64_t ddt_count;
+ int numhashbits;
+ boolean_t ddt_full;
+} dedup_table_t;
+
+static int
+high_order_bit(uint64_t n)
+{
+ int count;
+
+ for (count = 0; n != 0; count++)
+ n >>= 1;
+ return (count);
+}
+
+static size_t
+ssread(void *buf, size_t len, FILE *stream)
+{
+ size_t outlen;
+
+ if ((outlen = fread(buf, len, 1, stream)) == 0)
+ return (0);
+
+ return (outlen);
+}
+
+static void
+ddt_hash_append(libzfs_handle_t *hdl, dedup_table_t *ddt, dedup_entry_t **ddepp,
+ zio_cksum_t *cs, uint64_t prop, dataref_t *dr)
+{
+ dedup_entry_t *dde;
+
+ if (ddt->cur_ddt_size >= ddt->max_ddt_size) {
+ if (ddt->ddt_full == B_FALSE) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Dedup table full. Deduplication will continue "
+ "with existing table entries"));
+ ddt->ddt_full = B_TRUE;
+ }
+ return;
+ }
+
+ if ((dde = umem_cache_alloc(ddt->ddecache, UMEM_DEFAULT))
+ != NULL) {
+ assert(*ddepp == NULL);
+ dde->dde_next = NULL;
+ dde->dde_chksum = *cs;
+ dde->dde_prop = prop;
+ dde->dde_ref = *dr;
+ *ddepp = dde;
+ ddt->cur_ddt_size += sizeof (dedup_entry_t);
+ ddt->ddt_count++;
+ }
+}
+
+/*
+ * Using the specified dedup table, do a lookup for an entry with
+ * the checksum cs. If found, return the block's reference info
+ * in *dr. Otherwise, insert a new entry in the dedup table, using
+ * the reference information specified by *dr.
+ *
+ * return value: true - entry was found
+ * false - entry was not found
+ */
+static boolean_t
+ddt_update(libzfs_handle_t *hdl, dedup_table_t *ddt, zio_cksum_t *cs,
+ uint64_t prop, dataref_t *dr)
+{
+ uint32_t hashcode;
+ dedup_entry_t **ddepp;
+
+ hashcode = BF64_GET(cs->zc_word[0], 0, ddt->numhashbits);
+
+ for (ddepp = &(ddt->dedup_hash_array[hashcode]); *ddepp != NULL;
+ ddepp = &((*ddepp)->dde_next)) {
+ if (ZIO_CHECKSUM_EQUAL(((*ddepp)->dde_chksum), *cs) &&
+ (*ddepp)->dde_prop == prop) {
+ *dr = (*ddepp)->dde_ref;
+ return (B_TRUE);
+ }
+ }
+ ddt_hash_append(hdl, ddt, ddepp, cs, prop, dr);
+ return (B_FALSE);
+}
+
+static int
+dump_record(dmu_replay_record_t *drr, void *payload, int payload_len,
+ zio_cksum_t *zc, int outfd)
+{
+ ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+ ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
+ (void) fletcher_4_incremental_native(drr,
+ offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), zc);
+ if (drr->drr_type != DRR_BEGIN) {
+ ASSERT(ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.
+ drr_checksum.drr_checksum));
+ drr->drr_u.drr_checksum.drr_checksum = *zc;
+ }
+ (void) fletcher_4_incremental_native(
+ &drr->drr_u.drr_checksum.drr_checksum, sizeof (zio_cksum_t), zc);
+ if (write(outfd, drr, sizeof (*drr)) == -1)
+ return (errno);
+ if (payload_len != 0) {
+ (void) fletcher_4_incremental_native(payload, payload_len, zc);
+ if (write(outfd, payload, payload_len) == -1)
+ return (errno);
+ }
+ return (0);
+}
+
+/*
+ * This function is started in a separate thread when the dedup option
+ * has been requested. The main send thread determines the list of
+ * snapshots to be included in the send stream and makes the ioctl calls
+ * for each one. But instead of having the ioctl send the output to the
+ * the output fd specified by the caller of zfs_send()), the
+ * ioctl is told to direct the output to a pipe, which is read by the
+ * alternate thread running THIS function. This function does the
+ * dedup'ing by:
+ * 1. building a dedup table (the DDT)
+ * 2. doing checksums on each data block and inserting a record in the DDT
+ * 3. looking for matching checksums, and
+ * 4. sending a DRR_WRITE_BYREF record instead of a write record whenever
+ * a duplicate block is found.
+ * The output of this function then goes to the output fd requested
+ * by the caller of zfs_send().
+ */
+static void *
+cksummer(void *arg)
+{
+ dedup_arg_t *dda = arg;
+ char *buf = zfs_alloc(dda->dedup_hdl, SPA_MAXBLOCKSIZE);
+ dmu_replay_record_t thedrr;
+ dmu_replay_record_t *drr = &thedrr;
+ FILE *ofp;
+ int outfd;
+ dedup_table_t ddt;
+ zio_cksum_t stream_cksum;
+ uint64_t physmem = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
+ uint64_t numbuckets;
+
+ ddt.max_ddt_size =
+ MAX((physmem * MAX_DDT_PHYSMEM_PERCENT) / 100,
+ SMALLEST_POSSIBLE_MAX_DDT_MB << 20);
+
+ numbuckets = ddt.max_ddt_size / (sizeof (dedup_entry_t));
+
+ /*
+ * numbuckets must be a power of 2. Increase number to
+ * a power of 2 if necessary.
+ */
+ if (!ISP2(numbuckets))
+ numbuckets = 1 << high_order_bit(numbuckets);
+
+ ddt.dedup_hash_array = calloc(numbuckets, sizeof (dedup_entry_t *));
+ ddt.ddecache = umem_cache_create("dde", sizeof (dedup_entry_t), 0,
+ NULL, NULL, NULL, NULL, NULL, 0);
+ ddt.cur_ddt_size = numbuckets * sizeof (dedup_entry_t *);
+ ddt.numhashbits = high_order_bit(numbuckets) - 1;
+ ddt.ddt_full = B_FALSE;
+
+ outfd = dda->outputfd;
+ ofp = fdopen(dda->inputfd, "r");
+ while (ssread(drr, sizeof (*drr), ofp) != 0) {
+
+ /*
+ * kernel filled in checksum, we are going to write same
+ * record, but need to regenerate checksum.
+ */
+ if (drr->drr_type != DRR_BEGIN) {
+ bzero(&drr->drr_u.drr_checksum.drr_checksum,
+ sizeof (drr->drr_u.drr_checksum.drr_checksum));
+ }
+
+ switch (drr->drr_type) {
+ case DRR_BEGIN:
+ {
+ struct drr_begin *drrb = &drr->drr_u.drr_begin;
+ int fflags;
+ int sz = 0;
+ ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0);
+
+ ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
+
+ /* set the DEDUP feature flag for this stream */
+ fflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+ fflags |= (DMU_BACKUP_FEATURE_DEDUP |
+ DMU_BACKUP_FEATURE_DEDUPPROPS);
+ DMU_SET_FEATUREFLAGS(drrb->drr_versioninfo, fflags);
+
+ if (drr->drr_payloadlen != 0) {
+ sz = drr->drr_payloadlen;
+
+ if (sz > SPA_MAXBLOCKSIZE) {
+ buf = zfs_realloc(dda->dedup_hdl, buf,
+ SPA_MAXBLOCKSIZE, sz);
+ }
+ (void) ssread(buf, sz, ofp);
+ if (ferror(stdin))
+ perror("fread");
+ }
+ if (dump_record(drr, buf, sz, &stream_cksum,
+ outfd) != 0)
+ goto out;
+ break;
+ }
+
+ case DRR_END:
+ {
+ struct drr_end *drre = &drr->drr_u.drr_end;
+ /* use the recalculated checksum */
+ drre->drr_checksum = stream_cksum;
+ if (dump_record(drr, NULL, 0, &stream_cksum,
+ outfd) != 0)
+ goto out;
+ break;
+ }
+
+ case DRR_OBJECT:
+ {
+ struct drr_object *drro = &drr->drr_u.drr_object;
+ if (drro->drr_bonuslen > 0) {
+ (void) ssread(buf,
+ P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
+ ofp);
+ }
+ if (dump_record(drr, buf,
+ P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
+ &stream_cksum, outfd) != 0)
+ goto out;
+ break;
+ }
+
+ case DRR_SPILL:
+ {
+ struct drr_spill *drrs = &drr->drr_u.drr_spill;
+ (void) ssread(buf, drrs->drr_length, ofp);
+ if (dump_record(drr, buf, drrs->drr_length,
+ &stream_cksum, outfd) != 0)
+ goto out;
+ break;
+ }
+
+ case DRR_FREEOBJECTS:
+ {
+ if (dump_record(drr, NULL, 0, &stream_cksum,
+ outfd) != 0)
+ goto out;
+ break;
+ }
+
+ case DRR_WRITE:
+ {
+ struct drr_write *drrw = &drr->drr_u.drr_write;
+ dataref_t dataref;
+ uint64_t payload_size;
+
+ payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw);
+ (void) ssread(buf, payload_size, ofp);
+
+ /*
+ * Use the existing checksum if it's dedup-capable,
+ * else calculate a SHA256 checksum for it.
+ */
+
+ if (ZIO_CHECKSUM_EQUAL(drrw->drr_key.ddk_cksum,
+ zero_cksum) ||
+ !DRR_IS_DEDUP_CAPABLE(drrw->drr_checksumflags)) {
+ SHA256_CTX ctx;
+ zio_cksum_t tmpsha256;
+
+ SHA256Init(&ctx);
+ SHA256Update(&ctx, buf, payload_size);
+ SHA256Final(&tmpsha256, &ctx);
+ drrw->drr_key.ddk_cksum.zc_word[0] =
+ BE_64(tmpsha256.zc_word[0]);
+ drrw->drr_key.ddk_cksum.zc_word[1] =
+ BE_64(tmpsha256.zc_word[1]);
+ drrw->drr_key.ddk_cksum.zc_word[2] =
+ BE_64(tmpsha256.zc_word[2]);
+ drrw->drr_key.ddk_cksum.zc_word[3] =
+ BE_64(tmpsha256.zc_word[3]);
+ drrw->drr_checksumtype = ZIO_CHECKSUM_SHA256;
+ drrw->drr_checksumflags = DRR_CHECKSUM_DEDUP;
+ }
+
+ dataref.ref_guid = drrw->drr_toguid;
+ dataref.ref_object = drrw->drr_object;
+ dataref.ref_offset = drrw->drr_offset;
+
+ if (ddt_update(dda->dedup_hdl, &ddt,
+ &drrw->drr_key.ddk_cksum, drrw->drr_key.ddk_prop,
+ &dataref)) {
+ dmu_replay_record_t wbr_drr = {0};
+ struct drr_write_byref *wbr_drrr =
+ &wbr_drr.drr_u.drr_write_byref;
+
+ /* block already present in stream */
+ wbr_drr.drr_type = DRR_WRITE_BYREF;
+
+ wbr_drrr->drr_object = drrw->drr_object;
+ wbr_drrr->drr_offset = drrw->drr_offset;
+ wbr_drrr->drr_length = drrw->drr_logical_size;
+ wbr_drrr->drr_toguid = drrw->drr_toguid;
+ wbr_drrr->drr_refguid = dataref.ref_guid;
+ wbr_drrr->drr_refobject =
+ dataref.ref_object;
+ wbr_drrr->drr_refoffset =
+ dataref.ref_offset;
+
+ wbr_drrr->drr_checksumtype =
+ drrw->drr_checksumtype;
+ wbr_drrr->drr_checksumflags =
+ drrw->drr_checksumtype;
+ wbr_drrr->drr_key.ddk_cksum =
+ drrw->drr_key.ddk_cksum;
+ wbr_drrr->drr_key.ddk_prop =
+ drrw->drr_key.ddk_prop;
+
+ if (dump_record(&wbr_drr, NULL, 0,
+ &stream_cksum, outfd) != 0)
+ goto out;
+ } else {
+ /* block not previously seen */
+ if (dump_record(drr, buf, payload_size,
+ &stream_cksum, outfd) != 0)
+ goto out;
+ }
+ break;
+ }
+
+ case DRR_WRITE_EMBEDDED:
+ {
+ struct drr_write_embedded *drrwe =
+ &drr->drr_u.drr_write_embedded;
+ (void) ssread(buf,
+ P2ROUNDUP((uint64_t)drrwe->drr_psize, 8), ofp);
+ if (dump_record(drr, buf,
+ P2ROUNDUP((uint64_t)drrwe->drr_psize, 8),
+ &stream_cksum, outfd) != 0)
+ goto out;
+ break;
+ }
+
+ case DRR_FREE:
+ {
+ if (dump_record(drr, NULL, 0, &stream_cksum,
+ outfd) != 0)
+ goto out;
+ break;
+ }
+
+ default:
+ (void) fprintf(stderr, "INVALID record type 0x%x\n",
+ drr->drr_type);
+ /* should never happen, so assert */
+ assert(B_FALSE);
+ }
+ }
+out:
+ umem_cache_destroy(ddt.ddecache);
+ free(ddt.dedup_hash_array);
+ free(buf);
+ (void) fclose(ofp);
+
+ return (NULL);
+}
+
+/*
+ * Routines for dealing with the AVL tree of fs-nvlists
+ */
+typedef struct fsavl_node {
+ avl_node_t fn_node;
+ nvlist_t *fn_nvfs;
+ char *fn_snapname;
+ uint64_t fn_guid;
+} fsavl_node_t;
+
+static int
+fsavl_compare(const void *arg1, const void *arg2)
+{
+ const fsavl_node_t *fn1 = (const fsavl_node_t *)arg1;
+ const fsavl_node_t *fn2 = (const fsavl_node_t *)arg2;
+
+ return (AVL_CMP(fn1->fn_guid, fn2->fn_guid));
+}
+
+/*
+ * Given the GUID of a snapshot, find its containing filesystem and
+ * (optionally) name.
+ */
+static nvlist_t *
+fsavl_find(avl_tree_t *avl, uint64_t snapguid, char **snapname)
+{
+ fsavl_node_t fn_find;
+ fsavl_node_t *fn;
+
+ fn_find.fn_guid = snapguid;
+
+ fn = avl_find(avl, &fn_find, NULL);
+ if (fn) {
+ if (snapname)
+ *snapname = fn->fn_snapname;
+ return (fn->fn_nvfs);
+ }
+ return (NULL);
+}
+
+static void
+fsavl_destroy(avl_tree_t *avl)
+{
+ fsavl_node_t *fn;
+ void *cookie;
+
+ if (avl == NULL)
+ return;
+
+ cookie = NULL;
+ while ((fn = avl_destroy_nodes(avl, &cookie)) != NULL)
+ free(fn);
+ avl_destroy(avl);
+ free(avl);
+}
+
+/*
+ * Given an nvlist, produce an avl tree of snapshots, ordered by guid
+ */
+static avl_tree_t *
+fsavl_create(nvlist_t *fss)
+{
+ avl_tree_t *fsavl;
+ nvpair_t *fselem = NULL;
+
+ if ((fsavl = malloc(sizeof (avl_tree_t))) == NULL)
+ return (NULL);
+
+ avl_create(fsavl, fsavl_compare, sizeof (fsavl_node_t),
+ offsetof(fsavl_node_t, fn_node));
+
+ while ((fselem = nvlist_next_nvpair(fss, fselem)) != NULL) {
+ nvlist_t *nvfs, *snaps;
+ nvpair_t *snapelem = NULL;
+
+ VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs));
+ VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps));
+
+ while ((snapelem =
+ nvlist_next_nvpair(snaps, snapelem)) != NULL) {
+ fsavl_node_t *fn;
+ uint64_t guid;
+
+ VERIFY(0 == nvpair_value_uint64(snapelem, &guid));
+ if ((fn = malloc(sizeof (fsavl_node_t))) == NULL) {
+ fsavl_destroy(fsavl);
+ return (NULL);
+ }
+ fn->fn_nvfs = nvfs;
+ fn->fn_snapname = nvpair_name(snapelem);
+ fn->fn_guid = guid;
+
+ /*
+ * Note: if there are multiple snaps with the
+ * same GUID, we ignore all but one.
+ */
+ if (avl_find(fsavl, fn, NULL) == NULL)
+ avl_add(fsavl, fn);
+ else
+ free(fn);
+ }
+ }
+
+ return (fsavl);
+}
+
+/*
+ * Routines for dealing with the giant nvlist of fs-nvlists, etc.
+ */
+typedef struct send_data {
+ /*
+ * assigned inside every recursive call,
+ * restored from *_save on return:
+ *
+ * guid of fromsnap snapshot in parent dataset
+ * txg of fromsnap snapshot in current dataset
+ * txg of tosnap snapshot in current dataset
+ */
+
+ uint64_t parent_fromsnap_guid;
+ uint64_t fromsnap_txg;
+ uint64_t tosnap_txg;
+
+ /* the nvlists get accumulated during depth-first traversal */
+ nvlist_t *parent_snaps;
+ nvlist_t *fss;
+ nvlist_t *snapprops;
+
+ /* send-receive configuration, does not change during traversal */
+ const char *fsname;
+ const char *fromsnap;
+ const char *tosnap;
+ boolean_t recursive;
+ boolean_t verbose;
+ boolean_t replicate;
+
+ /*
+ * The header nvlist is of the following format:
+ * {
+ * "tosnap" -> string
+ * "fromsnap" -> string (if incremental)
+ * "fss" -> {
+ * id -> {
+ *
+ * "name" -> string (full name; for debugging)
+ * "parentfromsnap" -> number (guid of fromsnap in parent)
+ *
+ * "props" -> { name -> value (only if set here) }
+ * "snaps" -> { name (lastname) -> number (guid) }
+ * "snapprops" -> { name (lastname) -> { name -> value } }
+ *
+ * "origin" -> number (guid) (if clone)
+ * "sent" -> boolean (not on-disk)
+ * }
+ * }
+ * }
+ *
+ */
+} send_data_t;
+
+static void send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv);
+
+static int
+send_iterate_snap(zfs_handle_t *zhp, void *arg)
+{
+ send_data_t *sd = arg;
+ uint64_t guid = zhp->zfs_dmustats.dds_guid;
+ uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;
+ char *snapname;
+ nvlist_t *nv;
+
+ snapname = strrchr(zhp->zfs_name, '@')+1;
+
+ if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {
+ if (sd->verbose) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "skipping snapshot %s because it was created "
+ "after the destination snapshot (%s)\n"),
+ zhp->zfs_name, sd->tosnap);
+ }
+ zfs_close(zhp);
+ return (0);
+ }
+
+ VERIFY(0 == nvlist_add_uint64(sd->parent_snaps, snapname, guid));
+ /*
+ * NB: if there is no fromsnap here (it's a newly created fs in
+ * an incremental replication), we will substitute the tosnap.
+ */
+ if ((sd->fromsnap && strcmp(snapname, sd->fromsnap) == 0) ||
+ (sd->parent_fromsnap_guid == 0 && sd->tosnap &&
+ strcmp(snapname, sd->tosnap) == 0)) {
+ sd->parent_fromsnap_guid = guid;
+ }
+
+ VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
+ send_iterate_prop(zhp, nv);
+ VERIFY(0 == nvlist_add_nvlist(sd->snapprops, snapname, nv));
+ nvlist_free(nv);
+
+ zfs_close(zhp);
+ return (0);
+}
+
+static void
+send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv)
+{
+ nvpair_t *elem = NULL;
+
+ while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) {
+ char *propname = nvpair_name(elem);
+ zfs_prop_t prop = zfs_name_to_prop(propname);
+ nvlist_t *propnv;
+
+ if (!zfs_prop_user(propname)) {
+ /*
+ * Realistically, this should never happen. However,
+ * we want the ability to add DSL properties without
+ * needing to make incompatible version changes. We
+ * need to ignore unknown properties to allow older
+ * software to still send datasets containing these
+ * properties, with the unknown properties elided.
+ */
+ if (prop == ZPROP_INVAL)
+ continue;
+
+ if (zfs_prop_readonly(prop))
+ continue;
+ }
+
+ verify(nvpair_value_nvlist(elem, &propnv) == 0);
+ if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION ||
+ prop == ZFS_PROP_REFQUOTA ||
+ prop == ZFS_PROP_REFRESERVATION) {
+ char *source;
+ uint64_t value;
+ verify(nvlist_lookup_uint64(propnv,
+ ZPROP_VALUE, &value) == 0);
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
+ continue;
+ /*
+ * May have no source before SPA_VERSION_RECVD_PROPS,
+ * but is still modifiable.
+ */
+ if (nvlist_lookup_string(propnv,
+ ZPROP_SOURCE, &source) == 0) {
+ if ((strcmp(source, zhp->zfs_name) != 0) &&
+ (strcmp(source,
+ ZPROP_SOURCE_VAL_RECVD) != 0))
+ continue;
+ }
+ } else {
+ char *source;
+ if (nvlist_lookup_string(propnv,
+ ZPROP_SOURCE, &source) != 0)
+ continue;
+ if ((strcmp(source, zhp->zfs_name) != 0) &&
+ (strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0))
+ continue;
+ }
+
+ if (zfs_prop_user(propname) ||
+ zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
+ char *value;
+ verify(nvlist_lookup_string(propnv,
+ ZPROP_VALUE, &value) == 0);
+ VERIFY(0 == nvlist_add_string(nv, propname, value));
+ } else {
+ uint64_t value;
+ verify(nvlist_lookup_uint64(propnv,
+ ZPROP_VALUE, &value) == 0);
+ VERIFY(0 == nvlist_add_uint64(nv, propname, value));
+ }
+ }
+}
+
+/*
+ * returns snapshot creation txg
+ * and returns 0 if the snapshot does not exist
+ */
+static uint64_t
+get_snap_txg(libzfs_handle_t *hdl, const char *fs, const char *snap)
+{
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ uint64_t txg = 0;
+
+ if (fs == NULL || fs[0] == '\0' || snap == NULL || snap[0] == '\0')
+ return (txg);
+
+ (void) snprintf(name, sizeof (name), "%s@%s", fs, snap);
+ if (zfs_dataset_exists(hdl, name, ZFS_TYPE_SNAPSHOT)) {
+ zfs_handle_t *zhp = zfs_open(hdl, name, ZFS_TYPE_SNAPSHOT);
+ if (zhp != NULL) {
+ txg = zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG);
+ zfs_close(zhp);
+ }
+ }
+
+ return (txg);
+}
+
+/*
+ * recursively generate nvlists describing datasets. See comment
+ * for the data structure send_data_t above for description of contents
+ * of the nvlist.
+ */
+static int
+send_iterate_fs(zfs_handle_t *zhp, void *arg)
+{
+ send_data_t *sd = arg;
+ nvlist_t *nvfs, *nv;
+ int rv = 0;
+ uint64_t min_txg = 0, max_txg = 0;
+ uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid;
+ uint64_t fromsnap_txg_save = sd->fromsnap_txg;
+ uint64_t tosnap_txg_save = sd->tosnap_txg;
+ uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;
+ uint64_t guid = zhp->zfs_dmustats.dds_guid;
+ uint64_t fromsnap_txg, tosnap_txg;
+ char guidstring[64];
+
+ fromsnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->fromsnap);
+ if (fromsnap_txg != 0)
+ sd->fromsnap_txg = fromsnap_txg;
+
+ tosnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->tosnap);
+ if (tosnap_txg != 0)
+ sd->tosnap_txg = tosnap_txg;
+
+ /*
+ * on the send side, if the current dataset does not have tosnap,
+ * perform two additional checks:
+ *
+ * - skip sending the current dataset if it was created later than
+ * the parent tosnap
+ * - return error if the current dataset was created earlier than
+ * the parent tosnap
+ */
+ if (sd->tosnap != NULL && tosnap_txg == 0) {
+ if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {
+ if (sd->verbose) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "skipping dataset %s: snapshot %s does "
+ "not exist\n"), zhp->zfs_name, sd->tosnap);
+ }
+ } else {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "cannot send %s@%s%s: snapshot %s@%s does not "
+ "exist\n"), sd->fsname, sd->tosnap, sd->recursive ?
+ dgettext(TEXT_DOMAIN, " recursively") : "",
+ zhp->zfs_name, sd->tosnap);
+ rv = -1;
+ }
+ goto out;
+ }
+
+ nvfs = fnvlist_alloc();
+ fnvlist_add_string(nvfs, "name", zhp->zfs_name);
+ fnvlist_add_uint64(nvfs, "parentfromsnap",
+ sd->parent_fromsnap_guid);
+
+ if (zhp->zfs_dmustats.dds_origin[0]) {
+ zfs_handle_t *origin = zfs_open(zhp->zfs_hdl,
+ zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT);
+ if (origin == NULL) {
+ rv = -1;
+ goto out;
+ }
+ VERIFY(0 == nvlist_add_uint64(nvfs, "origin",
+ origin->zfs_dmustats.dds_guid));
+ }
+
+ /* iterate over props */
+ VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
+ send_iterate_prop(zhp, nv);
+ VERIFY(0 == nvlist_add_nvlist(nvfs, "props", nv));
+ nvlist_free(nv);
+
+ /* iterate over snaps, and set sd->parent_fromsnap_guid */
+ if (!sd->replicate && fromsnap_txg != 0)
+ min_txg = fromsnap_txg;
+ if (!sd->replicate && tosnap_txg != 0)
+ max_txg = tosnap_txg;
+ sd->parent_fromsnap_guid = 0;
+ VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
+ VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
+ (void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd,
+ min_txg, max_txg);
+ VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps));
+ VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
+ fnvlist_free(sd->parent_snaps);
+ fnvlist_free(sd->snapprops);
+
+ /* add this fs to nvlist */
+ (void) snprintf(guidstring, sizeof (guidstring),
+ "0x%llx", (longlong_t)guid);
+ VERIFY(0 == nvlist_add_nvlist(sd->fss, guidstring, nvfs));
+ nvlist_free(nvfs);
+
+ /* iterate over children */
+ if (sd->recursive)
+ rv = zfs_iter_filesystems(zhp, send_iterate_fs, sd);
+
+out:
+ sd->parent_fromsnap_guid = parent_fromsnap_guid_save;
+ sd->fromsnap_txg = fromsnap_txg_save;
+ sd->tosnap_txg = tosnap_txg_save;
+
+ zfs_close(zhp);
+ return (rv);
+}
+
+static int
+gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
+ const char *tosnap, boolean_t recursive, boolean_t verbose,
+ boolean_t replicate, nvlist_t **nvlp, avl_tree_t **avlp)
+{
+ zfs_handle_t *zhp;
+ int error;
+ uint64_t min_txg = 0, max_txg = 0;
+ send_data_t sd = { 0 };
+
+ zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ return (EZFS_BADTYPE);
+
+ VERIFY(0 == nvlist_alloc(&sd.fss, NV_UNIQUE_NAME, 0));
+ sd.fsname = fsname;
+ sd.fromsnap = fromsnap;
+ sd.tosnap = tosnap;
+ sd.recursive = recursive;
+ sd.verbose = verbose;
+ sd.replicate = replicate;
+
+ if ((error = send_iterate_fs(zhp, &sd)) != 0) {
+ nvlist_free(sd.fss);
+ if (avlp != NULL)
+ *avlp = NULL;
+ *nvlp = NULL;
+ return (error);
+ }
+
+ if (avlp != NULL && (*avlp = fsavl_create(sd.fss)) == NULL) {
+ nvlist_free(sd.fss);
+ *nvlp = NULL;
+ return (EZFS_NOMEM);
+ }
+
+ *nvlp = sd.fss;
+ return (0);
+}
+
+/*
+ * Routines specific to "zfs send"
+ */
+typedef struct send_dump_data {
+ /* these are all just the short snapname (the part after the @) */
+ const char *fromsnap;
+ const char *tosnap;
+ char prevsnap[ZFS_MAX_DATASET_NAME_LEN];
+ uint64_t prevsnap_obj;
+ boolean_t seenfrom, seento, replicate, doall, fromorigin;
+ boolean_t verbose, dryrun, parsable, progress, embed_data, std_out;
+ boolean_t progressastitle;
+ boolean_t large_block, compress;
+ int outfd;
+ boolean_t err;
+ nvlist_t *fss;
+ nvlist_t *snapholds;
+ avl_tree_t *fsavl;
+ snapfilter_cb_t *filter_cb;
+ void *filter_cb_arg;
+ nvlist_t *debugnv;
+ char holdtag[ZFS_MAX_DATASET_NAME_LEN];
+ int cleanup_fd;
+ uint64_t size;
+} send_dump_data_t;
+
+static int
+zfs_send_space(zfs_handle_t *zhp, const char *snapname, const char *from,
+ enum lzc_send_flags flags, uint64_t *spacep)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ int error;
+
+ assert(snapname != NULL);
+ error = lzc_send_space(snapname, from, flags, spacep);
+
+ if (error != 0) {
+ char errbuf[1024];
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "warning: cannot estimate space for '%s'"), snapname);
+
+ switch (error) {
+ case EXDEV:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not an earlier snapshot from the same fs"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+
+ case ENOENT:
+ if (zfs_dataset_exists(hdl, snapname,
+ ZFS_TYPE_SNAPSHOT)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "incremental source (%s) does not exist"),
+ snapname);
+ }
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+ case EDQUOT:
+ case EFBIG:
+ case EIO:
+ case ENOLINK:
+ case ENOSPC:
+ case ENXIO:
+ case EPIPE:
+ case ERANGE:
+ case EFAULT:
+ case EROFS:
+ case EINVAL:
+ zfs_error_aux(hdl, strerror(error));
+ return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+ default:
+ return (zfs_standard_error(hdl, error, errbuf));
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
+ * NULL) to the file descriptor specified by outfd.
+ */
+static int
+dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
+ boolean_t fromorigin, int outfd, enum lzc_send_flags flags,
+ nvlist_t *debugnv)
+{
+ zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ nvlist_t *thisdbg;
+
+ assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+ assert(fromsnap_obj == 0 || !fromorigin);
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ zc.zc_cookie = outfd;
+ zc.zc_obj = fromorigin;
+ zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
+ zc.zc_fromobj = fromsnap_obj;
+ zc.zc_flags = flags;
+
+ VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0));
+ if (fromsnap && fromsnap[0] != '\0') {
+ VERIFY(0 == nvlist_add_string(thisdbg,
+ "fromsnap", fromsnap));
+ }
+
+ if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
+ char errbuf[1024];
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "warning: cannot send '%s'"), zhp->zfs_name);
+
+ VERIFY(0 == nvlist_add_uint64(thisdbg, "error", errno));
+ if (debugnv) {
+ VERIFY(0 == nvlist_add_nvlist(debugnv,
+ zhp->zfs_name, thisdbg));
+ }
+ nvlist_free(thisdbg);
+
+ switch (errno) {
+ case EXDEV:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not an earlier snapshot from the same fs"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+
+ case ENOENT:
+ if (zfs_dataset_exists(hdl, zc.zc_name,
+ ZFS_TYPE_SNAPSHOT)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "incremental source (@%s) does not exist"),
+ zc.zc_value);
+ }
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+ case EDQUOT:
+ case EFBIG:
+ case EIO:
+ case ENOLINK:
+ case ENOSPC:
+#ifdef illumos
+ case ENOSTR:
+#endif
+ case ENXIO:
+ case EPIPE:
+ case ERANGE:
+ case EFAULT:
+ case EROFS:
+ zfs_error_aux(hdl, strerror(errno));
+ return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+ default:
+ return (zfs_standard_error(hdl, errno, errbuf));
+ }
+ }
+
+ if (debugnv)
+ VERIFY(0 == nvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg));
+ nvlist_free(thisdbg);
+
+ return (0);
+}
+
+static void
+gather_holds(zfs_handle_t *zhp, send_dump_data_t *sdd)
+{
+ assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+
+ /*
+ * zfs_send() only sets snapholds for sends that need them,
+ * e.g. replication and doall.
+ */
+ if (sdd->snapholds == NULL)
+ return;
+
+ fnvlist_add_string(sdd->snapholds, zhp->zfs_name, sdd->holdtag);
+}
+
+static void *
+send_progress_thread(void *arg)
+{
+ progress_arg_t *pa = arg;
+ zfs_cmd_t zc = { 0 };
+ zfs_handle_t *zhp = pa->pa_zhp;
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ unsigned long long bytes, total;
+ char buf[16];
+ time_t t;
+ struct tm *tm;
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+ if (!pa->pa_parsable && !pa->pa_astitle)
+ (void) fprintf(stderr, "TIME SENT SNAPSHOT\n");
+
+ /*
+ * Print the progress from ZFS_IOC_SEND_PROGRESS every second.
+ */
+ for (;;) {
+ (void) sleep(1);
+
+ zc.zc_cookie = pa->pa_fd;
+ if (zfs_ioctl(hdl, ZFS_IOC_SEND_PROGRESS, &zc) != 0)
+ return ((void *)-1);
+
+ (void) time(&t);
+ tm = localtime(&t);
+ bytes = zc.zc_cookie;
+
+ if (pa->pa_astitle) {
+ int pct;
+ if (pa->pa_size > bytes)
+ pct = 100 * bytes / pa->pa_size;
+ else
+ pct = 100;
+
+ setproctitle("sending %s (%d%%: %llu/%llu)",
+ zhp->zfs_name, pct, bytes, pa->pa_size);
+ } else if (pa->pa_parsable) {
+ (void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ bytes, zhp->zfs_name);
+ } else {
+ zfs_nicenum(bytes, buf, sizeof (buf));
+ (void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n",
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ buf, zhp->zfs_name);
+ }
+ }
+}
+
+static void
+send_print_verbose(FILE *fout, const char *tosnap, const char *fromsnap,
+ uint64_t size, boolean_t parsable)
+{
+ if (parsable) {
+ if (fromsnap != NULL) {
+ (void) fprintf(fout, "incremental\t%s\t%s",
+ fromsnap, tosnap);
+ } else {
+ (void) fprintf(fout, "full\t%s",
+ tosnap);
+ }
+ } else {
+ if (fromsnap != NULL) {
+ if (strchr(fromsnap, '@') == NULL &&
+ strchr(fromsnap, '#') == NULL) {
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "send from @%s to %s"),
+ fromsnap, tosnap);
+ } else {
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "send from %s to %s"),
+ fromsnap, tosnap);
+ }
+ } else {
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "full send of %s"),
+ tosnap);
+ }
+ }
+
+ if (parsable) {
+ (void) fprintf(fout, "\t%llu",
+ (longlong_t)size);
+ } else if (size != 0) {
+ char buf[16];
+ zfs_nicenum(size, buf, sizeof (buf));
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ " estimated size is %s"), buf);
+ }
+ (void) fprintf(fout, "\n");
+}
+
+static int
+dump_snapshot(zfs_handle_t *zhp, void *arg)
+{
+ send_dump_data_t *sdd = arg;
+ progress_arg_t pa = { 0 };
+ pthread_t tid;
+ char *thissnap;
+ enum lzc_send_flags flags = 0;
+ int err;
+ boolean_t isfromsnap, istosnap, fromorigin;
+ boolean_t exclude = B_FALSE;
+ FILE *fout = sdd->std_out ? stdout : stderr;
+
+ err = 0;
+ thissnap = strchr(zhp->zfs_name, '@') + 1;
+ isfromsnap = (sdd->fromsnap != NULL &&
+ strcmp(sdd->fromsnap, thissnap) == 0);
+
+ if (!sdd->seenfrom && isfromsnap) {
+ gather_holds(zhp, sdd);
+ sdd->seenfrom = B_TRUE;
+ (void) strcpy(sdd->prevsnap, thissnap);
+ sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
+ zfs_close(zhp);
+ return (0);
+ }
+
+ if (sdd->seento || !sdd->seenfrom) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ istosnap = (strcmp(sdd->tosnap, thissnap) == 0);
+ if (istosnap)
+ sdd->seento = B_TRUE;
+
+ if (sdd->large_block)
+ flags |= LZC_SEND_FLAG_LARGE_BLOCK;
+ if (sdd->embed_data)
+ flags |= LZC_SEND_FLAG_EMBED_DATA;
+ if (sdd->compress)
+ flags |= LZC_SEND_FLAG_COMPRESS;
+
+ if (!sdd->doall && !isfromsnap && !istosnap) {
+ if (sdd->replicate) {
+ char *snapname;
+ nvlist_t *snapprops;
+ /*
+ * Filter out all intermediate snapshots except origin
+ * snapshots needed to replicate clones.
+ */
+ nvlist_t *nvfs = fsavl_find(sdd->fsavl,
+ zhp->zfs_dmustats.dds_guid, &snapname);
+
+ VERIFY(0 == nvlist_lookup_nvlist(nvfs,
+ "snapprops", &snapprops));
+ VERIFY(0 == nvlist_lookup_nvlist(snapprops,
+ thissnap, &snapprops));
+ exclude = !nvlist_exists(snapprops, "is_clone_origin");
+ } else {
+ exclude = B_TRUE;
+ }
+ }
+
+ /*
+ * If a filter function exists, call it to determine whether
+ * this snapshot will be sent.
+ */
+ if (exclude || (sdd->filter_cb != NULL &&
+ sdd->filter_cb(zhp, sdd->filter_cb_arg) == B_FALSE)) {
+ /*
+ * This snapshot is filtered out. Don't send it, and don't
+ * set prevsnap_obj, so it will be as if this snapshot didn't
+ * exist, and the next accepted snapshot will be sent as
+ * an incremental from the last accepted one, or as the
+ * first (and full) snapshot in the case of a replication,
+ * non-incremental send.
+ */
+ zfs_close(zhp);
+ return (0);
+ }
+
+ gather_holds(zhp, sdd);
+ fromorigin = sdd->prevsnap[0] == '\0' &&
+ (sdd->fromorigin || sdd->replicate);
+
+ if (sdd->verbose || sdd->progress) {
+ uint64_t size = 0;
+ char fromds[ZFS_MAX_DATASET_NAME_LEN];
+
+ if (sdd->prevsnap[0] != '\0') {
+ (void) strlcpy(fromds, zhp->zfs_name, sizeof (fromds));
+ *(strchr(fromds, '@') + 1) = '\0';
+ (void) strlcat(fromds, sdd->prevsnap, sizeof (fromds));
+ }
+ if (zfs_send_space(zhp, zhp->zfs_name,
+ sdd->prevsnap[0] ? fromds : NULL, flags, &size) != 0) {
+ size = 0; /* cannot estimate send space */
+ } else {
+ send_print_verbose(fout, zhp->zfs_name,
+ sdd->prevsnap[0] ? sdd->prevsnap : NULL,
+ size, sdd->parsable);
+ }
+ sdd->size += size;
+ }
+
+ if (!sdd->dryrun) {
+ /*
+ * If progress reporting is requested, spawn a new thread to
+ * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
+ */
+ if (sdd->progress) {
+ pa.pa_zhp = zhp;
+ pa.pa_fd = sdd->outfd;
+ pa.pa_parsable = sdd->parsable;
+ pa.pa_size = sdd->size;
+ pa.pa_astitle = sdd->progressastitle;
+
+ if ((err = pthread_create(&tid, NULL,
+ send_progress_thread, &pa)) != 0) {
+ zfs_close(zhp);
+ return (err);
+ }
+ }
+
+ err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
+ fromorigin, sdd->outfd, flags, sdd->debugnv);
+
+ if (sdd->progress) {
+ (void) pthread_cancel(tid);
+ (void) pthread_join(tid, NULL);
+ }
+ }
+
+ (void) strcpy(sdd->prevsnap, thissnap);
+ sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
+ zfs_close(zhp);
+ return (err);
+}
+
+static int
+dump_filesystem(zfs_handle_t *zhp, void *arg)
+{
+ int rv = 0;
+ uint64_t min_txg = 0, max_txg = 0;
+ send_dump_data_t *sdd = arg;
+ boolean_t missingfrom = B_FALSE;
+ zfs_cmd_t zc = { 0 };
+
+ (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
+ zhp->zfs_name, sdd->tosnap);
+ if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "WARNING: could not send %s@%s: does not exist\n"),
+ zhp->zfs_name, sdd->tosnap);
+ sdd->err = B_TRUE;
+ return (0);
+ }
+
+ if (sdd->replicate && sdd->fromsnap) {
+ /*
+ * If this fs does not have fromsnap, and we're doing
+ * recursive, we need to send a full stream from the
+ * beginning (or an incremental from the origin if this
+ * is a clone). If we're doing non-recursive, then let
+ * them get the error.
+ */
+ (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
+ zhp->zfs_name, sdd->fromsnap);
+ if (ioctl(zhp->zfs_hdl->libzfs_fd,
+ ZFS_IOC_OBJSET_STATS, &zc) != 0) {
+ missingfrom = B_TRUE;
+ }
+ }
+
+ sdd->seenfrom = sdd->seento = sdd->prevsnap[0] = 0;
+ sdd->prevsnap_obj = 0;
+ if (sdd->fromsnap == NULL || missingfrom)
+ sdd->seenfrom = B_TRUE;
+
+ if (!sdd->replicate && sdd->fromsnap != NULL)
+ min_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
+ sdd->fromsnap);
+ if (!sdd->replicate && sdd->tosnap != NULL)
+ max_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
+ sdd->tosnap);
+
+ rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg,
+ min_txg, max_txg);
+ if (!sdd->seenfrom) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "WARNING: could not send %s@%s:\n"
+ "incremental source (%s@%s) does not exist\n"),
+ zhp->zfs_name, sdd->tosnap,
+ zhp->zfs_name, sdd->fromsnap);
+ sdd->err = B_TRUE;
+ } else if (!sdd->seento) {
+ if (sdd->fromsnap) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "WARNING: could not send %s@%s:\n"
+ "incremental source (%s@%s) "
+ "is not earlier than it\n"),
+ zhp->zfs_name, sdd->tosnap,
+ zhp->zfs_name, sdd->fromsnap);
+ } else {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "WARNING: "
+ "could not send %s@%s: does not exist\n"),
+ zhp->zfs_name, sdd->tosnap);
+ }
+ sdd->err = B_TRUE;
+ }
+
+ return (rv);
+}
+
+static int
+dump_filesystems(zfs_handle_t *rzhp, void *arg)
+{
+ send_dump_data_t *sdd = arg;
+ nvpair_t *fspair;
+ boolean_t needagain, progress;
+
+ if (!sdd->replicate)
+ return (dump_filesystem(rzhp, sdd));
+
+ /* Mark the clone origin snapshots. */
+ for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
+ fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
+ nvlist_t *nvfs;
+ uint64_t origin_guid = 0;
+
+ VERIFY(0 == nvpair_value_nvlist(fspair, &nvfs));
+ (void) nvlist_lookup_uint64(nvfs, "origin", &origin_guid);
+ if (origin_guid != 0) {
+ char *snapname;
+ nvlist_t *origin_nv = fsavl_find(sdd->fsavl,
+ origin_guid, &snapname);
+ if (origin_nv != NULL) {
+ nvlist_t *snapprops;
+ VERIFY(0 == nvlist_lookup_nvlist(origin_nv,
+ "snapprops", &snapprops));
+ VERIFY(0 == nvlist_lookup_nvlist(snapprops,
+ snapname, &snapprops));
+ VERIFY(0 == nvlist_add_boolean(
+ snapprops, "is_clone_origin"));
+ }
+ }
+ }
+again:
+ needagain = progress = B_FALSE;
+ for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
+ fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
+ nvlist_t *fslist, *parent_nv;
+ char *fsname;
+ zfs_handle_t *zhp;
+ int err;
+ uint64_t origin_guid = 0;
+ uint64_t parent_guid = 0;
+
+ VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0);
+ if (nvlist_lookup_boolean(fslist, "sent") == 0)
+ continue;
+
+ VERIFY(nvlist_lookup_string(fslist, "name", &fsname) == 0);
+ (void) nvlist_lookup_uint64(fslist, "origin", &origin_guid);
+ (void) nvlist_lookup_uint64(fslist, "parentfromsnap",
+ &parent_guid);
+
+ if (parent_guid != 0) {
+ parent_nv = fsavl_find(sdd->fsavl, parent_guid, NULL);
+ if (!nvlist_exists(parent_nv, "sent")) {
+ /* parent has not been sent; skip this one */
+ needagain = B_TRUE;
+ continue;
+ }
+ }
+
+ if (origin_guid != 0) {
+ nvlist_t *origin_nv = fsavl_find(sdd->fsavl,
+ origin_guid, NULL);
+ if (origin_nv != NULL &&
+ !nvlist_exists(origin_nv, "sent")) {
+ /*
+ * origin has not been sent yet;
+ * skip this clone.
+ */
+ needagain = B_TRUE;
+ continue;
+ }
+ }
+
+ zhp = zfs_open(rzhp->zfs_hdl, fsname, ZFS_TYPE_DATASET);
+ if (zhp == NULL)
+ return (-1);
+ err = dump_filesystem(zhp, sdd);
+ VERIFY(nvlist_add_boolean(fslist, "sent") == 0);
+ progress = B_TRUE;
+ zfs_close(zhp);
+ if (err)
+ return (err);
+ }
+ if (needagain) {
+ assert(progress);
+ goto again;
+ }
+
+ /* clean out the sent flags in case we reuse this fss */
+ for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
+ fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
+ nvlist_t *fslist;
+
+ VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0);
+ (void) nvlist_remove_all(fslist, "sent");
+ }
+
+ return (0);
+}
+
+nvlist_t *
+zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
+{
+ unsigned int version;
+ int nread;
+ unsigned long long checksum, packed_len;
+
+ /*
+ * Decode token header, which is:
+ * <token version>-<checksum of payload>-<uncompressed payload length>
+ * Note that the only supported token version is 1.
+ */
+ nread = sscanf(token, "%u-%llx-%llx-",
+ &version, &checksum, &packed_len);
+ if (nread != 3) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (invalid format)"));
+ return (NULL);
+ }
+
+ if (version != ZFS_SEND_RESUME_TOKEN_VERSION) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (invalid version %u)"),
+ version);
+ return (NULL);
+ }
+
+ /* convert hexadecimal representation to binary */
+ token = strrchr(token, '-') + 1;
+ int len = strlen(token) / 2;
+ unsigned char *compressed = zfs_alloc(hdl, len);
+ for (int i = 0; i < len; i++) {
+ nread = sscanf(token + i * 2, "%2hhx", compressed + i);
+ if (nread != 1) {
+ free(compressed);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt "
+ "(payload is not hex-encoded)"));
+ return (NULL);
+ }
+ }
+
+ /* verify checksum */
+ zio_cksum_t cksum;
+ fletcher_4_native(compressed, len, NULL, &cksum);
+ if (cksum.zc_word[0] != checksum) {
+ free(compressed);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (incorrect checksum)"));
+ return (NULL);
+ }
+
+ /* uncompress */
+ void *packed = zfs_alloc(hdl, packed_len);
+ uLongf packed_len_long = packed_len;
+ if (uncompress(packed, &packed_len_long, compressed, len) != Z_OK ||
+ packed_len_long != packed_len) {
+ free(packed);
+ free(compressed);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (decompression failed)"));
+ return (NULL);
+ }
+
+ /* unpack nvlist */
+ nvlist_t *nv;
+ int error = nvlist_unpack(packed, packed_len, &nv, KM_SLEEP);
+ free(packed);
+ free(compressed);
+ if (error != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt (nvlist_unpack failed)"));
+ return (NULL);
+ }
+ return (nv);
+}
+
+int
+zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
+ const char *resume_token)
+{
+ char errbuf[1024];
+ char *toname;
+ char *fromname = NULL;
+ uint64_t resumeobj, resumeoff, toguid, fromguid, bytes;
+ zfs_handle_t *zhp;
+ int error = 0;
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ enum lzc_send_flags lzc_flags = 0;
+ uint64_t size = 0;
+ FILE *fout = (flags->verbose && flags->dryrun) ? stdout : stderr;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot resume send"));
+
+ nvlist_t *resume_nvl =
+ zfs_send_resume_token_to_nvlist(hdl, resume_token);
+ if (resume_nvl == NULL) {
+ /*
+ * zfs_error_aux has already been set by
+ * zfs_send_resume_token_to_nvlist
+ */
+ return (zfs_error(hdl, EZFS_FAULT, errbuf));
+ }
+ if (flags->verbose) {
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "resume token contents:\n"));
+ nvlist_print(fout, resume_nvl);
+ }
+
+ if (nvlist_lookup_string(resume_nvl, "toname", &toname) != 0 ||
+ nvlist_lookup_uint64(resume_nvl, "object", &resumeobj) != 0 ||
+ nvlist_lookup_uint64(resume_nvl, "offset", &resumeoff) != 0 ||
+ nvlist_lookup_uint64(resume_nvl, "bytes", &bytes) != 0 ||
+ nvlist_lookup_uint64(resume_nvl, "toguid", &toguid) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "resume token is corrupt"));
+ return (zfs_error(hdl, EZFS_FAULT, errbuf));
+ }
+ fromguid = 0;
+ (void) nvlist_lookup_uint64(resume_nvl, "fromguid", &fromguid);
+
+ if (flags->largeblock || nvlist_exists(resume_nvl, "largeblockok"))
+ lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;
+ if (flags->embed_data || nvlist_exists(resume_nvl, "embedok"))
+ lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;
+ if (flags->compress || nvlist_exists(resume_nvl, "compressok"))
+ lzc_flags |= LZC_SEND_FLAG_COMPRESS;
+
+ if (guid_to_name(hdl, toname, toguid, B_FALSE, name) != 0) {
+ if (zfs_dataset_exists(hdl, toname, ZFS_TYPE_DATASET)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is no longer the same snapshot used in "
+ "the initial send"), toname);
+ } else {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' used in the initial send no longer exists"),
+ toname);
+ }
+ return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+ }
+ zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
+ if (zhp == NULL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "unable to access '%s'"), name);
+ return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+ }
+
+ if (fromguid != 0) {
+ if (guid_to_name(hdl, toname, fromguid, B_TRUE, name) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "incremental source %#llx no longer exists"),
+ (longlong_t)fromguid);
+ return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+ }
+ fromname = name;
+ }
+
+ if (flags->progress || flags->verbose) {
+ error = lzc_send_space(zhp->zfs_name, fromname,
+ lzc_flags, &size);
+ if (error == 0)
+ size = MAX(0, (int64_t)(size - bytes));
+ }
+ if (flags->verbose) {
+ send_print_verbose(fout, zhp->zfs_name, fromname,
+ size, flags->parsable);
+ }
+
+ if (!flags->dryrun) {
+ progress_arg_t pa = { 0 };
+ pthread_t tid;
+ /*
+ * If progress reporting is requested, spawn a new thread to
+ * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
+ */
+ if (flags->progress) {
+ pa.pa_zhp = zhp;
+ pa.pa_fd = outfd;
+ pa.pa_parsable = flags->parsable;
+ pa.pa_size = size;
+ pa.pa_astitle = flags->progressastitle;
+
+ error = pthread_create(&tid, NULL,
+ send_progress_thread, &pa);
+ if (error != 0) {
+ zfs_close(zhp);
+ return (error);
+ }
+ }
+
+ error = lzc_send_resume(zhp->zfs_name, fromname, outfd,
+ lzc_flags, resumeobj, resumeoff);
+
+ if (flags->progress) {
+ (void) pthread_cancel(tid);
+ (void) pthread_join(tid, NULL);
+ }
+
+ char errbuf[1024];
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "warning: cannot send '%s'"), zhp->zfs_name);
+
+ zfs_close(zhp);
+
+ switch (error) {
+ case 0:
+ return (0);
+ case EXDEV:
+ case ENOENT:
+ case EDQUOT:
+ case EFBIG:
+ case EIO:
+ case ENOLINK:
+ case ENOSPC:
+#ifdef illumos
+ case ENOSTR:
+#endif
+ case ENXIO:
+ case EPIPE:
+ case ERANGE:
+ case EFAULT:
+ case EROFS:
+ zfs_error_aux(hdl, strerror(errno));
+ return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+ default:
+ return (zfs_standard_error(hdl, errno, errbuf));
+ }
+ }
+
+
+ zfs_close(zhp);
+
+ return (error);
+}
+
+/*
+ * Generate a send stream for the dataset identified by the argument zhp.
+ *
+ * The content of the send stream is the snapshot identified by
+ * 'tosnap'. Incremental streams are requested in two ways:
+ * - from the snapshot identified by "fromsnap" (if non-null) or
+ * - from the origin of the dataset identified by zhp, which must
+ * be a clone. In this case, "fromsnap" is null and "fromorigin"
+ * is TRUE.
+ *
+ * The send stream is recursive (i.e. dumps a hierarchy of snapshots) and
+ * uses a special header (with a hdrtype field of DMU_COMPOUNDSTREAM)
+ * if "replicate" is set. If "doall" is set, dump all the intermediate
+ * snapshots. The DMU_COMPOUNDSTREAM header is used in the "doall"
+ * case too. If "props" is set, send properties.
+ */
+int
+zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
+ sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,
+ void *cb_arg, nvlist_t **debugnvp)
+{
+ char errbuf[1024];
+ send_dump_data_t sdd = { 0 };
+ int err = 0;
+ nvlist_t *fss = NULL;
+ avl_tree_t *fsavl = NULL;
+ static uint64_t holdseq;
+ int spa_version;
+ pthread_t tid = 0;
+ int pipefd[2];
+ dedup_arg_t dda = { 0 };
+ int featureflags = 0;
+ FILE *fout;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot send '%s'"), zhp->zfs_name);
+
+ if (fromsnap && fromsnap[0] == '\0') {
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "zero-length incremental source"));
+ return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
+ }
+
+ if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM) {
+ uint64_t version;
+ version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+ if (version >= ZPL_VERSION_SA) {
+ featureflags |= DMU_BACKUP_FEATURE_SA_SPILL;
+ }
+ }
+
+ if (flags->dedup && !flags->dryrun) {
+ featureflags |= (DMU_BACKUP_FEATURE_DEDUP |
+ DMU_BACKUP_FEATURE_DEDUPPROPS);
+ if ((err = pipe(pipefd)) != 0) {
+ zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+ return (zfs_error(zhp->zfs_hdl, EZFS_PIPEFAILED,
+ errbuf));
+ }
+ dda.outputfd = outfd;
+ dda.inputfd = pipefd[1];
+ dda.dedup_hdl = zhp->zfs_hdl;
+ if ((err = pthread_create(&tid, NULL, cksummer, &dda)) != 0) {
+ (void) close(pipefd[0]);
+ (void) close(pipefd[1]);
+ zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+ return (zfs_error(zhp->zfs_hdl,
+ EZFS_THREADCREATEFAILED, errbuf));
+ }
+ }
+
+ if (flags->replicate || flags->doall || flags->props) {
+ dmu_replay_record_t drr = { 0 };
+ char *packbuf = NULL;
+ size_t buflen = 0;
+ zio_cksum_t zc = { 0 };
+
+ if (flags->replicate || flags->props) {
+ nvlist_t *hdrnv;
+
+ VERIFY(0 == nvlist_alloc(&hdrnv, NV_UNIQUE_NAME, 0));
+ if (fromsnap) {
+ VERIFY(0 == nvlist_add_string(hdrnv,
+ "fromsnap", fromsnap));
+ }
+ VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap));
+ if (!flags->replicate) {
+ VERIFY(0 == nvlist_add_boolean(hdrnv,
+ "not_recursive"));
+ }
+
+ err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
+ fromsnap, tosnap, flags->replicate, flags->verbose,
+ flags->replicate, &fss, &fsavl);
+ if (err)
+ goto err_out;
+ VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
+ err = nvlist_pack(hdrnv, &packbuf, &buflen,
+ NV_ENCODE_XDR, 0);
+ if (debugnvp)
+ *debugnvp = hdrnv;
+ else
+ nvlist_free(hdrnv);
+ if (err)
+ goto stderr_out;
+ }
+
+ if (!flags->dryrun) {
+ /* write first begin record */
+ drr.drr_type = DRR_BEGIN;
+ drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
+ DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.
+ drr_versioninfo, DMU_COMPOUNDSTREAM);
+ DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.
+ drr_versioninfo, featureflags);
+ (void) snprintf(drr.drr_u.drr_begin.drr_toname,
+ sizeof (drr.drr_u.drr_begin.drr_toname),
+ "%s@%s", zhp->zfs_name, tosnap);
+ drr.drr_payloadlen = buflen;
+
+ err = dump_record(&drr, packbuf, buflen, &zc, outfd);
+ free(packbuf);
+ if (err != 0)
+ goto stderr_out;
+
+ /* write end record */
+ bzero(&drr, sizeof (drr));
+ drr.drr_type = DRR_END;
+ drr.drr_u.drr_end.drr_checksum = zc;
+ err = write(outfd, &drr, sizeof (drr));
+ if (err == -1) {
+ err = errno;
+ goto stderr_out;
+ }
+
+ err = 0;
+ }
+ }
+
+ /* dump each stream */
+ sdd.fromsnap = fromsnap;
+ sdd.tosnap = tosnap;
+ if (tid != 0)
+ sdd.outfd = pipefd[0];
+ else
+ sdd.outfd = outfd;
+ sdd.replicate = flags->replicate;
+ sdd.doall = flags->doall;
+ sdd.fromorigin = flags->fromorigin;
+ sdd.fss = fss;
+ sdd.fsavl = fsavl;
+ sdd.verbose = flags->verbose;
+ sdd.parsable = flags->parsable;
+ sdd.progress = flags->progress;
+ sdd.progressastitle = flags->progressastitle;
+ sdd.dryrun = flags->dryrun;
+ sdd.large_block = flags->largeblock;
+ sdd.embed_data = flags->embed_data;
+ sdd.compress = flags->compress;
+ sdd.filter_cb = filter_func;
+ sdd.filter_cb_arg = cb_arg;
+ if (debugnvp)
+ sdd.debugnv = *debugnvp;
+ if (sdd.verbose && sdd.dryrun)
+ sdd.std_out = B_TRUE;
+ fout = sdd.std_out ? stdout : stderr;
+
+ /*
+ * Some flags require that we place user holds on the datasets that are
+ * being sent so they don't get destroyed during the send. We can skip
+ * this step if the pool is imported read-only since the datasets cannot
+ * be destroyed.
+ */
+ if (!flags->dryrun && !zpool_get_prop_int(zfs_get_pool_handle(zhp),
+ ZPOOL_PROP_READONLY, NULL) &&
+ zfs_spa_version(zhp, &spa_version) == 0 &&
+ spa_version >= SPA_VERSION_USERREFS &&
+ (flags->doall || flags->replicate)) {
+ ++holdseq;
+ (void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),
+ ".send-%d-%llu", getpid(), (u_longlong_t)holdseq);
+ sdd.cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
+ if (sdd.cleanup_fd < 0) {
+ err = errno;
+ goto stderr_out;
+ }
+ sdd.snapholds = fnvlist_alloc();
+ } else {
+ sdd.cleanup_fd = -1;
+ sdd.snapholds = NULL;
+ }
+ if (flags->progress || flags->verbose || sdd.snapholds != NULL) {
+ /*
+ * Do a verbose no-op dry run to get all the verbose output
+ * or to gather snapshot hold's before generating any data,
+ * then do a non-verbose real run to generate the streams.
+ */
+ sdd.dryrun = B_TRUE;
+ err = dump_filesystems(zhp, &sdd);
+
+ if (err != 0)
+ goto stderr_out;
+
+ if (flags->verbose) {
+ if (flags->parsable) {
+ (void) fprintf(fout, "size\t%llu\n",
+ (longlong_t)sdd.size);
+ } else {
+ char buf[16];
+ zfs_nicenum(sdd.size, buf, sizeof (buf));
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "total estimated size is %s\n"), buf);
+ }
+ }
+
+ /* Ensure no snaps found is treated as an error. */
+ if (!sdd.seento) {
+ err = ENOENT;
+ goto err_out;
+ }
+
+ /* Skip the second run if dryrun was requested. */
+ if (flags->dryrun)
+ goto err_out;
+
+ if (sdd.snapholds != NULL) {
+ err = zfs_hold_nvl(zhp, sdd.cleanup_fd, sdd.snapholds);
+ if (err != 0)
+ goto stderr_out;
+
+ fnvlist_free(sdd.snapholds);
+ sdd.snapholds = NULL;
+ }
+
+ sdd.dryrun = B_FALSE;
+ sdd.verbose = B_FALSE;
+ }
+
+ err = dump_filesystems(zhp, &sdd);
+ fsavl_destroy(fsavl);
+ nvlist_free(fss);
+
+ /* Ensure no snaps found is treated as an error. */
+ if (err == 0 && !sdd.seento)
+ err = ENOENT;
+
+ if (tid != 0) {
+ if (err != 0)
+ (void) pthread_cancel(tid);
+ (void) close(pipefd[0]);
+ (void) pthread_join(tid, NULL);
+ }
+
+ if (sdd.cleanup_fd != -1) {
+ VERIFY(0 == close(sdd.cleanup_fd));
+ sdd.cleanup_fd = -1;
+ }
+
+ if (!flags->dryrun && (flags->replicate || flags->doall ||
+ flags->props)) {
+ /*
+ * write final end record. NB: want to do this even if
+ * there was some error, because it might not be totally
+ * failed.
+ */
+ dmu_replay_record_t drr = { 0 };
+ drr.drr_type = DRR_END;
+ if (write(outfd, &drr, sizeof (drr)) == -1) {
+ return (zfs_standard_error(zhp->zfs_hdl,
+ errno, errbuf));
+ }
+ }
+
+ return (err || sdd.err);
+
+stderr_out:
+ err = zfs_standard_error(zhp->zfs_hdl, err, errbuf);
+err_out:
+ fsavl_destroy(fsavl);
+ nvlist_free(fss);
+ fnvlist_free(sdd.snapholds);
+
+ if (sdd.cleanup_fd != -1)
+ VERIFY(0 == close(sdd.cleanup_fd));
+ if (tid != 0) {
+ (void) pthread_cancel(tid);
+ (void) close(pipefd[0]);
+ (void) pthread_join(tid, NULL);
+ }
+ return (err);
+}
+
+int
+zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t flags)
+{
+ int err = 0;
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ enum lzc_send_flags lzc_flags = 0;
+ FILE *fout = (flags.verbose && flags.dryrun) ? stdout : stderr;
+ char errbuf[1024];
+
+ if (flags.largeblock)
+ lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;
+ if (flags.embed_data)
+ lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;
+ if (flags.compress)
+ lzc_flags |= LZC_SEND_FLAG_COMPRESS;
+
+ if (flags.verbose) {
+ uint64_t size = 0;
+ err = lzc_send_space(zhp->zfs_name, from, lzc_flags, &size);
+ if (err == 0) {
+ send_print_verbose(fout, zhp->zfs_name, from, size,
+ flags.parsable);
+ if (flags.parsable) {
+ (void) fprintf(fout, "size\t%llu\n",
+ (longlong_t)size);
+ } else {
+ char buf[16];
+ zfs_nicenum(size, buf, sizeof (buf));
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "total estimated size is %s\n"), buf);
+ }
+ } else {
+ (void) fprintf(stderr, "Cannot estimate send size: "
+ "%s\n", strerror(errno));
+ }
+ }
+
+ if (flags.dryrun)
+ return (err);
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "warning: cannot send '%s'"), zhp->zfs_name);
+
+ err = lzc_send(zhp->zfs_name, from, fd, lzc_flags);
+ if (err != 0) {
+ switch (errno) {
+ case EXDEV:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not an earlier snapshot from the same fs"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+
+ case ENOENT:
+ case ESRCH:
+ if (lzc_exists(zhp->zfs_name)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "incremental source (%s) does not exist"),
+ from);
+ }
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+ case EBUSY:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "target is busy; if a filesystem, "
+ "it must not be mounted"));
+ return (zfs_error(hdl, EZFS_BUSY, errbuf));
+
+ case EDQUOT:
+ case EFBIG:
+ case EIO:
+ case ENOLINK:
+ case ENOSPC:
+#ifdef illumos
+ case ENOSTR:
+#endif
+ case ENXIO:
+ case EPIPE:
+ case ERANGE:
+ case EFAULT:
+ case EROFS:
+ zfs_error_aux(hdl, strerror(errno));
+ return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+ default:
+ return (zfs_standard_error(hdl, errno, errbuf));
+ }
+ }
+ return (err != 0);
+}
+
+/*
+ * Routines specific to "zfs recv"
+ */
+
+static int
+recv_read(libzfs_handle_t *hdl, int fd, void *buf, int ilen,
+ boolean_t byteswap, zio_cksum_t *zc)
+{
+ char *cp = buf;
+ int rv;
+ int len = ilen;
+
+ assert(ilen <= SPA_MAXBLOCKSIZE);
+
+ do {
+ rv = read(fd, cp, len);
+ cp += rv;
+ len -= rv;
+ } while (rv > 0);
+
+ if (rv < 0 || len != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "failed to read from stream"));
+ return (zfs_error(hdl, EZFS_BADSTREAM, dgettext(TEXT_DOMAIN,
+ "cannot receive")));
+ }
+
+ if (zc) {
+ if (byteswap)
+ (void) fletcher_4_incremental_byteswap(buf, ilen, zc);
+ else
+ (void) fletcher_4_incremental_native(buf, ilen, zc);
+ }
+ return (0);
+}
+
+static int
+recv_read_nvlist(libzfs_handle_t *hdl, int fd, int len, nvlist_t **nvp,
+ boolean_t byteswap, zio_cksum_t *zc)
+{
+ char *buf;
+ int err;
+
+ buf = zfs_alloc(hdl, len);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ err = recv_read(hdl, fd, buf, len, byteswap, zc);
+ if (err != 0) {
+ free(buf);
+ return (err);
+ }
+
+ err = nvlist_unpack(buf, len, nvp, 0);
+ free(buf);
+ if (err != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+ "stream (malformed nvlist)"));
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
+ int baselen, char *newname, recvflags_t *flags)
+{
+ static int seq;
+ int err;
+ prop_changelist_t *clp;
+ zfs_handle_t *zhp;
+
+ zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
+ if (zhp == NULL)
+ return (-1);
+ clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+ flags->force ? MS_FORCE : 0);
+ zfs_close(zhp);
+ if (clp == NULL)
+ return (-1);
+ err = changelist_prefix(clp);
+ if (err)
+ return (err);
+
+ if (tryname) {
+ (void) strcpy(newname, tryname);
+ if (flags->verbose) {
+ (void) printf("attempting rename %s to %s\n",
+ name, newname);
+ }
+ err = lzc_rename(name, newname);
+ if (err == 0)
+ changelist_rename(clp, name, tryname);
+ } else {
+ err = ENOENT;
+ }
+
+ if (err != 0 && strncmp(name + baselen, "recv-", 5) != 0) {
+ seq++;
+
+ (void) snprintf(newname, ZFS_MAX_DATASET_NAME_LEN,
+ "%.*srecv-%u-%u", baselen, name, getpid(), seq);
+ if (flags->verbose) {
+ (void) printf("failed - trying rename %s to %s\n",
+ name, newname);
+ }
+ err = lzc_rename(name, newname);
+ if (err == 0)
+ changelist_rename(clp, name, newname);
+ if (err && flags->verbose) {
+ (void) printf("failed (%u) - "
+ "will try again on next pass\n", errno);
+ }
+ err = EAGAIN;
+ } else if (flags->verbose) {
+ if (err == 0)
+ (void) printf("success\n");
+ else
+ (void) printf("failed (%u)\n", errno);
+ }
+
+ (void) changelist_postfix(clp);
+ changelist_free(clp);
+
+ return (err);
+}
+
+static int
+recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
+ char *newname, recvflags_t *flags)
+{
+ int err = 0;
+ prop_changelist_t *clp;
+ zfs_handle_t *zhp;
+ boolean_t defer = B_FALSE;
+ int spa_version;
+
+ zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
+ if (zhp == NULL)
+ return (-1);
+ clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+ flags->force ? MS_FORCE : 0);
+ if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
+ zfs_spa_version(zhp, &spa_version) == 0 &&
+ spa_version >= SPA_VERSION_USERREFS)
+ defer = B_TRUE;
+ zfs_close(zhp);
+ if (clp == NULL)
+ return (-1);
+ err = changelist_prefix(clp);
+ if (err)
+ return (err);
+
+ if (flags->verbose)
+ (void) printf("attempting destroy %s\n", name);
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+ nvlist_t *nv = fnvlist_alloc();
+ fnvlist_add_boolean(nv, name);
+ err = lzc_destroy_snaps(nv, defer, NULL);
+ fnvlist_free(nv);
+ } else {
+ err = lzc_destroy(name);
+ }
+ if (err == 0) {
+ if (flags->verbose)
+ (void) printf("success\n");
+ changelist_remove(clp, name);
+ }
+
+ (void) changelist_postfix(clp);
+ changelist_free(clp);
+
+ /*
+ * Deferred destroy might destroy the snapshot or only mark it to be
+ * destroyed later, and it returns success in either case.
+ */
+ if (err != 0 || (defer && zfs_dataset_exists(hdl, name,
+ ZFS_TYPE_SNAPSHOT))) {
+ err = recv_rename(hdl, name, NULL, baselen, newname, flags);
+ }
+
+ return (err);
+}
+
+typedef struct guid_to_name_data {
+ uint64_t guid;
+ boolean_t bookmark_ok;
+ char *name;
+ char *skip;
+} guid_to_name_data_t;
+
+static int
+guid_to_name_cb(zfs_handle_t *zhp, void *arg)
+{
+ guid_to_name_data_t *gtnd = arg;
+ const char *slash;
+ int err;
+
+ if (gtnd->skip != NULL &&
+ (slash = strrchr(zhp->zfs_name, '/')) != NULL &&
+ strcmp(slash + 1, gtnd->skip) == 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ if (zfs_prop_get_int(zhp, ZFS_PROP_GUID) == gtnd->guid) {
+ (void) strcpy(gtnd->name, zhp->zfs_name);
+ zfs_close(zhp);
+ return (EEXIST);
+ }
+
+ err = zfs_iter_children(zhp, guid_to_name_cb, gtnd);
+ if (err != EEXIST && gtnd->bookmark_ok)
+ err = zfs_iter_bookmarks(zhp, guid_to_name_cb, gtnd);
+ zfs_close(zhp);
+ return (err);
+}
+
+/*
+ * Attempt to find the local dataset associated with this guid. In the case of
+ * multiple matches, we attempt to find the "best" match by searching
+ * progressively larger portions of the hierarchy. This allows one to send a
+ * tree of datasets individually and guarantee that we will find the source
+ * guid within that hierarchy, even if there are multiple matches elsewhere.
+ */
+static int
+guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,
+ boolean_t bookmark_ok, char *name)
+{
+ char pname[ZFS_MAX_DATASET_NAME_LEN];
+ guid_to_name_data_t gtnd;
+
+ gtnd.guid = guid;
+ gtnd.bookmark_ok = bookmark_ok;
+ gtnd.name = name;
+ gtnd.skip = NULL;
+
+ /*
+ * Search progressively larger portions of the hierarchy, starting
+ * with the filesystem specified by 'parent'. This will
+ * select the "most local" version of the origin snapshot in the case
+ * that there are multiple matching snapshots in the system.
+ */
+ (void) strlcpy(pname, parent, sizeof (pname));
+ char *cp = strrchr(pname, '@');
+ if (cp == NULL)
+ cp = strchr(pname, '\0');
+ for (; cp != NULL; cp = strrchr(pname, '/')) {
+ /* Chop off the last component and open the parent */
+ *cp = '\0';
+ zfs_handle_t *zhp = make_dataset_handle(hdl, pname);
+
+ if (zhp == NULL)
+ continue;
+ int err = guid_to_name_cb(zfs_handle_dup(zhp), &gtnd);
+ if (err != EEXIST)
+ err = zfs_iter_children(zhp, guid_to_name_cb, &gtnd);
+ if (err != EEXIST && bookmark_ok)
+ err = zfs_iter_bookmarks(zhp, guid_to_name_cb, &gtnd);
+ zfs_close(zhp);
+ if (err == EEXIST)
+ return (0);
+
+ /*
+ * Remember the last portion of the dataset so we skip it next
+ * time through (as we've already searched that portion of the
+ * hierarchy).
+ */
+ gtnd.skip = strrchr(pname, '/') + 1;
+ }
+
+ return (ENOENT);
+}
+
+/*
+ * Return +1 if guid1 is before guid2, 0 if they are the same, and -1 if
+ * guid1 is after guid2.
+ */
+static int
+created_before(libzfs_handle_t *hdl, avl_tree_t *avl,
+ uint64_t guid1, uint64_t guid2)
+{
+ nvlist_t *nvfs;
+ char *fsname, *snapname;
+ char buf[ZFS_MAX_DATASET_NAME_LEN];
+ int rv;
+ zfs_handle_t *guid1hdl, *guid2hdl;
+ uint64_t create1, create2;
+
+ if (guid2 == 0)
+ return (0);
+ if (guid1 == 0)
+ return (1);
+
+ nvfs = fsavl_find(avl, guid1, &snapname);
+ VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
+ (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);
+ guid1hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
+ if (guid1hdl == NULL)
+ return (-1);
+
+ nvfs = fsavl_find(avl, guid2, &snapname);
+ VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
+ (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);
+ guid2hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
+ if (guid2hdl == NULL) {
+ zfs_close(guid1hdl);
+ return (-1);
+ }
+
+ create1 = zfs_prop_get_int(guid1hdl, ZFS_PROP_CREATETXG);
+ create2 = zfs_prop_get_int(guid2hdl, ZFS_PROP_CREATETXG);
+
+ if (create1 < create2)
+ rv = -1;
+ else if (create1 > create2)
+ rv = +1;
+ else
+ rv = 0;
+
+ zfs_close(guid1hdl);
+ zfs_close(guid2hdl);
+
+ return (rv);
+}
+
+static int
+recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
+ recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
+ nvlist_t *renamed)
+{
+ nvlist_t *local_nv, *deleted = NULL;
+ avl_tree_t *local_avl;
+ nvpair_t *fselem, *nextfselem;
+ char *fromsnap;
+ char newname[ZFS_MAX_DATASET_NAME_LEN];
+ char guidname[32];
+ int error;
+ boolean_t needagain, progress, recursive;
+ char *s1, *s2;
+
+ VERIFY(0 == nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap));
+
+ recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
+ ENOENT);
+
+ if (flags->dryrun)
+ return (0);
+
+again:
+ needagain = progress = B_FALSE;
+
+ VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0));
+
+ if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
+ recursive, B_FALSE, B_FALSE, &local_nv, &local_avl)) != 0)
+ return (error);
+
+ /*
+ * Process deletes and renames
+ */
+ for (fselem = nvlist_next_nvpair(local_nv, NULL);
+ fselem; fselem = nextfselem) {
+ nvlist_t *nvfs, *snaps;
+ nvlist_t *stream_nvfs = NULL;
+ nvpair_t *snapelem, *nextsnapelem;
+ uint64_t fromguid = 0;
+ uint64_t originguid = 0;
+ uint64_t stream_originguid = 0;
+ uint64_t parent_fromsnap_guid, stream_parent_fromsnap_guid;
+ char *fsname, *stream_fsname;
+
+ nextfselem = nvlist_next_nvpair(local_nv, fselem);
+
+ VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs));
+ VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps));
+ VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
+ VERIFY(0 == nvlist_lookup_uint64(nvfs, "parentfromsnap",
+ &parent_fromsnap_guid));
+ (void) nvlist_lookup_uint64(nvfs, "origin", &originguid);
+
+ /*
+ * First find the stream's fs, so we can check for
+ * a different origin (due to "zfs promote")
+ */
+ for (snapelem = nvlist_next_nvpair(snaps, NULL);
+ snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) {
+ uint64_t thisguid;
+
+ VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid));
+ stream_nvfs = fsavl_find(stream_avl, thisguid, NULL);
+
+ if (stream_nvfs != NULL)
+ break;
+ }
+
+ /* check for promote */
+ (void) nvlist_lookup_uint64(stream_nvfs, "origin",
+ &stream_originguid);
+ if (stream_nvfs && originguid != stream_originguid) {
+ switch (created_before(hdl, local_avl,
+ stream_originguid, originguid)) {
+ case 1: {
+ /* promote it! */
+ zfs_cmd_t zc = { 0 };
+ nvlist_t *origin_nvfs;
+ char *origin_fsname;
+
+ if (flags->verbose)
+ (void) printf("promoting %s\n", fsname);
+
+ origin_nvfs = fsavl_find(local_avl, originguid,
+ NULL);
+ VERIFY(0 == nvlist_lookup_string(origin_nvfs,
+ "name", &origin_fsname));
+ (void) strlcpy(zc.zc_value, origin_fsname,
+ sizeof (zc.zc_value));
+ (void) strlcpy(zc.zc_name, fsname,
+ sizeof (zc.zc_name));
+ error = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);
+ if (error == 0)
+ progress = B_TRUE;
+ break;
+ }
+ default:
+ break;
+ case -1:
+ fsavl_destroy(local_avl);
+ nvlist_free(local_nv);
+ return (-1);
+ }
+ /*
+ * We had/have the wrong origin, therefore our
+ * list of snapshots is wrong. Need to handle
+ * them on the next pass.
+ */
+ needagain = B_TRUE;
+ continue;
+ }
+
+ for (snapelem = nvlist_next_nvpair(snaps, NULL);
+ snapelem; snapelem = nextsnapelem) {
+ uint64_t thisguid;
+ char *stream_snapname;
+ nvlist_t *found, *props;
+
+ nextsnapelem = nvlist_next_nvpair(snaps, snapelem);
+
+ VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid));
+ found = fsavl_find(stream_avl, thisguid,
+ &stream_snapname);
+
+ /* check for delete */
+ if (found == NULL) {
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+
+ if (!flags->force)
+ continue;
+
+ (void) snprintf(name, sizeof (name), "%s@%s",
+ fsname, nvpair_name(snapelem));
+
+ error = recv_destroy(hdl, name,
+ strlen(fsname)+1, newname, flags);
+ if (error)
+ needagain = B_TRUE;
+ else
+ progress = B_TRUE;
+ sprintf(guidname, "%" PRIu64, thisguid);
+ nvlist_add_boolean(deleted, guidname);
+ continue;
+ }
+
+ stream_nvfs = found;
+
+ if (0 == nvlist_lookup_nvlist(stream_nvfs, "snapprops",
+ &props) && 0 == nvlist_lookup_nvlist(props,
+ stream_snapname, &props)) {
+ zfs_cmd_t zc = { 0 };
+
+ zc.zc_cookie = B_TRUE; /* received */
+ (void) snprintf(zc.zc_name, sizeof (zc.zc_name),
+ "%s@%s", fsname, nvpair_name(snapelem));
+ if (zcmd_write_src_nvlist(hdl, &zc,
+ props) == 0) {
+ (void) zfs_ioctl(hdl,
+ ZFS_IOC_SET_PROP, &zc);
+ zcmd_free_nvlists(&zc);
+ }
+ }
+
+ /* check for different snapname */
+ if (strcmp(nvpair_name(snapelem),
+ stream_snapname) != 0) {
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ char tryname[ZFS_MAX_DATASET_NAME_LEN];
+
+ (void) snprintf(name, sizeof (name), "%s@%s",
+ fsname, nvpair_name(snapelem));
+ (void) snprintf(tryname, sizeof (name), "%s@%s",
+ fsname, stream_snapname);
+
+ error = recv_rename(hdl, name, tryname,
+ strlen(fsname)+1, newname, flags);
+ if (error)
+ needagain = B_TRUE;
+ else
+ progress = B_TRUE;
+ }
+
+ if (strcmp(stream_snapname, fromsnap) == 0)
+ fromguid = thisguid;
+ }
+
+ /* check for delete */
+ if (stream_nvfs == NULL) {
+ if (!flags->force)
+ continue;
+
+ error = recv_destroy(hdl, fsname, strlen(tofs)+1,
+ newname, flags);
+ if (error)
+ needagain = B_TRUE;
+ else
+ progress = B_TRUE;
+ sprintf(guidname, "%" PRIu64, parent_fromsnap_guid);
+ nvlist_add_boolean(deleted, guidname);
+ continue;
+ }
+
+ if (fromguid == 0) {
+ if (flags->verbose) {
+ (void) printf("local fs %s does not have "
+ "fromsnap (%s in stream); must have "
+ "been deleted locally; ignoring\n",
+ fsname, fromsnap);
+ }
+ continue;
+ }
+
+ VERIFY(0 == nvlist_lookup_string(stream_nvfs,
+ "name", &stream_fsname));
+ VERIFY(0 == nvlist_lookup_uint64(stream_nvfs,
+ "parentfromsnap", &stream_parent_fromsnap_guid));
+
+ s1 = strrchr(fsname, '/');
+ s2 = strrchr(stream_fsname, '/');
+
+ /*
+ * Check if we're going to rename based on parent guid change
+ * and the current parent guid was also deleted. If it was then
+ * rename will fail and is likely unneeded, so avoid this and
+ * force an early retry to determine the new
+ * parent_fromsnap_guid.
+ */
+ if (stream_parent_fromsnap_guid != 0 &&
+ parent_fromsnap_guid != 0 &&
+ stream_parent_fromsnap_guid != parent_fromsnap_guid) {
+ sprintf(guidname, "%" PRIu64, parent_fromsnap_guid);
+ if (nvlist_exists(deleted, guidname)) {
+ progress = B_TRUE;
+ needagain = B_TRUE;
+ goto doagain;
+ }
+ }
+
+ /*
+ * Check for rename. If the exact receive path is specified, it
+ * does not count as a rename, but we still need to check the
+ * datasets beneath it.
+ */
+ if ((stream_parent_fromsnap_guid != 0 &&
+ parent_fromsnap_guid != 0 &&
+ stream_parent_fromsnap_guid != parent_fromsnap_guid) ||
+ ((flags->isprefix || strcmp(tofs, fsname) != 0) &&
+ (s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) {
+ nvlist_t *parent;
+ char tryname[ZFS_MAX_DATASET_NAME_LEN];
+
+ parent = fsavl_find(local_avl,
+ stream_parent_fromsnap_guid, NULL);
+ /*
+ * NB: parent might not be found if we used the
+ * tosnap for stream_parent_fromsnap_guid,
+ * because the parent is a newly-created fs;
+ * we'll be able to rename it after we recv the
+ * new fs.
+ */
+ if (parent != NULL) {
+ char *pname;
+
+ VERIFY(0 == nvlist_lookup_string(parent, "name",
+ &pname));
+ (void) snprintf(tryname, sizeof (tryname),
+ "%s%s", pname, strrchr(stream_fsname, '/'));
+ } else {
+ tryname[0] = '\0';
+ if (flags->verbose) {
+ (void) printf("local fs %s new parent "
+ "not found\n", fsname);
+ }
+ }
+
+ newname[0] = '\0';
+
+ error = recv_rename(hdl, fsname, tryname,
+ strlen(tofs)+1, newname, flags);
+
+ if (renamed != NULL && newname[0] != '\0') {
+ VERIFY(0 == nvlist_add_boolean(renamed,
+ newname));
+ }
+
+ if (error)
+ needagain = B_TRUE;
+ else
+ progress = B_TRUE;
+ }
+ }
+
+doagain:
+ fsavl_destroy(local_avl);
+ nvlist_free(local_nv);
+ nvlist_free(deleted);
+
+ if (needagain && progress) {
+ /* do another pass to fix up temporary names */
+ if (flags->verbose)
+ (void) printf("another pass:\n");
+ goto again;
+ }
+
+ return (needagain);
+}
+
+static int
+zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
+ recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
+ char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
+{
+ nvlist_t *stream_nv = NULL;
+ avl_tree_t *stream_avl = NULL;
+ char *fromsnap = NULL;
+ char *sendsnap = NULL;
+ char *cp;
+ char tofs[ZFS_MAX_DATASET_NAME_LEN];
+ char sendfs[ZFS_MAX_DATASET_NAME_LEN];
+ char errbuf[1024];
+ dmu_replay_record_t drre;
+ int error;
+ boolean_t anyerr = B_FALSE;
+ boolean_t softerr = B_FALSE;
+ boolean_t recursive;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot receive"));
+
+ assert(drr->drr_type == DRR_BEGIN);
+ assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);
+ assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==
+ DMU_COMPOUNDSTREAM);
+
+ /*
+ * Read in the nvlist from the stream.
+ */
+ if (drr->drr_payloadlen != 0) {
+ error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen,
+ &stream_nv, flags->byteswap, zc);
+ if (error) {
+ error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+ goto out;
+ }
+ }
+
+ recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
+ ENOENT);
+
+ if (recursive && strchr(destname, '@')) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cannot specify snapshot name for multi-snapshot stream"));
+ error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+ goto out;
+ }
+
+ /*
+ * Read in the end record and verify checksum.
+ */
+ if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre),
+ flags->byteswap, NULL)))
+ goto out;
+ if (flags->byteswap) {
+ drre.drr_type = BSWAP_32(drre.drr_type);
+ drre.drr_u.drr_end.drr_checksum.zc_word[0] =
+ BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]);
+ drre.drr_u.drr_end.drr_checksum.zc_word[1] =
+ BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[1]);
+ drre.drr_u.drr_end.drr_checksum.zc_word[2] =
+ BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[2]);
+ drre.drr_u.drr_end.drr_checksum.zc_word[3] =
+ BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[3]);
+ }
+ if (drre.drr_type != DRR_END) {
+ error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+ goto out;
+ }
+ if (!ZIO_CHECKSUM_EQUAL(drre.drr_u.drr_end.drr_checksum, *zc)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "incorrect header checksum"));
+ error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+ goto out;
+ }
+
+ (void) nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap);
+
+ if (drr->drr_payloadlen != 0) {
+ nvlist_t *stream_fss;
+
+ VERIFY(0 == nvlist_lookup_nvlist(stream_nv, "fss",
+ &stream_fss));
+ if ((stream_avl = fsavl_create(stream_fss)) == NULL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "couldn't allocate avl tree"));
+ error = zfs_error(hdl, EZFS_NOMEM, errbuf);
+ goto out;
+ }
+
+ if (fromsnap != NULL && recursive) {
+ nvlist_t *renamed = NULL;
+ nvpair_t *pair = NULL;
+
+ (void) strlcpy(tofs, destname, sizeof (tofs));
+ if (flags->isprefix) {
+ struct drr_begin *drrb = &drr->drr_u.drr_begin;
+ int i;
+
+ if (flags->istail) {
+ cp = strrchr(drrb->drr_toname, '/');
+ if (cp == NULL) {
+ (void) strlcat(tofs, "/",
+ sizeof (tofs));
+ i = 0;
+ } else {
+ i = (cp - drrb->drr_toname);
+ }
+ } else {
+ i = strcspn(drrb->drr_toname, "/@");
+ }
+ /* zfs_receive_one() will create_parents() */
+ (void) strlcat(tofs, &drrb->drr_toname[i],
+ sizeof (tofs));
+ *strchr(tofs, '@') = '\0';
+ }
+
+ if (!flags->dryrun && !flags->nomount) {
+ VERIFY(0 == nvlist_alloc(&renamed,
+ NV_UNIQUE_NAME, 0));
+ }
+
+ softerr = recv_incremental_replication(hdl, tofs, flags,
+ stream_nv, stream_avl, renamed);
+
+ /* Unmount renamed filesystems before receiving. */
+ while ((pair = nvlist_next_nvpair(renamed,
+ pair)) != NULL) {
+ zfs_handle_t *zhp;
+ prop_changelist_t *clp = NULL;
+
+ zhp = zfs_open(hdl, nvpair_name(pair),
+ ZFS_TYPE_FILESYSTEM);
+ if (zhp != NULL) {
+ clp = changelist_gather(zhp,
+ ZFS_PROP_MOUNTPOINT, 0, 0);
+ zfs_close(zhp);
+ if (clp != NULL) {
+ softerr |=
+ changelist_prefix(clp);
+ changelist_free(clp);
+ }
+ }
+ }
+
+ nvlist_free(renamed);
+ }
+ }
+
+ /*
+ * Get the fs specified by the first path in the stream (the top level
+ * specified by 'zfs send') and pass it to each invocation of
+ * zfs_receive_one().
+ */
+ (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
+ sizeof (sendfs));
+ if ((cp = strchr(sendfs, '@')) != NULL) {
+ *cp = '\0';
+ /*
+ * Find the "sendsnap", the final snapshot in a replication
+ * stream. zfs_receive_one() handles certain errors
+ * differently, depending on if the contained stream is the
+ * last one or not.
+ */
+ sendsnap = (cp + 1);
+ }
+
+ /* Finally, receive each contained stream */
+ do {
+ /*
+ * we should figure out if it has a recoverable
+ * error, in which case do a recv_skip() and drive on.
+ * Note, if we fail due to already having this guid,
+ * zfs_receive_one() will take care of it (ie,
+ * recv_skip() and return 0).
+ */
+ error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
+ sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
+ action_handlep, sendsnap);
+ if (error == ENODATA) {
+ error = 0;
+ break;
+ }
+ anyerr |= error;
+ } while (error == 0);
+
+ if (drr->drr_payloadlen != 0 && recursive && fromsnap != NULL) {
+ /*
+ * Now that we have the fs's they sent us, try the
+ * renames again.
+ */
+ softerr = recv_incremental_replication(hdl, tofs, flags,
+ stream_nv, stream_avl, NULL);
+ }
+
+out:
+ fsavl_destroy(stream_avl);
+ nvlist_free(stream_nv);
+ if (softerr)
+ error = -2;
+ if (anyerr)
+ error = -1;
+ return (error);
+}
+
+static void
+trunc_prop_errs(int truncated)
+{
+ ASSERT(truncated != 0);
+
+ if (truncated == 1)
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "1 more property could not be set\n"));
+ else
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%d more properties could not be set\n"), truncated);
+}
+
+static int
+recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
+{
+ dmu_replay_record_t *drr;
+ void *buf = zfs_alloc(hdl, SPA_MAXBLOCKSIZE);
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot receive:"));
+
+ /* XXX would be great to use lseek if possible... */
+ drr = buf;
+
+ while (recv_read(hdl, fd, drr, sizeof (dmu_replay_record_t),
+ byteswap, NULL) == 0) {
+ if (byteswap)
+ drr->drr_type = BSWAP_32(drr->drr_type);
+
+ switch (drr->drr_type) {
+ case DRR_BEGIN:
+ if (drr->drr_payloadlen != 0) {
+ (void) recv_read(hdl, fd, buf,
+ drr->drr_payloadlen, B_FALSE, NULL);
+ }
+ break;
+
+ case DRR_END:
+ free(buf);
+ return (0);
+
+ case DRR_OBJECT:
+ if (byteswap) {
+ drr->drr_u.drr_object.drr_bonuslen =
+ BSWAP_32(drr->drr_u.drr_object.
+ drr_bonuslen);
+ }
+ (void) recv_read(hdl, fd, buf,
+ P2ROUNDUP(drr->drr_u.drr_object.drr_bonuslen, 8),
+ B_FALSE, NULL);
+ break;
+
+ case DRR_WRITE:
+ if (byteswap) {
+ drr->drr_u.drr_write.drr_logical_size =
+ BSWAP_64(
+ drr->drr_u.drr_write.drr_logical_size);
+ drr->drr_u.drr_write.drr_compressed_size =
+ BSWAP_64(
+ drr->drr_u.drr_write.drr_compressed_size);
+ }
+ uint64_t payload_size =
+ DRR_WRITE_PAYLOAD_SIZE(&drr->drr_u.drr_write);
+ (void) recv_read(hdl, fd, buf,
+ payload_size, B_FALSE, NULL);
+ break;
+ case DRR_SPILL:
+ if (byteswap) {
+ drr->drr_u.drr_spill.drr_length =
+ BSWAP_64(drr->drr_u.drr_spill.drr_length);
+ }
+ (void) recv_read(hdl, fd, buf,
+ drr->drr_u.drr_spill.drr_length, B_FALSE, NULL);
+ break;
+ case DRR_WRITE_EMBEDDED:
+ if (byteswap) {
+ drr->drr_u.drr_write_embedded.drr_psize =
+ BSWAP_32(drr->drr_u.drr_write_embedded.
+ drr_psize);
+ }
+ (void) recv_read(hdl, fd, buf,
+ P2ROUNDUP(drr->drr_u.drr_write_embedded.drr_psize,
+ 8), B_FALSE, NULL);
+ break;
+ case DRR_WRITE_BYREF:
+ case DRR_FREEOBJECTS:
+ case DRR_FREE:
+ break;
+
+ default:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid record type"));
+ return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+ }
+ }
+
+ free(buf);
+ return (-1);
+}
+
+static void
+recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap,
+ boolean_t resumable)
+{
+ char target_fs[ZFS_MAX_DATASET_NAME_LEN];
+
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "checksum mismatch or incomplete stream"));
+
+ if (!resumable)
+ return;
+ (void) strlcpy(target_fs, target_snap, sizeof (target_fs));
+ *strchr(target_fs, '@') = '\0';
+ zfs_handle_t *zhp = zfs_open(hdl, target_fs,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ return;
+
+ char token_buf[ZFS_MAXPROPLEN];
+ int error = zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+ token_buf, sizeof (token_buf),
+ NULL, NULL, 0, B_TRUE);
+ if (error == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "checksum mismatch or incomplete stream.\n"
+ "Partially received snapshot is saved.\n"
+ "A resuming stream can be generated on the sending "
+ "system by running:\n"
+ " zfs send -t %s"),
+ token_buf);
+ }
+ zfs_close(zhp);
+}
+
+/*
+ * Restores a backup of tosnap from the file descriptor specified by infd.
+ */
+static int
+zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
+ const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
+ dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
+ avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
+ uint64_t *action_handlep, const char *finalsnap)
+{
+ zfs_cmd_t zc = { 0 };
+ time_t begin_time;
+ int ioctl_err, ioctl_errno, err;
+ char *cp;
+ struct drr_begin *drrb = &drr->drr_u.drr_begin;
+ char errbuf[1024];
+ char prop_errbuf[1024];
+ const char *chopprefix;
+ boolean_t newfs = B_FALSE;
+ boolean_t stream_wantsnewfs;
+ uint64_t parent_snapguid = 0;
+ prop_changelist_t *clp = NULL;
+ nvlist_t *snapprops_nvlist = NULL;
+ zprop_errflags_t prop_errflags;
+ boolean_t recursive;
+ char *snapname = NULL;
+
+ begin_time = time(NULL);
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot receive"));
+
+ recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
+ ENOENT);
+
+ if (stream_avl != NULL) {
+ nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
+ &snapname);
+ nvlist_t *props;
+ int ret;
+
+ (void) nvlist_lookup_uint64(fs, "parentfromsnap",
+ &parent_snapguid);
+ err = nvlist_lookup_nvlist(fs, "props", &props);
+ if (err)
+ VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
+
+ if (flags->canmountoff) {
+ VERIFY(0 == nvlist_add_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
+ }
+ ret = zcmd_write_src_nvlist(hdl, &zc, props);
+ if (err)
+ nvlist_free(props);
+
+ if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
+ VERIFY(0 == nvlist_lookup_nvlist(props,
+ snapname, &snapprops_nvlist));
+ }
+
+ if (ret != 0)
+ return (-1);
+ }
+
+ cp = NULL;
+
+ /*
+ * Determine how much of the snapshot name stored in the stream
+ * we are going to tack on to the name they specified on the
+ * command line, and how much we are going to chop off.
+ *
+ * If they specified a snapshot, chop the entire name stored in
+ * the stream.
+ */
+ if (flags->istail) {
+ /*
+ * A filesystem was specified with -e. We want to tack on only
+ * the tail of the sent snapshot path.
+ */
+ if (strchr(tosnap, '@')) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+ "argument - snapshot not allowed with -e"));
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ }
+
+ chopprefix = strrchr(sendfs, '/');
+
+ if (chopprefix == NULL) {
+ /*
+ * The tail is the poolname, so we need to
+ * prepend a path separator.
+ */
+ int len = strlen(drrb->drr_toname);
+ cp = malloc(len + 2);
+ cp[0] = '/';
+ (void) strcpy(&cp[1], drrb->drr_toname);
+ chopprefix = cp;
+ } else {
+ chopprefix = drrb->drr_toname + (chopprefix - sendfs);
+ }
+ } else if (flags->isprefix) {
+ /*
+ * A filesystem was specified with -d. We want to tack on
+ * everything but the first element of the sent snapshot path
+ * (all but the pool name).
+ */
+ if (strchr(tosnap, '@')) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+ "argument - snapshot not allowed with -d"));
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ }
+
+ chopprefix = strchr(drrb->drr_toname, '/');
+ if (chopprefix == NULL)
+ chopprefix = strchr(drrb->drr_toname, '@');
+ } else if (strchr(tosnap, '@') == NULL) {
+ /*
+ * If a filesystem was specified without -d or -e, we want to
+ * tack on everything after the fs specified by 'zfs send'.
+ */
+ chopprefix = drrb->drr_toname + strlen(sendfs);
+ } else {
+ /* A snapshot was specified as an exact path (no -d or -e). */
+ if (recursive) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cannot specify snapshot name for multi-snapshot "
+ "stream"));
+ return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+ }
+ chopprefix = drrb->drr_toname + strlen(drrb->drr_toname);
+ }
+
+ ASSERT(strstr(drrb->drr_toname, sendfs) == drrb->drr_toname);
+ ASSERT(chopprefix > drrb->drr_toname);
+ ASSERT(chopprefix <= drrb->drr_toname + strlen(drrb->drr_toname));
+ ASSERT(chopprefix[0] == '/' || chopprefix[0] == '@' ||
+ chopprefix[0] == '\0');
+
+ /*
+ * Determine name of destination snapshot, store in zc_value.
+ */
+ (void) strcpy(zc.zc_value, tosnap);
+ (void) strncat(zc.zc_value, chopprefix, sizeof (zc.zc_value));
+#ifdef __FreeBSD__
+ if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
+ zfs_ioctl_version = get_zfs_ioctl_version();
+ /*
+ * For forward compatibility hide tosnap in zc_value
+ */
+ if (zfs_ioctl_version < ZFS_IOCVER_LZC)
+ (void) strcpy(zc.zc_value + strlen(zc.zc_value) + 1, tosnap);
+#endif
+ free(cp);
+ if (!zfs_name_valid(zc.zc_value, ZFS_TYPE_SNAPSHOT)) {
+ zcmd_free_nvlists(&zc);
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ }
+
+ /*
+ * Determine the name of the origin snapshot, store in zc_string.
+ */
+ if (originsnap) {
+ (void) strncpy(zc.zc_string, originsnap, sizeof (zc.zc_string));
+ if (flags->verbose)
+ (void) printf("using provided clone origin %s\n",
+ zc.zc_string);
+ } else if (drrb->drr_flags & DRR_FLAG_CLONE) {
+ if (guid_to_name(hdl, zc.zc_value,
+ drrb->drr_fromguid, B_FALSE, zc.zc_string) != 0) {
+ zcmd_free_nvlists(&zc);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "local origin for clone %s does not exist"),
+ zc.zc_value);
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+ }
+ if (flags->verbose)
+ (void) printf("found clone origin %s\n", zc.zc_string);
+ }
+
+ boolean_t resuming = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+ DMU_BACKUP_FEATURE_RESUMING;
+ stream_wantsnewfs = (drrb->drr_fromguid == 0 ||
+ (drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && !resuming;
+
+ if (stream_wantsnewfs) {
+ /*
+ * if the parent fs does not exist, look for it based on
+ * the parent snap GUID
+ */
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot receive new filesystem stream"));
+
+ (void) strcpy(zc.zc_name, zc.zc_value);
+ cp = strrchr(zc.zc_name, '/');
+ if (cp)
+ *cp = '\0';
+ if (cp &&
+ !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
+ char suffix[ZFS_MAX_DATASET_NAME_LEN];
+ (void) strcpy(suffix, strrchr(zc.zc_value, '/'));
+ if (guid_to_name(hdl, zc.zc_name, parent_snapguid,
+ B_FALSE, zc.zc_value) == 0) {
+ *strchr(zc.zc_value, '@') = '\0';
+ (void) strcat(zc.zc_value, suffix);
+ }
+ }
+ } else {
+ /*
+ * If the fs does not exist, look for it based on the
+ * fromsnap GUID.
+ */
+ if (resuming) {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot receive resume stream"));
+ } else {
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot receive incremental stream"));
+ }
+
+ (void) strcpy(zc.zc_name, zc.zc_value);
+ *strchr(zc.zc_name, '@') = '\0';
+
+ /*
+ * If the exact receive path was specified and this is the
+ * topmost path in the stream, then if the fs does not exist we
+ * should look no further.
+ */
+ if ((flags->isprefix || (*(chopprefix = drrb->drr_toname +
+ strlen(sendfs)) != '\0' && *chopprefix != '@')) &&
+ !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
+ char snap[ZFS_MAX_DATASET_NAME_LEN];
+ (void) strcpy(snap, strchr(zc.zc_value, '@'));
+ if (guid_to_name(hdl, zc.zc_name, drrb->drr_fromguid,
+ B_FALSE, zc.zc_value) == 0) {
+ *strchr(zc.zc_value, '@') = '\0';
+ (void) strcat(zc.zc_value, snap);
+ }
+ }
+ }
+
+ (void) strcpy(zc.zc_name, zc.zc_value);
+ *strchr(zc.zc_name, '@') = '\0';
+
+ if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
+ zfs_handle_t *zhp;
+
+ /*
+ * Destination fs exists. It must be one of these cases:
+ * - an incremental send stream
+ * - the stream specifies a new fs (full stream or clone)
+ * and they want us to blow away the existing fs (and
+ * have therefore specified -F and removed any snapshots)
+ * - we are resuming a failed receive.
+ */
+ if (stream_wantsnewfs) {
+ if (!flags->force) {
+ zcmd_free_nvlists(&zc);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination '%s' exists\n"
+ "must specify -F to overwrite it"),
+ zc.zc_name);
+ return (zfs_error(hdl, EZFS_EXISTS, errbuf));
+ }
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT,
+ &zc) == 0) {
+ zcmd_free_nvlists(&zc);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination has snapshots (eg. %s)\n"
+ "must destroy them to overwrite it"),
+ zc.zc_name);
+ return (zfs_error(hdl, EZFS_EXISTS, errbuf));
+ }
+ }
+
+ if ((zhp = zfs_open(hdl, zc.zc_name,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+
+ if (stream_wantsnewfs &&
+ zhp->zfs_dmustats.dds_origin[0]) {
+ zcmd_free_nvlists(&zc);
+ zfs_close(zhp);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination '%s' is a clone\n"
+ "must destroy it to overwrite it"),
+ zc.zc_name);
+ return (zfs_error(hdl, EZFS_EXISTS, errbuf));
+ }
+
+ if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
+ stream_wantsnewfs) {
+ /* We can't do online recv in this case */
+ clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0);
+ if (clp == NULL) {
+ zfs_close(zhp);
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ if (changelist_prefix(clp) != 0) {
+ changelist_free(clp);
+ zfs_close(zhp);
+ zcmd_free_nvlists(&zc);
+ return (-1);
+ }
+ }
+
+ /*
+ * If we are resuming a newfs, set newfs here so that we will
+ * mount it if the recv succeeds this time. We can tell
+ * that it was a newfs on the first recv because the fs
+ * itself will be inconsistent (if the fs existed when we
+ * did the first recv, we would have received it into
+ * .../%recv).
+ */
+ if (resuming && zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT))
+ newfs = B_TRUE;
+
+ zfs_close(zhp);
+ } else {
+ /*
+ * Destination filesystem does not exist. Therefore we better
+ * be creating a new filesystem (either from a full backup, or
+ * a clone). It would therefore be invalid if the user
+ * specified only the pool name (i.e. if the destination name
+ * contained no slash character).
+ */
+ if (!stream_wantsnewfs ||
+ (cp = strrchr(zc.zc_name, '/')) == NULL) {
+ zcmd_free_nvlists(&zc);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination '%s' does not exist"), zc.zc_name);
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+ }
+
+ /*
+ * Trim off the final dataset component so we perform the
+ * recvbackup ioctl to the filesystems's parent.
+ */
+ *cp = '\0';
+
+ if (flags->isprefix && !flags->istail && !flags->dryrun &&
+ create_parents(hdl, zc.zc_value, strlen(tosnap)) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (zfs_error(hdl, EZFS_BADRESTORE, errbuf));
+ }
+
+ newfs = B_TRUE;
+ }
+
+ zc.zc_begin_record = *drr_noswap;
+ zc.zc_cookie = infd;
+ zc.zc_guid = flags->force;
+ zc.zc_resumable = flags->resumable;
+ if (flags->verbose) {
+ (void) printf("%s %s stream of %s into %s\n",
+ flags->dryrun ? "would receive" : "receiving",
+ drrb->drr_fromguid ? "incremental" : "full",
+ drrb->drr_toname, zc.zc_value);
+ (void) fflush(stdout);
+ }
+
+ if (flags->dryrun) {
+ zcmd_free_nvlists(&zc);
+ return (recv_skip(hdl, infd, flags->byteswap));
+ }
+
+ zc.zc_nvlist_dst = (uint64_t)(uintptr_t)prop_errbuf;
+ zc.zc_nvlist_dst_size = sizeof (prop_errbuf);
+ zc.zc_cleanup_fd = cleanup_fd;
+ zc.zc_action_handle = *action_handlep;
+
+ err = ioctl_err = zfs_ioctl(hdl, ZFS_IOC_RECV, &zc);
+ ioctl_errno = errno;
+ prop_errflags = (zprop_errflags_t)zc.zc_obj;
+
+ if (err == 0) {
+ nvlist_t *prop_errors;
+ VERIFY(0 == nvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
+ zc.zc_nvlist_dst_size, &prop_errors, 0));
+
+ nvpair_t *prop_err = NULL;
+
+ while ((prop_err = nvlist_next_nvpair(prop_errors,
+ prop_err)) != NULL) {
+ char tbuf[1024];
+ zfs_prop_t prop;
+ int intval;
+
+ prop = zfs_name_to_prop(nvpair_name(prop_err));
+ (void) nvpair_value_int32(prop_err, &intval);
+ if (strcmp(nvpair_name(prop_err),
+ ZPROP_N_MORE_ERRORS) == 0) {
+ trunc_prop_errs(intval);
+ break;
+ } else if (snapname == NULL || finalsnap == NULL ||
+ strcmp(finalsnap, snapname) == 0 ||
+ strcmp(nvpair_name(prop_err),
+ zfs_prop_to_name(ZFS_PROP_REFQUOTA)) != 0) {
+ /*
+ * Skip the special case of, for example,
+ * "refquota", errors on intermediate
+ * snapshots leading up to a final one.
+ * That's why we have all of the checks above.
+ *
+ * See zfs_ioctl.c's extract_delay_props() for
+ * a list of props which can fail on
+ * intermediate snapshots, but shouldn't
+ * affect the overall receive.
+ */
+ (void) snprintf(tbuf, sizeof (tbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot receive %s property on %s"),
+ nvpair_name(prop_err), zc.zc_name);
+ zfs_setprop_error(hdl, prop, intval, tbuf);
+ }
+ }
+ nvlist_free(prop_errors);
+ }
+
+ zc.zc_nvlist_dst = 0;
+ zc.zc_nvlist_dst_size = 0;
+ zcmd_free_nvlists(&zc);
+
+ if (err == 0 && snapprops_nvlist) {
+ zfs_cmd_t zc2 = { 0 };
+
+ (void) strcpy(zc2.zc_name, zc.zc_value);
+ zc2.zc_cookie = B_TRUE; /* received */
+ if (zcmd_write_src_nvlist(hdl, &zc2, snapprops_nvlist) == 0) {
+ (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc2);
+ zcmd_free_nvlists(&zc2);
+ }
+ }
+
+ if (err && (ioctl_errno == ENOENT || ioctl_errno == EEXIST)) {
+ /*
+ * It may be that this snapshot already exists,
+ * in which case we want to consume & ignore it
+ * rather than failing.
+ */
+ avl_tree_t *local_avl;
+ nvlist_t *local_nv, *fs;
+ cp = strchr(zc.zc_value, '@');
+
+ /*
+ * XXX Do this faster by just iterating over snaps in
+ * this fs. Also if zc_value does not exist, we will
+ * get a strange "does not exist" error message.
+ */
+ *cp = '\0';
+ if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, B_FALSE,
+ B_FALSE, B_FALSE, &local_nv, &local_avl) == 0) {
+ *cp = '@';
+ fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
+ fsavl_destroy(local_avl);
+ nvlist_free(local_nv);
+
+ if (fs != NULL) {
+ if (flags->verbose) {
+ (void) printf("snap %s already exists; "
+ "ignoring\n", zc.zc_value);
+ }
+ err = ioctl_err = recv_skip(hdl, infd,
+ flags->byteswap);
+ }
+ }
+ *cp = '@';
+ }
+
+ if (ioctl_err != 0) {
+ switch (ioctl_errno) {
+ case ENODEV:
+ cp = strchr(zc.zc_value, '@');
+ *cp = '\0';
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "most recent snapshot of %s does not\n"
+ "match incremental source"), zc.zc_value);
+ (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
+ *cp = '@';
+ break;
+ case ETXTBSY:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination %s has been modified\n"
+ "since most recent snapshot"), zc.zc_name);
+ (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
+ break;
+ case EEXIST:
+ cp = strchr(zc.zc_value, '@');
+ if (newfs) {
+ /* it's the containing fs that exists */
+ *cp = '\0';
+ }
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination already exists"));
+ (void) zfs_error_fmt(hdl, EZFS_EXISTS,
+ dgettext(TEXT_DOMAIN, "cannot restore to %s"),
+ zc.zc_value);
+ *cp = '@';
+ break;
+ case EINVAL:
+ (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+ break;
+ case ECKSUM:
+ recv_ecksum_set_aux(hdl, zc.zc_value, flags->resumable);
+ (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+ break;
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded to receive this stream."));
+ (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+ break;
+ case EDQUOT:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination %s space quota exceeded"), zc.zc_name);
+ (void) zfs_error(hdl, EZFS_NOSPC, errbuf);
+ break;
+ default:
+ (void) zfs_standard_error(hdl, ioctl_errno, errbuf);
+ }
+ }
+
+ /*
+ * Mount the target filesystem (if created). Also mount any
+ * children of the target filesystem if we did a replication
+ * receive (indicated by stream_avl being non-NULL).
+ */
+ cp = strchr(zc.zc_value, '@');
+ if (cp && (ioctl_err == 0 || !newfs)) {
+ zfs_handle_t *h;
+
+ *cp = '\0';
+ h = zfs_open(hdl, zc.zc_value,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (h != NULL) {
+ if (h->zfs_type == ZFS_TYPE_VOLUME) {
+ *cp = '@';
+ } else if (newfs || stream_avl) {
+ /*
+ * Track the first/top of hierarchy fs,
+ * for mounting and sharing later.
+ */
+ if (top_zfs && *top_zfs == NULL)
+ *top_zfs = zfs_strdup(hdl, zc.zc_value);
+ }
+ zfs_close(h);
+ }
+ *cp = '@';
+ }
+
+ if (clp) {
+ if (!flags->nomount)
+ err |= changelist_postfix(clp);
+ changelist_free(clp);
+ }
+
+ if (prop_errflags & ZPROP_ERR_NOCLEAR) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "
+ "failed to clear unreceived properties on %s"),
+ zc.zc_name);
+ (void) fprintf(stderr, "\n");
+ }
+ if (prop_errflags & ZPROP_ERR_NORESTORE) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "
+ "failed to restore original properties on %s"),
+ zc.zc_name);
+ (void) fprintf(stderr, "\n");
+ }
+
+ if (err || ioctl_err)
+ return (-1);
+
+ *action_handlep = zc.zc_action_handle;
+
+ if (flags->verbose) {
+ char buf1[64];
+ char buf2[64];
+ uint64_t bytes = zc.zc_cookie;
+ time_t delta = time(NULL) - begin_time;
+ if (delta == 0)
+ delta = 1;
+ zfs_nicenum(bytes, buf1, sizeof (buf1));
+ zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
+
+ (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
+ buf1, delta, buf2);
+ }
+
+ return (0);
+}
+
+static int
+zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
+ const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
+ nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
+ uint64_t *action_handlep, const char *finalsnap)
+{
+ int err;
+ dmu_replay_record_t drr, drr_noswap;
+ struct drr_begin *drrb = &drr.drr_u.drr_begin;
+ char errbuf[1024];
+ zio_cksum_t zcksum = { 0 };
+ uint64_t featureflags;
+ int hdrtype;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot receive"));
+
+ if (flags->isprefix &&
+ !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
+ "(%s) does not exist"), tosnap);
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+ }
+ if (originsnap &&
+ !zfs_dataset_exists(hdl, originsnap, ZFS_TYPE_DATASET)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified origin fs "
+ "(%s) does not exist"), originsnap);
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+ }
+
+ /* read in the BEGIN record */
+ if (0 != (err = recv_read(hdl, infd, &drr, sizeof (drr), B_FALSE,
+ &zcksum)))
+ return (err);
+
+ if (drr.drr_type == DRR_END || drr.drr_type == BSWAP_32(DRR_END)) {
+ /* It's the double end record at the end of a package */
+ return (ENODATA);
+ }
+
+ /* the kernel needs the non-byteswapped begin record */
+ drr_noswap = drr;
+
+ flags->byteswap = B_FALSE;
+ if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
+ /*
+ * We computed the checksum in the wrong byteorder in
+ * recv_read() above; do it again correctly.
+ */
+ bzero(&zcksum, sizeof (zio_cksum_t));
+ (void) fletcher_4_incremental_byteswap(&drr,
+ sizeof (drr), &zcksum);
+ flags->byteswap = B_TRUE;
+
+ drr.drr_type = BSWAP_32(drr.drr_type);
+ drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen);
+ drrb->drr_magic = BSWAP_64(drrb->drr_magic);
+ drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo);
+ drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);
+ drrb->drr_type = BSWAP_32(drrb->drr_type);
+ drrb->drr_flags = BSWAP_32(drrb->drr_flags);
+ drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
+ drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);
+ }
+
+ if (drrb->drr_magic != DMU_BACKUP_MAGIC || drr.drr_type != DRR_BEGIN) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+ "stream (bad magic number)"));
+ return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+ }
+
+ featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+ hdrtype = DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo);
+
+ if (!DMU_STREAM_SUPPORTED(featureflags) ||
+ (hdrtype != DMU_SUBSTREAM && hdrtype != DMU_COMPOUNDSTREAM)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "stream has unsupported feature, feature flags = %lx"),
+ featureflags);
+ return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+ }
+
+ if (strchr(drrb->drr_toname, '@') == NULL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+ "stream (bad snapshot name)"));
+ return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+ }
+
+ if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
+ char nonpackage_sendfs[ZFS_MAX_DATASET_NAME_LEN];
+ if (sendfs == NULL) {
+ /*
+ * We were not called from zfs_receive_package(). Get
+ * the fs specified by 'zfs send'.
+ */
+ char *cp;
+ (void) strlcpy(nonpackage_sendfs,
+ drr.drr_u.drr_begin.drr_toname,
+ sizeof (nonpackage_sendfs));
+ if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
+ *cp = '\0';
+ sendfs = nonpackage_sendfs;
+ VERIFY(finalsnap == NULL);
+ }
+ return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
+ &drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
+ cleanup_fd, action_handlep, finalsnap));
+ } else {
+ assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
+ DMU_COMPOUNDSTREAM);
+ return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
+ &zcksum, top_zfs, cleanup_fd, action_handlep));
+ }
+}
+
+/*
+ * Restores a backup of tosnap from the file descriptor specified by infd.
+ * Return 0 on total success, -2 if some things couldn't be
+ * destroyed/renamed/promoted, -1 if some things couldn't be received.
+ * (-1 will override -2, if -1 and the resumable flag was specified the
+ * transfer can be resumed if the sending side supports it).
+ */
+int
+zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
+ recvflags_t *flags, int infd, avl_tree_t *stream_avl)
+{
+ char *top_zfs = NULL;
+ int err;
+ int cleanup_fd;
+ uint64_t action_handle = 0;
+ char *originsnap = NULL;
+ if (props) {
+ err = nvlist_lookup_string(props, "origin", &originsnap);
+ if (err && err != ENOENT)
+ return (err);
+ }
+
+ cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
+ VERIFY(cleanup_fd >= 0);
+
+ err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
+ stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
+
+ VERIFY(0 == close(cleanup_fd));
+
+ if (err == 0 && !flags->nomount && top_zfs) {
+ zfs_handle_t *zhp;
+ prop_changelist_t *clp;
+
+ zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
+ if (zhp != NULL) {
+ clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
+ CL_GATHER_MOUNT_ALWAYS, 0);
+ zfs_close(zhp);
+ if (clp != NULL) {
+ /* mount and share received datasets */
+ err = changelist_postfix(clp);
+ changelist_free(clp);
+ }
+ }
+ if (zhp == NULL || clp == NULL || err)
+ err = -1;
+ }
+ if (top_zfs)
+ free(top_zfs);
+
+ return (err);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c
new file mode 100644
index 000000000000..d32662022cf5
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c
@@ -0,0 +1,511 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ */
+
+/*
+ * This file contains the functions which analyze the status of a pool. This
+ * include both the status of an active pool, as well as the status exported
+ * pools. Returns one of the ZPOOL_STATUS_* defines describing the status of
+ * the pool. This status is independent (to a certain degree) from the state of
+ * the pool. A pool's state describes only whether or not it is capable of
+ * providing the necessary fault tolerance for data. The status describes the
+ * overall status of devices. A pool that is online can still have a device
+ * that is experiencing errors.
+ *
+ * Only a subset of the possible faults can be detected using 'zpool status',
+ * and not all possible errors correspond to a FMA message ID. The explanation
+ * is left up to the caller, depending on whether it is a live pool or an
+ * import.
+ */
+
+#include <libzfs.h>
+#include <string.h>
+#include <unistd.h>
+#include "libzfs_impl.h"
+#include "zfeature_common.h"
+
+/*
+ * Message ID table. This must be kept in sync with the ZPOOL_STATUS_* defines
+ * in libzfs.h. Note that there are some status results which go past the end
+ * of this table, and hence have no associated message ID.
+ */
+static char *zfs_msgid_table[] = {
+ "ZFS-8000-14", /* ZPOOL_STATUS_CORRUPT_CACHE */
+ "ZFS-8000-2Q", /* ZPOOL_STATUS_MISSING_DEV_R */
+ "ZFS-8000-3C", /* ZPOOL_STATUS_MISSING_DEV_NR */
+ "ZFS-8000-4J", /* ZPOOL_STATUS_CORRUPT_LABEL_R */
+ "ZFS-8000-5E", /* ZPOOL_STATUS_CORRUPT_LABEL_NR */
+ "ZFS-8000-6X", /* ZPOOL_STATUS_BAD_GUID_SUM */
+ "ZFS-8000-72", /* ZPOOL_STATUS_CORRUPT_POOL */
+ "ZFS-8000-8A", /* ZPOOL_STATUS_CORRUPT_DATA */
+ "ZFS-8000-9P", /* ZPOOL_STATUS_FAILING_DEV */
+ "ZFS-8000-A5", /* ZPOOL_STATUS_VERSION_NEWER */
+ "ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_MISMATCH */
+ "ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_ACTIVE */
+ "ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_REQUIRED */
+ "ZFS-8000-HC", /* ZPOOL_STATUS_IO_FAILURE_WAIT */
+ "ZFS-8000-JQ", /* ZPOOL_STATUS_IO_FAILURE_CONTINUE */
+ "ZFS-8000-MM", /* ZPOOL_STATUS_IO_FAILURE_MMP */
+ "ZFS-8000-K4", /* ZPOOL_STATUS_BAD_LOG */
+ /*
+ * The following results have no message ID.
+ * ZPOOL_STATUS_UNSUP_FEAT_READ
+ * ZPOOL_STATUS_UNSUP_FEAT_WRITE
+ * ZPOOL_STATUS_FAULTED_DEV_R
+ * ZPOOL_STATUS_FAULTED_DEV_NR
+ * ZPOOL_STATUS_VERSION_OLDER
+ * ZPOOL_STATUS_FEAT_DISABLED
+ * ZPOOL_STATUS_RESILVERING
+ * ZPOOL_STATUS_OFFLINE_DEV
+ * ZPOOL_STATUS_REMOVED_DEV
+ * ZPOOL_STATUS_OK
+ */
+};
+
+#define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
+
+/* ARGSUSED */
+static int
+vdev_missing(vdev_stat_t *vs, uint_t vsc)
+{
+ return (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ vs->vs_aux == VDEV_AUX_OPEN_FAILED);
+}
+
+/* ARGSUSED */
+static int
+vdev_faulted(vdev_stat_t *vs, uint_t vsc)
+{
+ return (vs->vs_state == VDEV_STATE_FAULTED);
+}
+
+/* ARGSUSED */
+static int
+vdev_errors(vdev_stat_t *vs, uint_t vsc)
+{
+ return (vs->vs_state == VDEV_STATE_DEGRADED ||
+ vs->vs_read_errors != 0 || vs->vs_write_errors != 0 ||
+ vs->vs_checksum_errors != 0);
+}
+
+/* ARGSUSED */
+static int
+vdev_broken(vdev_stat_t *vs, uint_t vsc)
+{
+ return (vs->vs_state == VDEV_STATE_CANT_OPEN);
+}
+
+/* ARGSUSED */
+static int
+vdev_offlined(vdev_stat_t *vs, uint_t vsc)
+{
+ return (vs->vs_state == VDEV_STATE_OFFLINE);
+}
+
+/* ARGSUSED */
+static int
+vdev_removed(vdev_stat_t *vs, uint_t vsc)
+{
+ return (vs->vs_state == VDEV_STATE_REMOVED);
+}
+
+static int
+vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc)
+{
+ return (VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
+ vs->vs_configured_ashift < vs->vs_physical_ashift);
+}
+
+/*
+ * Detect if any leaf devices that have seen errors or could not be opened.
+ */
+static boolean_t
+find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
+ boolean_t ignore_replacing)
+{
+ nvlist_t **child;
+ vdev_stat_t *vs;
+ uint_t c, vsc, children;
+
+ /*
+ * Ignore problems within a 'replacing' vdev, since we're presumably in
+ * the process of repairing any such errors, and don't want to call them
+ * out again. We'll pick up the fact that a resilver is happening
+ * later.
+ */
+ if (ignore_replacing == B_TRUE) {
+ char *type;
+
+ verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE,
+ &type) == 0);
+ if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
+ return (B_FALSE);
+ }
+
+ if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
+ &children) == 0) {
+ for (c = 0; c < children; c++)
+ if (find_vdev_problem(child[c], func, ignore_replacing))
+ return (B_TRUE);
+ } else {
+ verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &vsc) == 0);
+
+ if (func(vs, vsc) != 0)
+ return (B_TRUE);
+ }
+
+ /*
+ * Check any L2 cache devs
+ */
+ if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_L2CACHE, &child,
+ &children) == 0) {
+ for (c = 0; c < children; c++)
+ if (find_vdev_problem(child[c], func, ignore_replacing))
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Active pool health status.
+ *
+ * To determine the status for a pool, we make several passes over the config,
+ * picking the most egregious error we find. In order of importance, we do the
+ * following:
+ *
+ * - Check for a complete and valid configuration
+ * - Look for any faulted or missing devices in a non-replicated config
+ * - Check for any data errors
+ * - Check for any faulted or missing devices in a replicated config
+ * - Look for any devices showing errors
+ * - Check for any resilvering devices
+ *
+ * There can obviously be multiple errors within a single pool, so this routine
+ * only picks the most damaging of all the current errors to report.
+ */
+static zpool_status_t
+check_status(nvlist_t *config, boolean_t isimport)
+{
+ nvlist_t *nvroot;
+ vdev_stat_t *vs;
+ pool_scan_stat_t *ps = NULL;
+ uint_t vsc, psc;
+ uint64_t nerr;
+ uint64_t version;
+ uint64_t stateval;
+ uint64_t suspended;
+ uint64_t hostid = 0;
+ unsigned long system_hostid = get_system_hostid();
+
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+ &version) == 0);
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &vsc) == 0);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+ &stateval) == 0);
+
+ /*
+ * Currently resilvering a vdev
+ */
+ (void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS,
+ (uint64_t **)&ps, &psc);
+ if (ps != NULL && ps->pss_func == POOL_SCAN_RESILVER &&
+ ps->pss_state == DSS_SCANNING)
+ return (ZPOOL_STATUS_RESILVERING);
+
+ /*
+ * The multihost property is set and the pool may be active.
+ */
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ vs->vs_aux == VDEV_AUX_ACTIVE) {
+ mmp_state_t mmp_state;
+ nvlist_t *nvinfo;
+
+ nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
+ mmp_state = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_STATE);
+
+ if (mmp_state == MMP_STATE_ACTIVE)
+ return (ZPOOL_STATUS_HOSTID_ACTIVE);
+ else if (mmp_state == MMP_STATE_NO_HOSTID)
+ return (ZPOOL_STATUS_HOSTID_REQUIRED);
+ else
+ return (ZPOOL_STATUS_HOSTID_MISMATCH);
+ }
+
+ /*
+ * Pool last accessed by another system.
+ */
+ (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
+ if (hostid != 0 && (unsigned long)hostid != system_hostid &&
+ stateval == POOL_STATE_ACTIVE)
+ return (ZPOOL_STATUS_HOSTID_MISMATCH);
+
+ /*
+ * Newer on-disk version.
+ */
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ vs->vs_aux == VDEV_AUX_VERSION_NEWER)
+ return (ZPOOL_STATUS_VERSION_NEWER);
+
+ /*
+ * Unsupported feature(s).
+ */
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ vs->vs_aux == VDEV_AUX_UNSUP_FEAT) {
+ nvlist_t *nvinfo;
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO,
+ &nvinfo) == 0);
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_CAN_RDONLY))
+ return (ZPOOL_STATUS_UNSUP_FEAT_WRITE);
+ return (ZPOOL_STATUS_UNSUP_FEAT_READ);
+ }
+
+ /*
+ * Check that the config is complete.
+ */
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
+ return (ZPOOL_STATUS_BAD_GUID_SUM);
+
+ /*
+ * Check whether the pool has suspended.
+ */
+ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED,
+ &suspended) == 0) {
+ uint64_t reason;
+
+ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED_REASON,
+ &reason) == 0 && reason == ZIO_SUSPEND_MMP)
+ return (ZPOOL_STATUS_IO_FAILURE_MMP);
+
+ if (suspended == ZIO_FAILURE_MODE_CONTINUE)
+ return (ZPOOL_STATUS_IO_FAILURE_CONTINUE);
+ return (ZPOOL_STATUS_IO_FAILURE_WAIT);
+ }
+
+ /*
+ * Could not read a log.
+ */
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ vs->vs_aux == VDEV_AUX_BAD_LOG) {
+ return (ZPOOL_STATUS_BAD_LOG);
+ }
+
+ /*
+ * Bad devices in non-replicated config.
+ */
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
+ return (ZPOOL_STATUS_FAULTED_DEV_NR);
+
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ find_vdev_problem(nvroot, vdev_missing, B_TRUE))
+ return (ZPOOL_STATUS_MISSING_DEV_NR);
+
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ find_vdev_problem(nvroot, vdev_broken, B_TRUE))
+ return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
+
+ /*
+ * Corrupted pool metadata
+ */
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
+ return (ZPOOL_STATUS_CORRUPT_POOL);
+
+ /*
+ * Persistent data errors.
+ */
+ if (!isimport) {
+ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
+ &nerr) == 0 && nerr != 0)
+ return (ZPOOL_STATUS_CORRUPT_DATA);
+ }
+
+ /*
+ * Missing devices in a replicated config.
+ */
+ if (find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
+ return (ZPOOL_STATUS_FAULTED_DEV_R);
+ if (find_vdev_problem(nvroot, vdev_missing, B_TRUE))
+ return (ZPOOL_STATUS_MISSING_DEV_R);
+ if (find_vdev_problem(nvroot, vdev_broken, B_TRUE))
+ return (ZPOOL_STATUS_CORRUPT_LABEL_R);
+
+ /*
+ * Devices with errors
+ */
+ if (!isimport && find_vdev_problem(nvroot, vdev_errors, B_TRUE))
+ return (ZPOOL_STATUS_FAILING_DEV);
+
+ /*
+ * Offlined devices
+ */
+ if (find_vdev_problem(nvroot, vdev_offlined, B_TRUE))
+ return (ZPOOL_STATUS_OFFLINE_DEV);
+
+ /*
+ * Removed device
+ */
+ if (find_vdev_problem(nvroot, vdev_removed, B_TRUE))
+ return (ZPOOL_STATUS_REMOVED_DEV);
+
+ /*
+ * Suboptimal, but usable, ashift configuration.
+ */
+ if (find_vdev_problem(nvroot, vdev_non_native_ashift, B_FALSE))
+ return (ZPOOL_STATUS_NON_NATIVE_ASHIFT);
+
+ /*
+ * Outdated, but usable, version
+ */
+ if (SPA_VERSION_IS_SUPPORTED(version) && version != SPA_VERSION)
+ return (ZPOOL_STATUS_VERSION_OLDER);
+
+ /*
+ * Usable pool with disabled features
+ */
+ if (version >= SPA_VERSION_FEATURES) {
+ int i;
+ nvlist_t *feat;
+
+ if (isimport) {
+ feat = fnvlist_lookup_nvlist(config,
+ ZPOOL_CONFIG_LOAD_INFO);
+ if (nvlist_exists(feat, ZPOOL_CONFIG_ENABLED_FEAT))
+ feat = fnvlist_lookup_nvlist(feat,
+ ZPOOL_CONFIG_ENABLED_FEAT);
+ } else {
+ feat = fnvlist_lookup_nvlist(config,
+ ZPOOL_CONFIG_FEATURE_STATS);
+ }
+
+ for (i = 0; i < SPA_FEATURES; i++) {
+ zfeature_info_t *fi = &spa_feature_table[i];
+ if (!nvlist_exists(feat, fi->fi_guid))
+ return (ZPOOL_STATUS_FEAT_DISABLED);
+ }
+ }
+
+ return (ZPOOL_STATUS_OK);
+}
+
+zpool_status_t
+zpool_get_status(zpool_handle_t *zhp, char **msgid)
+{
+ zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE);
+
+ if (ret >= NMSGID)
+ *msgid = NULL;
+ else
+ *msgid = zfs_msgid_table[ret];
+
+ return (ret);
+}
+
+zpool_status_t
+zpool_import_status(nvlist_t *config, char **msgid)
+{
+ zpool_status_t ret = check_status(config, B_TRUE);
+
+ if (ret >= NMSGID)
+ *msgid = NULL;
+ else
+ *msgid = zfs_msgid_table[ret];
+
+ return (ret);
+}
+
+static void
+dump_ddt_stat(const ddt_stat_t *dds, int h)
+{
+ char refcnt[6];
+ char blocks[6], lsize[6], psize[6], dsize[6];
+ char ref_blocks[6], ref_lsize[6], ref_psize[6], ref_dsize[6];
+
+ if (dds == NULL || dds->dds_blocks == 0)
+ return;
+
+ if (h == -1)
+ (void) strcpy(refcnt, "Total");
+ else
+ zfs_nicenum(1ULL << h, refcnt, sizeof (refcnt));
+
+ zfs_nicenum(dds->dds_blocks, blocks, sizeof (blocks));
+ zfs_nicenum(dds->dds_lsize, lsize, sizeof (lsize));
+ zfs_nicenum(dds->dds_psize, psize, sizeof (psize));
+ zfs_nicenum(dds->dds_dsize, dsize, sizeof (dsize));
+ zfs_nicenum(dds->dds_ref_blocks, ref_blocks, sizeof (ref_blocks));
+ zfs_nicenum(dds->dds_ref_lsize, ref_lsize, sizeof (ref_lsize));
+ zfs_nicenum(dds->dds_ref_psize, ref_psize, sizeof (ref_psize));
+ zfs_nicenum(dds->dds_ref_dsize, ref_dsize, sizeof (ref_dsize));
+
+ (void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n",
+ refcnt,
+ blocks, lsize, psize, dsize,
+ ref_blocks, ref_lsize, ref_psize, ref_dsize);
+}
+
+/*
+ * Print the DDT histogram and the column totals.
+ */
+void
+zpool_dump_ddt(const ddt_stat_t *dds_total, const ddt_histogram_t *ddh)
+{
+ int h;
+
+ (void) printf("\n");
+
+ (void) printf("bucket "
+ " allocated "
+ " referenced \n");
+ (void) printf("______ "
+ "______________________________ "
+ "______________________________\n");
+
+ (void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n",
+ "refcnt",
+ "blocks", "LSIZE", "PSIZE", "DSIZE",
+ "blocks", "LSIZE", "PSIZE", "DSIZE");
+
+ (void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n",
+ "------",
+ "------", "-----", "-----", "-----",
+ "------", "-----", "-----", "-----");
+
+ for (h = 0; h < 64; h++)
+ dump_ddt_stat(&ddh->ddh_stat[h], h);
+
+ dump_ddt_stat(dds_total, -1);
+
+ (void) printf("\n");
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
new file mode 100644
index 000000000000..8ba496abae33
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
@@ -0,0 +1,1621 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
+ * Copyright (c) 2017 Datto Inc.
+ */
+
+/*
+ * Internal utility routines for the ZFS library.
+ */
+
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <math.h>
+#include <sys/mnttab.h>
+#include <sys/mntent.h>
+#include <sys/types.h>
+#include <libcmdutils.h>
+
+#include <libzfs.h>
+#include <libzfs_core.h>
+
+#include "libzfs_impl.h"
+#include "zfs_prop.h"
+#include "zfs_comutil.h"
+#include "zfeature_common.h"
+
+
+int
+libzfs_errno(libzfs_handle_t *hdl)
+{
+ return (hdl->libzfs_error);
+}
+
+const char *
+libzfs_error_action(libzfs_handle_t *hdl)
+{
+ return (hdl->libzfs_action);
+}
+
+const char *
+libzfs_error_description(libzfs_handle_t *hdl)
+{
+ if (hdl->libzfs_desc[0] != '\0')
+ return (hdl->libzfs_desc);
+
+ switch (hdl->libzfs_error) {
+ case EZFS_NOMEM:
+ return (dgettext(TEXT_DOMAIN, "out of memory"));
+ case EZFS_BADPROP:
+ return (dgettext(TEXT_DOMAIN, "invalid property value"));
+ case EZFS_PROPREADONLY:
+ return (dgettext(TEXT_DOMAIN, "read-only property"));
+ case EZFS_PROPTYPE:
+ return (dgettext(TEXT_DOMAIN, "property doesn't apply to "
+ "datasets of this type"));
+ case EZFS_PROPNONINHERIT:
+ return (dgettext(TEXT_DOMAIN, "property cannot be inherited"));
+ case EZFS_PROPSPACE:
+ return (dgettext(TEXT_DOMAIN, "invalid quota or reservation"));
+ case EZFS_BADTYPE:
+ return (dgettext(TEXT_DOMAIN, "operation not applicable to "
+ "datasets of this type"));
+ case EZFS_BUSY:
+ return (dgettext(TEXT_DOMAIN, "pool or dataset is busy"));
+ case EZFS_EXISTS:
+ return (dgettext(TEXT_DOMAIN, "pool or dataset exists"));
+ case EZFS_NOENT:
+ return (dgettext(TEXT_DOMAIN, "no such pool or dataset"));
+ case EZFS_BADSTREAM:
+ return (dgettext(TEXT_DOMAIN, "invalid backup stream"));
+ case EZFS_DSREADONLY:
+ return (dgettext(TEXT_DOMAIN, "dataset is read-only"));
+ case EZFS_VOLTOOBIG:
+ return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for "
+ "this system"));
+ case EZFS_INVALIDNAME:
+ return (dgettext(TEXT_DOMAIN, "invalid name"));
+ case EZFS_BADRESTORE:
+ return (dgettext(TEXT_DOMAIN, "unable to restore to "
+ "destination"));
+ case EZFS_BADBACKUP:
+ return (dgettext(TEXT_DOMAIN, "backup failed"));
+ case EZFS_BADTARGET:
+ return (dgettext(TEXT_DOMAIN, "invalid target vdev"));
+ case EZFS_NODEVICE:
+ return (dgettext(TEXT_DOMAIN, "no such device in pool"));
+ case EZFS_BADDEV:
+ return (dgettext(TEXT_DOMAIN, "invalid device"));
+ case EZFS_NOREPLICAS:
+ return (dgettext(TEXT_DOMAIN, "no valid replicas"));
+ case EZFS_RESILVERING:
+ return (dgettext(TEXT_DOMAIN, "currently resilvering"));
+ case EZFS_BADVERSION:
+ return (dgettext(TEXT_DOMAIN, "unsupported version or "
+ "feature"));
+ case EZFS_POOLUNAVAIL:
+ return (dgettext(TEXT_DOMAIN, "pool is unavailable"));
+ case EZFS_DEVOVERFLOW:
+ return (dgettext(TEXT_DOMAIN, "too many devices in one vdev"));
+ case EZFS_BADPATH:
+ return (dgettext(TEXT_DOMAIN, "must be an absolute path"));
+ case EZFS_CROSSTARGET:
+ return (dgettext(TEXT_DOMAIN, "operation crosses datasets or "
+ "pools"));
+ case EZFS_ZONED:
+ return (dgettext(TEXT_DOMAIN, "dataset in use by local zone"));
+ case EZFS_MOUNTFAILED:
+ return (dgettext(TEXT_DOMAIN, "mount failed"));
+ case EZFS_UMOUNTFAILED:
+ return (dgettext(TEXT_DOMAIN, "umount failed"));
+ case EZFS_UNSHARENFSFAILED:
+ return (dgettext(TEXT_DOMAIN, "unshare(1M) failed"));
+ case EZFS_SHARENFSFAILED:
+ return (dgettext(TEXT_DOMAIN, "share(1M) failed"));
+ case EZFS_UNSHARESMBFAILED:
+ return (dgettext(TEXT_DOMAIN, "smb remove share failed"));
+ case EZFS_SHARESMBFAILED:
+ return (dgettext(TEXT_DOMAIN, "smb add share failed"));
+ case EZFS_PERM:
+ return (dgettext(TEXT_DOMAIN, "permission denied"));
+ case EZFS_NOSPC:
+ return (dgettext(TEXT_DOMAIN, "out of space"));
+ case EZFS_FAULT:
+ return (dgettext(TEXT_DOMAIN, "bad address"));
+ case EZFS_IO:
+ return (dgettext(TEXT_DOMAIN, "I/O error"));
+ case EZFS_INTR:
+ return (dgettext(TEXT_DOMAIN, "signal received"));
+ case EZFS_ISSPARE:
+ return (dgettext(TEXT_DOMAIN, "device is reserved as a hot "
+ "spare"));
+ case EZFS_INVALCONFIG:
+ return (dgettext(TEXT_DOMAIN, "invalid vdev configuration"));
+ case EZFS_RECURSIVE:
+ return (dgettext(TEXT_DOMAIN, "recursive dataset dependency"));
+ case EZFS_NOHISTORY:
+ return (dgettext(TEXT_DOMAIN, "no history available"));
+ case EZFS_POOLPROPS:
+ return (dgettext(TEXT_DOMAIN, "failed to retrieve "
+ "pool properties"));
+ case EZFS_POOL_NOTSUP:
+ return (dgettext(TEXT_DOMAIN, "operation not supported "
+ "on this type of pool"));
+ case EZFS_POOL_INVALARG:
+ return (dgettext(TEXT_DOMAIN, "invalid argument for "
+ "this pool operation"));
+ case EZFS_NAMETOOLONG:
+ return (dgettext(TEXT_DOMAIN, "dataset name is too long"));
+ case EZFS_OPENFAILED:
+ return (dgettext(TEXT_DOMAIN, "open failed"));
+ case EZFS_NOCAP:
+ return (dgettext(TEXT_DOMAIN,
+ "disk capacity information could not be retrieved"));
+ case EZFS_LABELFAILED:
+ return (dgettext(TEXT_DOMAIN, "write of label failed"));
+ case EZFS_BADWHO:
+ return (dgettext(TEXT_DOMAIN, "invalid user/group"));
+ case EZFS_BADPERM:
+ return (dgettext(TEXT_DOMAIN, "invalid permission"));
+ case EZFS_BADPERMSET:
+ return (dgettext(TEXT_DOMAIN, "invalid permission set name"));
+ case EZFS_NODELEGATION:
+ return (dgettext(TEXT_DOMAIN, "delegated administration is "
+ "disabled on pool"));
+ case EZFS_BADCACHE:
+ return (dgettext(TEXT_DOMAIN, "invalid or missing cache file"));
+ case EZFS_ISL2CACHE:
+ return (dgettext(TEXT_DOMAIN, "device is in use as a cache"));
+ case EZFS_VDEVNOTSUP:
+ return (dgettext(TEXT_DOMAIN, "vdev specification is not "
+ "supported"));
+ case EZFS_NOTSUP:
+ return (dgettext(TEXT_DOMAIN, "operation not supported "
+ "on this dataset"));
+ case EZFS_ACTIVE_SPARE:
+ return (dgettext(TEXT_DOMAIN, "pool has active shared spare "
+ "device"));
+ case EZFS_UNPLAYED_LOGS:
+ return (dgettext(TEXT_DOMAIN, "log device has unplayed intent "
+ "logs"));
+ case EZFS_REFTAG_RELE:
+ return (dgettext(TEXT_DOMAIN, "no such tag on this dataset"));
+ case EZFS_REFTAG_HOLD:
+ return (dgettext(TEXT_DOMAIN, "tag already exists on this "
+ "dataset"));
+ case EZFS_TAGTOOLONG:
+ return (dgettext(TEXT_DOMAIN, "tag too long"));
+ case EZFS_PIPEFAILED:
+ return (dgettext(TEXT_DOMAIN, "pipe create failed"));
+ case EZFS_THREADCREATEFAILED:
+ return (dgettext(TEXT_DOMAIN, "thread create failed"));
+ case EZFS_POSTSPLIT_ONLINE:
+ return (dgettext(TEXT_DOMAIN, "disk was split from this pool "
+ "into a new one"));
+ case EZFS_SCRUB_PAUSED:
+ return (dgettext(TEXT_DOMAIN, "scrub is paused; "
+ "use 'zpool scrub' to resume"));
+ case EZFS_SCRUBBING:
+ return (dgettext(TEXT_DOMAIN, "currently scrubbing; "
+ "use 'zpool scrub -s' to cancel current scrub"));
+ case EZFS_NO_SCRUB:
+ return (dgettext(TEXT_DOMAIN, "there is no active scrub"));
+ case EZFS_DIFF:
+ return (dgettext(TEXT_DOMAIN, "unable to generate diffs"));
+ case EZFS_DIFFDATA:
+ return (dgettext(TEXT_DOMAIN, "invalid diff data"));
+ case EZFS_POOLREADONLY:
+ return (dgettext(TEXT_DOMAIN, "pool is read-only"));
+ case EZFS_NO_PENDING:
+ return (dgettext(TEXT_DOMAIN, "operation is not "
+ "in progress"));
+ case EZFS_CHECKPOINT_EXISTS:
+ return (dgettext(TEXT_DOMAIN, "checkpoint exists"));
+ case EZFS_DISCARDING_CHECKPOINT:
+ return (dgettext(TEXT_DOMAIN, "currently discarding "
+ "checkpoint"));
+ case EZFS_NO_CHECKPOINT:
+ return (dgettext(TEXT_DOMAIN, "checkpoint does not exist"));
+ case EZFS_DEVRM_IN_PROGRESS:
+ return (dgettext(TEXT_DOMAIN, "device removal in progress"));
+ case EZFS_VDEV_TOO_BIG:
+ return (dgettext(TEXT_DOMAIN, "device exceeds supported size"));
+ case EZFS_ACTIVE_POOL:
+ return (dgettext(TEXT_DOMAIN, "pool is imported on a "
+ "different host"));
+ case EZFS_TOOMANY:
+ return (dgettext(TEXT_DOMAIN, "argument list too long"));
+ case EZFS_INITIALIZING:
+ return (dgettext(TEXT_DOMAIN, "currently initializing"));
+ case EZFS_NO_INITIALIZE:
+ return (dgettext(TEXT_DOMAIN, "there is no active "
+ "initialization"));
+ case EZFS_UNKNOWN:
+ return (dgettext(TEXT_DOMAIN, "unknown error"));
+ default:
+ assert(hdl->libzfs_error == 0);
+ return (dgettext(TEXT_DOMAIN, "no error"));
+ }
+}
+
+/*PRINTFLIKE2*/
+void
+zfs_error_aux(libzfs_handle_t *hdl, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ (void) vsnprintf(hdl->libzfs_desc, sizeof (hdl->libzfs_desc),
+ fmt, ap);
+ hdl->libzfs_desc_active = 1;
+
+ va_end(ap);
+}
+
+static void
+zfs_verror(libzfs_handle_t *hdl, int error, const char *fmt, va_list ap)
+{
+ (void) vsnprintf(hdl->libzfs_action, sizeof (hdl->libzfs_action),
+ fmt, ap);
+ hdl->libzfs_error = error;
+
+ if (hdl->libzfs_desc_active)
+ hdl->libzfs_desc_active = 0;
+ else
+ hdl->libzfs_desc[0] = '\0';
+
+ if (hdl->libzfs_printerr) {
+ if (error == EZFS_UNKNOWN) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "internal "
+ "error: %s\n"), libzfs_error_description(hdl));
+ abort();
+ }
+
+ (void) fprintf(stderr, "%s: %s\n", hdl->libzfs_action,
+ libzfs_error_description(hdl));
+ if (error == EZFS_NOMEM)
+ exit(1);
+ }
+}
+
+int
+zfs_error(libzfs_handle_t *hdl, int error, const char *msg)
+{
+ return (zfs_error_fmt(hdl, error, "%s", msg));
+}
+
+/*PRINTFLIKE3*/
+int
+zfs_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ zfs_verror(hdl, error, fmt, ap);
+
+ va_end(ap);
+
+ return (-1);
+}
+
+static int
+zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,
+ va_list ap)
+{
+ switch (error) {
+ case EPERM:
+ case EACCES:
+ zfs_verror(hdl, EZFS_PERM, fmt, ap);
+ return (-1);
+
+ case ECANCELED:
+ zfs_verror(hdl, EZFS_NODELEGATION, fmt, ap);
+ return (-1);
+
+ case EIO:
+ zfs_verror(hdl, EZFS_IO, fmt, ap);
+ return (-1);
+
+ case EFAULT:
+ zfs_verror(hdl, EZFS_FAULT, fmt, ap);
+ return (-1);
+
+ case EINTR:
+ zfs_verror(hdl, EZFS_INTR, fmt, ap);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+zfs_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
+{
+ return (zfs_standard_error_fmt(hdl, error, "%s", msg));
+}
+
+/*PRINTFLIKE3*/
+int
+zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if (zfs_common_error(hdl, error, fmt, ap) != 0) {
+ va_end(ap);
+ return (-1);
+ }
+
+ switch (error) {
+ case ENXIO:
+ case ENODEV:
+ case EPIPE:
+ zfs_verror(hdl, EZFS_IO, fmt, ap);
+ break;
+
+ case ENOENT:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset does not exist"));
+ zfs_verror(hdl, EZFS_NOENT, fmt, ap);
+ break;
+
+ case ENOSPC:
+ case EDQUOT:
+ zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
+ va_end(ap);
+ return (-1);
+
+ case EEXIST:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset already exists"));
+ zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
+ break;
+
+ case EBUSY:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset is busy"));
+ zfs_verror(hdl, EZFS_BUSY, fmt, ap);
+ break;
+ case EROFS:
+ zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
+ break;
+ case ENAMETOOLONG:
+ zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap);
+ break;
+ case ENOTSUP:
+ zfs_verror(hdl, EZFS_BADVERSION, fmt, ap);
+ break;
+ case EAGAIN:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool I/O is currently suspended"));
+ zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
+ break;
+ case EREMOTEIO:
+ zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap);
+ break;
+ default:
+ zfs_error_aux(hdl, strerror(error));
+ zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
+ break;
+ }
+
+ va_end(ap);
+ return (-1);
+}
+
+int
+zpool_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
+{
+ return (zpool_standard_error_fmt(hdl, error, "%s", msg));
+}
+
+/*PRINTFLIKE3*/
+int
+zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if (zfs_common_error(hdl, error, fmt, ap) != 0) {
+ va_end(ap);
+ return (-1);
+ }
+
+ switch (error) {
+ case ENODEV:
+ zfs_verror(hdl, EZFS_NODEVICE, fmt, ap);
+ break;
+
+ case ENOENT:
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "no such pool or dataset"));
+ zfs_verror(hdl, EZFS_NOENT, fmt, ap);
+ break;
+
+ case EEXIST:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool already exists"));
+ zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
+ break;
+
+ case EBUSY:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy"));
+ zfs_verror(hdl, EZFS_BUSY, fmt, ap);
+ break;
+
+ case ENXIO:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more devices is currently unavailable"));
+ zfs_verror(hdl, EZFS_BADDEV, fmt, ap);
+ break;
+
+ case ENAMETOOLONG:
+ zfs_verror(hdl, EZFS_DEVOVERFLOW, fmt, ap);
+ break;
+
+ case ENOTSUP:
+ zfs_verror(hdl, EZFS_POOL_NOTSUP, fmt, ap);
+ break;
+
+ case EINVAL:
+ zfs_verror(hdl, EZFS_POOL_INVALARG, fmt, ap);
+ break;
+
+ case ENOSPC:
+ case EDQUOT:
+ zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
+ va_end(ap);
+ return (-1);
+
+ case EAGAIN:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool I/O is currently suspended"));
+ zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
+ break;
+
+ case EROFS:
+ zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
+ break;
+ /* There is no pending operation to cancel */
+ case ESRCH:
+ zfs_verror(hdl, EZFS_NO_PENDING, fmt, ap);
+ break;
+ case EREMOTEIO:
+ zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap);
+ break;
+ case ZFS_ERR_CHECKPOINT_EXISTS:
+ zfs_verror(hdl, EZFS_CHECKPOINT_EXISTS, fmt, ap);
+ break;
+ case ZFS_ERR_DISCARDING_CHECKPOINT:
+ zfs_verror(hdl, EZFS_DISCARDING_CHECKPOINT, fmt, ap);
+ break;
+ case ZFS_ERR_NO_CHECKPOINT:
+ zfs_verror(hdl, EZFS_NO_CHECKPOINT, fmt, ap);
+ break;
+ case ZFS_ERR_DEVRM_IN_PROGRESS:
+ zfs_verror(hdl, EZFS_DEVRM_IN_PROGRESS, fmt, ap);
+ break;
+ case ZFS_ERR_VDEV_TOO_BIG:
+ zfs_verror(hdl, EZFS_VDEV_TOO_BIG, fmt, ap);
+ break;
+ default:
+ zfs_error_aux(hdl, strerror(error));
+ zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
+ }
+
+ va_end(ap);
+ return (-1);
+}
+
+/*
+ * Display an out of memory error message and abort the current program.
+ */
+int
+no_memory(libzfs_handle_t *hdl)
+{
+ return (zfs_error(hdl, EZFS_NOMEM, "internal error"));
+}
+
+/*
+ * A safe form of malloc() which will die if the allocation fails.
+ */
+void *
+zfs_alloc(libzfs_handle_t *hdl, size_t size)
+{
+ void *data;
+
+ if ((data = calloc(1, size)) == NULL)
+ (void) no_memory(hdl);
+
+ return (data);
+}
+
+/*
+ * A safe form of asprintf() which will die if the allocation fails.
+ */
+/*PRINTFLIKE2*/
+char *
+zfs_asprintf(libzfs_handle_t *hdl, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+ int err;
+
+ va_start(ap, fmt);
+
+ err = vasprintf(&ret, fmt, ap);
+
+ va_end(ap);
+
+ if (err < 0)
+ (void) no_memory(hdl);
+
+ return (ret);
+}
+
+/*
+ * A safe form of realloc(), which also zeroes newly allocated space.
+ */
+void *
+zfs_realloc(libzfs_handle_t *hdl, void *ptr, size_t oldsize, size_t newsize)
+{
+ void *ret;
+
+ if ((ret = realloc(ptr, newsize)) == NULL) {
+ (void) no_memory(hdl);
+ return (NULL);
+ }
+
+ bzero((char *)ret + oldsize, (newsize - oldsize));
+ return (ret);
+}
+
+/*
+ * A safe form of strdup() which will die if the allocation fails.
+ */
+char *
+zfs_strdup(libzfs_handle_t *hdl, const char *str)
+{
+ char *ret;
+
+ if ((ret = strdup(str)) == NULL)
+ (void) no_memory(hdl);
+
+ return (ret);
+}
+
+/*
+ * Convert a number to an appropriately human-readable output.
+ */
+void
+zfs_nicenum(uint64_t num, char *buf, size_t buflen)
+{
+ nicenum(num, buf, buflen);
+}
+
+void
+libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr)
+{
+ hdl->libzfs_printerr = printerr;
+}
+
+static int
+libzfs_load(void)
+{
+ int error;
+
+ if (modfind("zfs") < 0) {
+ /* Not present in kernel, try loading it. */
+ if (kldload("zfs") < 0 || modfind("zfs") < 0) {
+ if (errno != EEXIST)
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+libzfs_handle_t *
+libzfs_init(void)
+{
+ libzfs_handle_t *hdl;
+
+ if ((hdl = calloc(1, sizeof (libzfs_handle_t))) == NULL) {
+ return (NULL);
+ }
+
+ if (libzfs_load() < 0) {
+ free(hdl);
+ return (NULL);
+ }
+
+ if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
+ free(hdl);
+ return (NULL);
+ }
+
+ if ((hdl->libzfs_mnttab = fopen(MNTTAB, "r")) == NULL) {
+ (void) close(hdl->libzfs_fd);
+ free(hdl);
+ return (NULL);
+ }
+
+ hdl->libzfs_sharetab = fopen(ZFS_EXPORTS_PATH, "r");
+
+ if (libzfs_core_init() != 0) {
+ (void) close(hdl->libzfs_fd);
+ (void) fclose(hdl->libzfs_mnttab);
+ (void) fclose(hdl->libzfs_sharetab);
+ free(hdl);
+ return (NULL);
+ }
+
+ zfs_prop_init();
+ zpool_prop_init();
+ zpool_feature_init();
+ libzfs_mnttab_init(hdl);
+
+ if (getenv("ZFS_PROP_DEBUG") != NULL) {
+ hdl->libzfs_prop_debug = B_TRUE;
+ }
+
+ return (hdl);
+}
+
+void
+libzfs_fini(libzfs_handle_t *hdl)
+{
+ (void) close(hdl->libzfs_fd);
+ if (hdl->libzfs_mnttab)
+ (void) fclose(hdl->libzfs_mnttab);
+ if (hdl->libzfs_sharetab)
+ (void) fclose(hdl->libzfs_sharetab);
+ zfs_uninit_libshare(hdl);
+ zpool_free_handles(hdl);
+#ifdef illumos
+ libzfs_fru_clear(hdl, B_TRUE);
+#endif
+ namespace_clear(hdl);
+ libzfs_mnttab_fini(hdl);
+ libzfs_core_fini();
+ free(hdl);
+}
+
+libzfs_handle_t *
+zpool_get_handle(zpool_handle_t *zhp)
+{
+ return (zhp->zpool_hdl);
+}
+
+libzfs_handle_t *
+zfs_get_handle(zfs_handle_t *zhp)
+{
+ return (zhp->zfs_hdl);
+}
+
+zpool_handle_t *
+zfs_get_pool_handle(const zfs_handle_t *zhp)
+{
+ return (zhp->zpool_hdl);
+}
+
+/*
+ * Given a name, determine whether or not it's a valid path
+ * (starts with '/' or "./"). If so, walk the mnttab trying
+ * to match the device number. If not, treat the path as an
+ * fs/vol/snap/bkmark name.
+ */
+zfs_handle_t *
+zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype)
+{
+ struct stat64 statbuf;
+ struct extmnttab entry;
+ int ret;
+
+ if (path[0] != '/' && strncmp(path, "./", strlen("./")) != 0) {
+ /*
+ * It's not a valid path, assume it's a name of type 'argtype'.
+ */
+ return (zfs_open(hdl, path, argtype));
+ }
+
+ if (stat64(path, &statbuf) != 0) {
+ (void) fprintf(stderr, "%s: %s\n", path, strerror(errno));
+ return (NULL);
+ }
+
+#ifdef illumos
+ rewind(hdl->libzfs_mnttab);
+ while ((ret = getextmntent(hdl->libzfs_mnttab, &entry, 0)) == 0) {
+ if (makedevice(entry.mnt_major, entry.mnt_minor) ==
+ statbuf.st_dev) {
+ break;
+ }
+ }
+#else
+ {
+ struct statfs sfs;
+
+ ret = statfs(path, &sfs);
+ if (ret == 0)
+ statfs2mnttab(&sfs, &entry);
+ else {
+ (void) fprintf(stderr, "%s: %s\n", path,
+ strerror(errno));
+ }
+ }
+#endif /* illumos */
+ if (ret != 0) {
+ return (NULL);
+ }
+
+ if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
+ (void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"),
+ path);
+ return (NULL);
+ }
+
+ return (zfs_open(hdl, entry.mnt_special, ZFS_TYPE_FILESYSTEM));
+}
+
+/*
+ * Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from
+ * an ioctl().
+ */
+int
+zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
+{
+ if (len == 0)
+ len = 16 * 1024;
+ zc->zc_nvlist_dst_size = len;
+ zc->zc_nvlist_dst =
+ (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
+ if (zc->zc_nvlist_dst == 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Called when an ioctl() which returns an nvlist fails with ENOMEM. This will
+ * expand the nvlist to the size specified in 'zc_nvlist_dst_size', which was
+ * filled in by the kernel to indicate the actual required size.
+ */
+int
+zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)
+{
+ free((void *)(uintptr_t)zc->zc_nvlist_dst);
+ zc->zc_nvlist_dst =
+ (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
+ if (zc->zc_nvlist_dst == 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Called to free the src and dst nvlists stored in the command structure.
+ */
+void
+zcmd_free_nvlists(zfs_cmd_t *zc)
+{
+ free((void *)(uintptr_t)zc->zc_nvlist_conf);
+ free((void *)(uintptr_t)zc->zc_nvlist_src);
+ free((void *)(uintptr_t)zc->zc_nvlist_dst);
+ zc->zc_nvlist_conf = NULL;
+ zc->zc_nvlist_src = NULL;
+ zc->zc_nvlist_dst = NULL;
+}
+
+static int
+zcmd_write_nvlist_com(libzfs_handle_t *hdl, uint64_t *outnv, uint64_t *outlen,
+ nvlist_t *nvl)
+{
+ char *packed;
+ size_t len;
+
+ verify(nvlist_size(nvl, &len, NV_ENCODE_NATIVE) == 0);
+
+ if ((packed = zfs_alloc(hdl, len)) == NULL)
+ return (-1);
+
+ verify(nvlist_pack(nvl, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
+
+ *outnv = (uint64_t)(uintptr_t)packed;
+ *outlen = len;
+
+ return (0);
+}
+
+int
+zcmd_write_conf_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl)
+{
+ return (zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_conf,
+ &zc->zc_nvlist_conf_size, nvl));
+}
+
+int
+zcmd_write_src_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl)
+{
+ return (zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_src,
+ &zc->zc_nvlist_src_size, nvl));
+}
+
+/*
+ * Unpacks an nvlist from the ZFS ioctl command structure.
+ */
+int
+zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
+{
+ if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst,
+ zc->zc_nvlist_dst_size, nvlp, 0) != 0)
+ return (no_memory(hdl));
+
+ return (0);
+}
+
+int
+zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
+{
+ return (ioctl(hdl->libzfs_fd, request, zc));
+}
+
+/*
+ * ================================================================
+ * API shared by zfs and zpool property management
+ * ================================================================
+ */
+
+static void
+zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
+{
+ zprop_list_t *pl = cbp->cb_proplist;
+ int i;
+ char *title;
+ size_t len;
+
+ cbp->cb_first = B_FALSE;
+ if (cbp->cb_scripted)
+ return;
+
+ /*
+ * Start with the length of the column headers.
+ */
+ cbp->cb_colwidths[GET_COL_NAME] = strlen(dgettext(TEXT_DOMAIN, "NAME"));
+ cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(dgettext(TEXT_DOMAIN,
+ "PROPERTY"));
+ cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,
+ "VALUE"));
+ cbp->cb_colwidths[GET_COL_RECVD] = strlen(dgettext(TEXT_DOMAIN,
+ "RECEIVED"));
+ cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,
+ "SOURCE"));
+
+ /* first property is always NAME */
+ assert(cbp->cb_proplist->pl_prop ==
+ ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME : ZFS_PROP_NAME));
+
+ /*
+ * Go through and calculate the widths for each column. For the
+ * 'source' column, we kludge it up by taking the worst-case scenario of
+ * inheriting from the longest name. This is acceptable because in the
+ * majority of cases 'SOURCE' is the last column displayed, and we don't
+ * use the width anyway. Note that the 'VALUE' column can be oversized,
+ * if the name of the property is much longer than any values we find.
+ */
+ for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
+ /*
+ * 'PROPERTY' column
+ */
+ if (pl->pl_prop != ZPROP_INVAL) {
+ const char *propname = (type == ZFS_TYPE_POOL) ?
+ zpool_prop_to_name(pl->pl_prop) :
+ zfs_prop_to_name(pl->pl_prop);
+
+ len = strlen(propname);
+ if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
+ cbp->cb_colwidths[GET_COL_PROPERTY] = len;
+ } else {
+ len = strlen(pl->pl_user_prop);
+ if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
+ cbp->cb_colwidths[GET_COL_PROPERTY] = len;
+ }
+
+ /*
+ * 'VALUE' column. The first property is always the 'name'
+ * property that was tacked on either by /sbin/zfs's
+ * zfs_do_get() or when calling zprop_expand_list(), so we
+ * ignore its width. If the user specified the name property
+ * to display, then it will be later in the list in any case.
+ */
+ if (pl != cbp->cb_proplist &&
+ pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
+ cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
+
+ /* 'RECEIVED' column. */
+ if (pl != cbp->cb_proplist &&
+ pl->pl_recvd_width > cbp->cb_colwidths[GET_COL_RECVD])
+ cbp->cb_colwidths[GET_COL_RECVD] = pl->pl_recvd_width;
+
+ /*
+ * 'NAME' and 'SOURCE' columns
+ */
+ if (pl->pl_prop == (type == ZFS_TYPE_POOL ? ZPOOL_PROP_NAME :
+ ZFS_PROP_NAME) &&
+ pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) {
+ cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width;
+ cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width +
+ strlen(dgettext(TEXT_DOMAIN, "inherited from"));
+ }
+ }
+
+ /*
+ * Now go through and print the headers.
+ */
+ for (i = 0; i < ZFS_GET_NCOLS; i++) {
+ switch (cbp->cb_columns[i]) {
+ case GET_COL_NAME:
+ title = dgettext(TEXT_DOMAIN, "NAME");
+ break;
+ case GET_COL_PROPERTY:
+ title = dgettext(TEXT_DOMAIN, "PROPERTY");
+ break;
+ case GET_COL_VALUE:
+ title = dgettext(TEXT_DOMAIN, "VALUE");
+ break;
+ case GET_COL_RECVD:
+ title = dgettext(TEXT_DOMAIN, "RECEIVED");
+ break;
+ case GET_COL_SOURCE:
+ title = dgettext(TEXT_DOMAIN, "SOURCE");
+ break;
+ default:
+ title = NULL;
+ }
+
+ if (title != NULL) {
+ if (i == (ZFS_GET_NCOLS - 1) ||
+ cbp->cb_columns[i + 1] == GET_COL_NONE)
+ (void) printf("%s", title);
+ else
+ (void) printf("%-*s ",
+ cbp->cb_colwidths[cbp->cb_columns[i]],
+ title);
+ }
+ }
+ (void) printf("\n");
+}
+
+/*
+ * Display a single line of output, according to the settings in the callback
+ * structure.
+ */
+void
+zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
+ const char *propname, const char *value, zprop_source_t sourcetype,
+ const char *source, const char *recvd_value)
+{
+ int i;
+ const char *str = NULL;
+ char buf[128];
+
+ /*
+ * Ignore those source types that the user has chosen to ignore.
+ */
+ if ((sourcetype & cbp->cb_sources) == 0)
+ return;
+
+ if (cbp->cb_first)
+ zprop_print_headers(cbp, cbp->cb_type);
+
+ for (i = 0; i < ZFS_GET_NCOLS; i++) {
+ switch (cbp->cb_columns[i]) {
+ case GET_COL_NAME:
+ str = name;
+ break;
+
+ case GET_COL_PROPERTY:
+ str = propname;
+ break;
+
+ case GET_COL_VALUE:
+ str = value;
+ break;
+
+ case GET_COL_SOURCE:
+ switch (sourcetype) {
+ case ZPROP_SRC_NONE:
+ str = "-";
+ break;
+
+ case ZPROP_SRC_DEFAULT:
+ str = "default";
+ break;
+
+ case ZPROP_SRC_LOCAL:
+ str = "local";
+ break;
+
+ case ZPROP_SRC_TEMPORARY:
+ str = "temporary";
+ break;
+
+ case ZPROP_SRC_INHERITED:
+ (void) snprintf(buf, sizeof (buf),
+ "inherited from %s", source);
+ str = buf;
+ break;
+ case ZPROP_SRC_RECEIVED:
+ str = "received";
+ break;
+
+ default:
+ str = NULL;
+ assert(!"unhandled zprop_source_t");
+ }
+ break;
+
+ case GET_COL_RECVD:
+ str = (recvd_value == NULL ? "-" : recvd_value);
+ break;
+
+ default:
+ continue;
+ }
+
+ if (cbp->cb_columns[i + 1] == GET_COL_NONE)
+ (void) printf("%s", str);
+ else if (cbp->cb_scripted)
+ (void) printf("%s\t", str);
+ else
+ (void) printf("%-*s ",
+ cbp->cb_colwidths[cbp->cb_columns[i]],
+ str);
+ }
+
+ (void) printf("\n");
+}
+
+/*
+ * Given a numeric suffix, convert the value into a number of bits that the
+ * resulting value must be shifted.
+ */
+static int
+str2shift(libzfs_handle_t *hdl, const char *buf)
+{
+ const char *ends = "BKMGTPEZ";
+ int i;
+
+ if (buf[0] == '\0')
+ return (0);
+ for (i = 0; i < strlen(ends); i++) {
+ if (toupper(buf[0]) == ends[i])
+ break;
+ }
+ if (i == strlen(ends)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid numeric suffix '%s'"), buf);
+ return (-1);
+ }
+
+ /*
+ * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't
+ * allow 'BB' - that's just weird.
+ */
+ if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
+ toupper(buf[0]) != 'B'))
+ return (10*i);
+
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid numeric suffix '%s'"), buf);
+ return (-1);
+}
+
+/*
+ * Convert a string of the form '100G' into a real number. Used when setting
+ * properties or creating a volume. 'buf' is used to place an extended error
+ * message for the caller to use.
+ */
+int
+zfs_nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)
+{
+ char *end;
+ int shift;
+
+ *num = 0;
+
+ /* Check to see if this looks like a number. */
+ if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
+ if (hdl)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "bad numeric value '%s'"), value);
+ return (-1);
+ }
+
+ /* Rely on strtoull() to process the numeric portion. */
+ errno = 0;
+ *num = strtoull(value, &end, 10);
+
+ /*
+ * Check for ERANGE, which indicates that the value is too large to fit
+ * in a 64-bit value.
+ */
+ if (errno == ERANGE) {
+ if (hdl)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "numeric value is too large"));
+ return (-1);
+ }
+
+ /*
+ * If we have a decimal value, then do the computation with floating
+ * point arithmetic. Otherwise, use standard arithmetic.
+ */
+ if (*end == '.') {
+ double fval = strtod(value, &end);
+
+ if ((shift = str2shift(hdl, end)) == -1)
+ return (-1);
+
+ fval *= pow(2, shift);
+
+ if (fval > UINT64_MAX) {
+ if (hdl)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "numeric value is too large"));
+ return (-1);
+ }
+
+ *num = (uint64_t)fval;
+ } else {
+ if ((shift = str2shift(hdl, end)) == -1)
+ return (-1);
+
+ /* Check for overflow */
+ if (shift >= 64 || (*num << shift) >> shift != *num) {
+ if (hdl)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "numeric value is too large"));
+ return (-1);
+ }
+
+ *num <<= shift;
+ }
+
+ return (0);
+}
+
+/*
+ * Given a propname=value nvpair to set, parse any numeric properties
+ * (index, boolean, etc) if they are specified as strings and add the
+ * resulting nvpair to the returned nvlist.
+ *
+ * At the DSL layer, all properties are either 64-bit numbers or strings.
+ * We want the user to be able to ignore this fact and specify properties
+ * as native values (numbers, for example) or as strings (to simplify
+ * command line utilities). This also handles converting index types
+ * (compression, checksum, etc) from strings to their on-disk index.
+ */
+int
+zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop,
+ zfs_type_t type, nvlist_t *ret, char **svalp, uint64_t *ivalp,
+ const char *errbuf)
+{
+ data_type_t datatype = nvpair_type(elem);
+ zprop_type_t proptype;
+ const char *propname;
+ char *value;
+ boolean_t isnone = B_FALSE;
+ boolean_t isauto = B_FALSE;
+
+ if (type == ZFS_TYPE_POOL) {
+ proptype = zpool_prop_get_type(prop);
+ propname = zpool_prop_to_name(prop);
+ } else {
+ proptype = zfs_prop_get_type(prop);
+ propname = zfs_prop_to_name(prop);
+ }
+
+ /*
+ * Convert any properties to the internal DSL value types.
+ */
+ *svalp = NULL;
+ *ivalp = 0;
+
+ switch (proptype) {
+ case PROP_TYPE_STRING:
+ if (datatype != DATA_TYPE_STRING) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a string"), nvpair_name(elem));
+ goto error;
+ }
+ (void) nvpair_value_string(elem, svalp);
+ if (strlen(*svalp) >= ZFS_MAXPROPLEN) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is too long"), nvpair_name(elem));
+ goto error;
+ }
+ break;
+
+ case PROP_TYPE_NUMBER:
+ if (datatype == DATA_TYPE_STRING) {
+ (void) nvpair_value_string(elem, &value);
+ if (strcmp(value, "none") == 0) {
+ isnone = B_TRUE;
+ } else if (strcmp(value, "auto") == 0) {
+ isauto = B_TRUE;
+ } else if (zfs_nicestrtonum(hdl, value, ivalp) != 0) {
+ goto error;
+ }
+ } else if (datatype == DATA_TYPE_UINT64) {
+ (void) nvpair_value_uint64(elem, ivalp);
+ } else {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a number"), nvpair_name(elem));
+ goto error;
+ }
+
+ /*
+ * Quota special: force 'none' and don't allow 0.
+ */
+ if ((type & ZFS_TYPE_DATASET) && *ivalp == 0 && !isnone &&
+ (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_REFQUOTA)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "use 'none' to disable quota/refquota"));
+ goto error;
+ }
+
+ /*
+ * Special handling for "*_limit=none". In this case it's not
+ * 0 but UINT64_MAX.
+ */
+ if ((type & ZFS_TYPE_DATASET) && isnone &&
+ (prop == ZFS_PROP_FILESYSTEM_LIMIT ||
+ prop == ZFS_PROP_SNAPSHOT_LIMIT)) {
+ *ivalp = UINT64_MAX;
+ }
+
+ /*
+ * Special handling for setting 'refreservation' to 'auto'. Use
+ * UINT64_MAX to tell the caller to use zfs_fix_auto_resv().
+ * 'auto' is only allowed on volumes.
+ */
+ if (isauto) {
+ switch (prop) {
+ case ZFS_PROP_REFRESERVATION:
+ if ((type & ZFS_TYPE_VOLUME) == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s=auto' only allowed on "
+ "volumes"), nvpair_name(elem));
+ goto error;
+ }
+ *ivalp = UINT64_MAX;
+ break;
+ default:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'auto' is invalid value for '%s'"),
+ nvpair_name(elem));
+ goto error;
+ }
+ }
+
+ break;
+
+ case PROP_TYPE_INDEX:
+ if (datatype != DATA_TYPE_STRING) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a string"), nvpair_name(elem));
+ goto error;
+ }
+
+ (void) nvpair_value_string(elem, &value);
+
+ if (zprop_string_to_index(prop, value, ivalp, type) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be one of '%s'"), propname,
+ zprop_values(prop, type));
+ goto error;
+ }
+ break;
+
+ default:
+ abort();
+ }
+
+ /*
+ * Add the result to our return set of properties.
+ */
+ if (*svalp != NULL) {
+ if (nvlist_add_string(ret, propname, *svalp) != 0) {
+ (void) no_memory(hdl);
+ return (-1);
+ }
+ } else {
+ if (nvlist_add_uint64(ret, propname, *ivalp) != 0) {
+ (void) no_memory(hdl);
+ return (-1);
+ }
+ }
+
+ return (0);
+error:
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ return (-1);
+}
+
+static int
+addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp,
+ zfs_type_t type)
+{
+ int prop;
+ zprop_list_t *entry;
+
+ prop = zprop_name_to_prop(propname, type);
+
+ if (prop != ZPROP_INVAL && !zprop_valid_for_type(prop, type))
+ prop = ZPROP_INVAL;
+
+ /*
+ * When no property table entry can be found, return failure if
+ * this is a pool property or if this isn't a user-defined
+ * dataset property,
+ */
+ if (prop == ZPROP_INVAL && ((type == ZFS_TYPE_POOL &&
+ !zpool_prop_feature(propname) &&
+ !zpool_prop_unsupported(propname)) ||
+ (type == ZFS_TYPE_DATASET && !zfs_prop_user(propname) &&
+ !zfs_prop_userquota(propname) && !zfs_prop_written(propname)))) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid property '%s'"), propname);
+ return (zfs_error(hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN, "bad property list")));
+ }
+
+ if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
+ return (-1);
+
+ entry->pl_prop = prop;
+ if (prop == ZPROP_INVAL) {
+ if ((entry->pl_user_prop = zfs_strdup(hdl, propname)) ==
+ NULL) {
+ free(entry);
+ return (-1);
+ }
+ entry->pl_width = strlen(propname);
+ } else {
+ entry->pl_width = zprop_width(prop, &entry->pl_fixed,
+ type);
+ }
+
+ *listp = entry;
+
+ return (0);
+}
+
+/*
+ * Given a comma-separated list of properties, construct a property list
+ * containing both user-defined and native properties. This function will
+ * return a NULL list if 'all' is specified, which can later be expanded
+ * by zprop_expand_list().
+ */
+int
+zprop_get_list(libzfs_handle_t *hdl, char *props, zprop_list_t **listp,
+ zfs_type_t type)
+{
+ *listp = NULL;
+
+ /*
+ * If 'all' is specified, return a NULL list.
+ */
+ if (strcmp(props, "all") == 0)
+ return (0);
+
+ /*
+ * If no props were specified, return an error.
+ */
+ if (props[0] == '\0') {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "no properties specified"));
+ return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
+ "bad property list")));
+ }
+
+ /*
+ * It would be nice to use getsubopt() here, but the inclusion of column
+ * aliases makes this more effort than it's worth.
+ */
+ while (*props != '\0') {
+ size_t len;
+ char *p;
+ char c;
+
+ if ((p = strchr(props, ',')) == NULL) {
+ len = strlen(props);
+ p = props + len;
+ } else {
+ len = p - props;
+ }
+
+ /*
+ * Check for empty options.
+ */
+ if (len == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "empty property name"));
+ return (zfs_error(hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN, "bad property list")));
+ }
+
+ /*
+ * Check all regular property names.
+ */
+ c = props[len];
+ props[len] = '\0';
+
+ if (strcmp(props, "space") == 0) {
+ static char *spaceprops[] = {
+ "name", "avail", "used", "usedbysnapshots",
+ "usedbydataset", "usedbyrefreservation",
+ "usedbychildren", NULL
+ };
+ int i;
+
+ for (i = 0; spaceprops[i]; i++) {
+ if (addlist(hdl, spaceprops[i], listp, type))
+ return (-1);
+ listp = &(*listp)->pl_next;
+ }
+ } else {
+ if (addlist(hdl, props, listp, type))
+ return (-1);
+ listp = &(*listp)->pl_next;
+ }
+
+ props = p;
+ if (c == ',')
+ props++;
+ }
+
+ return (0);
+}
+
+void
+zprop_free_list(zprop_list_t *pl)
+{
+ zprop_list_t *next;
+
+ while (pl != NULL) {
+ next = pl->pl_next;
+ free(pl->pl_user_prop);
+ free(pl);
+ pl = next;
+ }
+}
+
+typedef struct expand_data {
+ zprop_list_t **last;
+ libzfs_handle_t *hdl;
+ zfs_type_t type;
+} expand_data_t;
+
+int
+zprop_expand_list_cb(int prop, void *cb)
+{
+ zprop_list_t *entry;
+ expand_data_t *edp = cb;
+
+ if ((entry = zfs_alloc(edp->hdl, sizeof (zprop_list_t))) == NULL)
+ return (ZPROP_INVAL);
+
+ entry->pl_prop = prop;
+ entry->pl_width = zprop_width(prop, &entry->pl_fixed, edp->type);
+ entry->pl_all = B_TRUE;
+
+ *(edp->last) = entry;
+ edp->last = &entry->pl_next;
+
+ return (ZPROP_CONT);
+}
+
+int
+zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp, zfs_type_t type)
+{
+ zprop_list_t *entry;
+ zprop_list_t **last;
+ expand_data_t exp;
+
+ if (*plp == NULL) {
+ /*
+ * If this is the very first time we've been called for an 'all'
+ * specification, expand the list to include all native
+ * properties.
+ */
+ last = plp;
+
+ exp.last = last;
+ exp.hdl = hdl;
+ exp.type = type;
+
+ if (zprop_iter_common(zprop_expand_list_cb, &exp, B_FALSE,
+ B_FALSE, type) == ZPROP_INVAL)
+ return (-1);
+
+ /*
+ * Add 'name' to the beginning of the list, which is handled
+ * specially.
+ */
+ if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
+ return (-1);
+
+ entry->pl_prop = (type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME :
+ ZFS_PROP_NAME;
+ entry->pl_width = zprop_width(entry->pl_prop,
+ &entry->pl_fixed, type);
+ entry->pl_all = B_TRUE;
+ entry->pl_next = *plp;
+ *plp = entry;
+ }
+ return (0);
+}
+
+int
+zprop_iter(zprop_func func, void *cb, boolean_t show_all, boolean_t ordered,
+ zfs_type_t type)
+{
+ return (zprop_iter_common(func, cb, show_all, ordered, type));
+}
+
+ulong_t
+get_system_hostid(void)
+{
+ char *env;
+
+ /*
+ * Allow the hostid to be subverted for testing.
+ */
+ env = getenv("ZFS_HOSTID");
+ if (env) {
+ ulong_t hostid = strtoull(env, NULL, 16);
+ return (hostid & 0xFFFFFFFF);
+ }
+
+ return (gethostid());
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
new file mode 100644
index 000000000000..cd5767e69b9b
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
@@ -0,0 +1,1164 @@
+/*
+ * 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 (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2017 RackTop Systems.
+ * Copyright (c) 2017 Datto Inc.
+ */
+
+/*
+ * LibZFS_Core (lzc) is intended to replace most functionality in libzfs.
+ * It has the following characteristics:
+ *
+ * - Thread Safe. libzfs_core is accessible concurrently from multiple
+ * threads. This is accomplished primarily by avoiding global data
+ * (e.g. caching). Since it's thread-safe, there is no reason for a
+ * process to have multiple libzfs "instances". Therefore, we store
+ * our few pieces of data (e.g. the file descriptor) in global
+ * variables. The fd is reference-counted so that the libzfs_core
+ * library can be "initialized" multiple times (e.g. by different
+ * consumers within the same process).
+ *
+ * - Committed Interface. The libzfs_core interface will be committed,
+ * therefore consumers can compile against it and be confident that
+ * their code will continue to work on future releases of this code.
+ * Currently, the interface is Evolving (not Committed), but we intend
+ * to commit to it once it is more complete and we determine that it
+ * meets the needs of all consumers.
+ *
+ * - Programatic Error Handling. libzfs_core communicates errors with
+ * defined error numbers, and doesn't print anything to stdout/stderr.
+ *
+ * - Thin Layer. libzfs_core is a thin layer, marshaling arguments
+ * to/from the kernel ioctls. There is generally a 1:1 correspondence
+ * between libzfs_core functions and ioctls to /dev/zfs.
+ *
+ * - Clear Atomicity. Because libzfs_core functions are generally 1:1
+ * with kernel ioctls, and kernel ioctls are general atomic, each
+ * libzfs_core function is atomic. For example, creating multiple
+ * snapshots with a single call to lzc_snapshot() is atomic -- it
+ * can't fail with only some of the requested snapshots created, even
+ * in the event of power loss or system crash.
+ *
+ * - Continued libzfs Support. Some higher-level operations (e.g.
+ * support for "zfs send -R") are too complicated to fit the scope of
+ * libzfs_core. This functionality will continue to live in libzfs.
+ * Where appropriate, libzfs will use the underlying atomic operations
+ * of libzfs_core. For example, libzfs may implement "zfs send -R |
+ * zfs receive" by using individual "send one snapshot", rename,
+ * destroy, and "receive one snapshot" operations in libzfs_core.
+ * /sbin/zfs and /zbin/zpool will link with both libzfs and
+ * libzfs_core. Other consumers should aim to use only libzfs_core,
+ * since that will be the supported, stable interface going forwards.
+ */
+
+#define _IN_LIBZFS_CORE_
+
+#include <libzfs_core.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/nvpair.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/zfs_ioctl.h>
+#include "libzfs_core_compat.h"
+#include "libzfs_compat.h"
+
+#ifdef __FreeBSD__
+extern int zfs_ioctl_version;
+#endif
+
+static int g_fd = -1;
+static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
+static int g_refcount;
+
+int
+libzfs_core_init(void)
+{
+ (void) pthread_mutex_lock(&g_lock);
+ if (g_refcount == 0) {
+ g_fd = open("/dev/zfs", O_RDWR);
+ if (g_fd < 0) {
+ (void) pthread_mutex_unlock(&g_lock);
+ return (errno);
+ }
+ }
+ g_refcount++;
+ (void) pthread_mutex_unlock(&g_lock);
+
+ return (0);
+}
+
+void
+libzfs_core_fini(void)
+{
+ (void) pthread_mutex_lock(&g_lock);
+ ASSERT3S(g_refcount, >, 0);
+
+ if (g_refcount > 0)
+ g_refcount--;
+
+ if (g_refcount == 0 && g_fd != -1) {
+ (void) close(g_fd);
+ g_fd = -1;
+ }
+ (void) pthread_mutex_unlock(&g_lock);
+}
+
+static int
+lzc_ioctl(zfs_ioc_t ioc, const char *name,
+ nvlist_t *source, nvlist_t **resultp)
+{
+ zfs_cmd_t zc = { 0 };
+ int error = 0;
+ char *packed = NULL;
+#ifdef __FreeBSD__
+ nvlist_t *oldsource;
+#endif
+ size_t size = 0;
+
+ ASSERT3S(g_refcount, >, 0);
+ VERIFY3S(g_fd, !=, -1);
+
+ if (name != NULL)
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+
+#ifdef __FreeBSD__
+ if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
+ zfs_ioctl_version = get_zfs_ioctl_version();
+
+ if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
+ oldsource = source;
+ error = lzc_compat_pre(&zc, &ioc, &source);
+ if (error)
+ return (error);
+ }
+#endif
+
+ if (source != NULL) {
+ packed = fnvlist_pack(source, &size);
+ zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
+ zc.zc_nvlist_src_size = size;
+ }
+
+ if (resultp != NULL) {
+ *resultp = NULL;
+ if (ioc == ZFS_IOC_CHANNEL_PROGRAM) {
+ zc.zc_nvlist_dst_size = fnvlist_lookup_uint64(source,
+ ZCP_ARG_MEMLIMIT);
+ } else {
+ zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
+ }
+ zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
+ malloc(zc.zc_nvlist_dst_size);
+#ifdef illumos
+ if (zc.zc_nvlist_dst == NULL) {
+#else
+ if (zc.zc_nvlist_dst == 0) {
+#endif
+ error = ENOMEM;
+ goto out;
+ }
+ }
+
+ while (ioctl(g_fd, ioc, &zc) != 0) {
+ /*
+ * If ioctl exited with ENOMEM, we retry the ioctl after
+ * increasing the size of the destination nvlist.
+ *
+ * Channel programs that exit with ENOMEM ran over the
+ * lua memory sandbox; they should not be retried.
+ */
+ if (errno == ENOMEM && resultp != NULL &&
+ ioc != ZFS_IOC_CHANNEL_PROGRAM) {
+ free((void *)(uintptr_t)zc.zc_nvlist_dst);
+ zc.zc_nvlist_dst_size *= 2;
+ zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
+ malloc(zc.zc_nvlist_dst_size);
+#ifdef illumos
+ if (zc.zc_nvlist_dst == NULL) {
+#else
+ if (zc.zc_nvlist_dst == 0) {
+#endif
+ error = ENOMEM;
+ goto out;
+ }
+ } else {
+ error = errno;
+ break;
+ }
+ }
+
+#ifdef __FreeBSD__
+ if (zfs_ioctl_version < ZFS_IOCVER_LZC)
+ lzc_compat_post(&zc, ioc);
+#endif
+ if (zc.zc_nvlist_dst_filled) {
+ *resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
+ zc.zc_nvlist_dst_size);
+ }
+#ifdef __FreeBSD__
+ if (zfs_ioctl_version < ZFS_IOCVER_LZC)
+ lzc_compat_outnvl(&zc, ioc, resultp);
+#endif
+out:
+#ifdef __FreeBSD__
+ if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
+ if (source != oldsource)
+ nvlist_free(source);
+ source = oldsource;
+ }
+#endif
+ fnvlist_pack_free(packed, size);
+ free((void *)(uintptr_t)zc.zc_nvlist_dst);
+ return (error);
+}
+
+int
+lzc_create(const char *fsname, enum lzc_dataset_type type, nvlist_t *props)
+{
+ int error;
+ nvlist_t *args = fnvlist_alloc();
+ fnvlist_add_int32(args, "type", (dmu_objset_type_t)type);
+ if (props != NULL)
+ fnvlist_add_nvlist(args, "props", props);
+ error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL);
+ nvlist_free(args);
+ return (error);
+}
+
+int
+lzc_clone(const char *fsname, const char *origin,
+ nvlist_t *props)
+{
+ int error;
+ nvlist_t *args = fnvlist_alloc();
+ fnvlist_add_string(args, "origin", origin);
+ if (props != NULL)
+ fnvlist_add_nvlist(args, "props", props);
+ error = lzc_ioctl(ZFS_IOC_CLONE, fsname, args, NULL);
+ nvlist_free(args);
+ return (error);
+}
+
+int
+lzc_promote(const char *fsname, char *snapnamebuf, int snapnamelen)
+{
+ /*
+ * The promote ioctl is still legacy, so we need to construct our
+ * own zfs_cmd_t rather than using lzc_ioctl().
+ */
+ zfs_cmd_t zc = { 0 };
+
+ ASSERT3S(g_refcount, >, 0);
+ VERIFY3S(g_fd, !=, -1);
+
+ (void) strlcpy(zc.zc_name, fsname, sizeof (zc.zc_name));
+ if (ioctl(g_fd, ZFS_IOC_PROMOTE, &zc) != 0) {
+ int error = errno;
+ if (error == EEXIST && snapnamebuf != NULL)
+ (void) strlcpy(snapnamebuf, zc.zc_string, snapnamelen);
+ return (error);
+ }
+ return (0);
+}
+
+int
+lzc_remap(const char *fsname)
+{
+ int error;
+ nvlist_t *args = fnvlist_alloc();
+ error = lzc_ioctl(ZFS_IOC_REMAP, fsname, args, NULL);
+ nvlist_free(args);
+ return (error);
+}
+
+int
+lzc_rename(const char *source, const char *target)
+{
+ zfs_cmd_t zc = { 0 };
+ int error;
+
+ ASSERT3S(g_refcount, >, 0);
+ VERIFY3S(g_fd, !=, -1);
+
+ (void) strlcpy(zc.zc_name, source, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
+ error = ioctl(g_fd, ZFS_IOC_RENAME, &zc);
+ if (error != 0)
+ error = errno;
+ return (error);
+}
+
+int
+lzc_destroy(const char *fsname)
+{
+ int error;
+
+ nvlist_t *args = fnvlist_alloc();
+ error = lzc_ioctl(ZFS_IOC_DESTROY, fsname, args, NULL);
+ nvlist_free(args);
+ return (error);
+}
+
+/*
+ * Creates snapshots.
+ *
+ * The keys in the snaps nvlist are the snapshots to be created.
+ * They must all be in the same pool.
+ *
+ * The props nvlist is properties to set. Currently only user properties
+ * are supported. { user:prop_name -> string value }
+ *
+ * The returned results nvlist will have an entry for each snapshot that failed.
+ * The value will be the (int32) error code.
+ *
+ * The return value will be 0 if all snapshots were created, otherwise it will
+ * be the errno of a (unspecified) snapshot that failed.
+ */
+int
+lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist)
+{
+ nvpair_t *elem;
+ nvlist_t *args;
+ int error;
+ char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+ *errlist = NULL;
+
+ /* determine the pool name */
+ elem = nvlist_next_nvpair(snaps, NULL);
+ if (elem == NULL)
+ return (0);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/@")] = '\0';
+
+ args = fnvlist_alloc();
+ fnvlist_add_nvlist(args, "snaps", snaps);
+ if (props != NULL)
+ fnvlist_add_nvlist(args, "props", props);
+
+ error = lzc_ioctl(ZFS_IOC_SNAPSHOT, pool, args, errlist);
+ nvlist_free(args);
+
+ return (error);
+}
+
+/*
+ * Destroys snapshots.
+ *
+ * The keys in the snaps nvlist are the snapshots to be destroyed.
+ * They must all be in the same pool.
+ *
+ * Snapshots that do not exist will be silently ignored.
+ *
+ * If 'defer' is not set, and a snapshot has user holds or clones, the
+ * destroy operation will fail and none of the snapshots will be
+ * destroyed.
+ *
+ * If 'defer' is set, and a snapshot has user holds or clones, it will be
+ * marked for deferred destruction, and will be destroyed when the last hold
+ * or clone is removed/destroyed.
+ *
+ * The return value will be 0 if all snapshots were destroyed (or marked for
+ * later destruction if 'defer' is set) or didn't exist to begin with.
+ *
+ * Otherwise the return value will be the errno of a (unspecified) snapshot
+ * that failed, no snapshots will be destroyed, and the errlist will have an
+ * entry for each snapshot that failed. The value in the errlist will be
+ * the (int32) error code.
+ */
+int
+lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist)
+{
+ nvpair_t *elem;
+ nvlist_t *args;
+ int error;
+ char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+ /* determine the pool name */
+ elem = nvlist_next_nvpair(snaps, NULL);
+ if (elem == NULL)
+ return (0);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/@")] = '\0';
+
+ args = fnvlist_alloc();
+ fnvlist_add_nvlist(args, "snaps", snaps);
+ if (defer)
+ fnvlist_add_boolean(args, "defer");
+
+ error = lzc_ioctl(ZFS_IOC_DESTROY_SNAPS, pool, args, errlist);
+ nvlist_free(args);
+
+ return (error);
+}
+
+int
+lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
+ uint64_t *usedp)
+{
+ nvlist_t *args;
+ nvlist_t *result;
+ int err;
+ char fs[ZFS_MAX_DATASET_NAME_LEN];
+ char *atp;
+
+ /* determine the fs name */
+ (void) strlcpy(fs, firstsnap, sizeof (fs));
+ atp = strchr(fs, '@');
+ if (atp == NULL)
+ return (EINVAL);
+ *atp = '\0';
+
+ args = fnvlist_alloc();
+ fnvlist_add_string(args, "firstsnap", firstsnap);
+
+ err = lzc_ioctl(ZFS_IOC_SPACE_SNAPS, lastsnap, args, &result);
+ nvlist_free(args);
+ if (err == 0)
+ *usedp = fnvlist_lookup_uint64(result, "used");
+ fnvlist_free(result);
+
+ return (err);
+}
+
+boolean_t
+lzc_exists(const char *dataset)
+{
+ /*
+ * The objset_stats ioctl is still legacy, so we need to construct our
+ * own zfs_cmd_t rather than using lzc_ioctl().
+ */
+ zfs_cmd_t zc = { 0 };
+
+ ASSERT3S(g_refcount, >, 0);
+ VERIFY3S(g_fd, !=, -1);
+
+ (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
+ return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0);
+}
+
+/*
+ * outnvl is unused.
+ * It was added to preserve the function signature in case it is
+ * needed in the future.
+ */
+/*ARGSUSED*/
+int
+lzc_sync(const char *pool_name, nvlist_t *innvl, nvlist_t **outnvl)
+{
+ return (lzc_ioctl(ZFS_IOC_POOL_SYNC, pool_name, innvl, NULL));
+}
+
+/*
+ * Create "user holds" on snapshots. If there is a hold on a snapshot,
+ * the snapshot can not be destroyed. (However, it can be marked for deletion
+ * by lzc_destroy_snaps(defer=B_TRUE).)
+ *
+ * The keys in the nvlist are snapshot names.
+ * The snapshots must all be in the same pool.
+ * The value is the name of the hold (string type).
+ *
+ * If cleanup_fd is not -1, it must be the result of open("/dev/zfs", O_EXCL).
+ * In this case, when the cleanup_fd is closed (including on process
+ * termination), the holds will be released. If the system is shut down
+ * uncleanly, the holds will be released when the pool is next opened
+ * or imported.
+ *
+ * Holds for snapshots which don't exist will be skipped and have an entry
+ * added to errlist, but will not cause an overall failure.
+ *
+ * The return value will be 0 if all holds, for snapshots that existed,
+ * were succesfully created.
+ *
+ * Otherwise the return value will be the errno of a (unspecified) hold that
+ * failed and no holds will be created.
+ *
+ * In all cases the errlist will have an entry for each hold that failed
+ * (name = snapshot), with its value being the error code (int32).
+ */
+int
+lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
+{
+ char pool[ZFS_MAX_DATASET_NAME_LEN];
+ nvlist_t *args;
+ nvpair_t *elem;
+ int error;
+
+ /* determine the pool name */
+ elem = nvlist_next_nvpair(holds, NULL);
+ if (elem == NULL)
+ return (0);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/@")] = '\0';
+
+ args = fnvlist_alloc();
+ fnvlist_add_nvlist(args, "holds", holds);
+ if (cleanup_fd != -1)
+ fnvlist_add_int32(args, "cleanup_fd", cleanup_fd);
+
+ error = lzc_ioctl(ZFS_IOC_HOLD, pool, args, errlist);
+ nvlist_free(args);
+ return (error);
+}
+
+/*
+ * Release "user holds" on snapshots. If the snapshot has been marked for
+ * deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
+ * any clones, and all the user holds are removed, then the snapshot will be
+ * destroyed.
+ *
+ * The keys in the nvlist are snapshot names.
+ * The snapshots must all be in the same pool.
+ * The value is a nvlist whose keys are the holds to remove.
+ *
+ * Holds which failed to release because they didn't exist will have an entry
+ * added to errlist, but will not cause an overall failure.
+ *
+ * The return value will be 0 if the nvl holds was empty or all holds that
+ * existed, were successfully removed.
+ *
+ * Otherwise the return value will be the errno of a (unspecified) hold that
+ * failed to release and no holds will be released.
+ *
+ * In all cases the errlist will have an entry for each hold that failed to
+ * to release.
+ */
+int
+lzc_release(nvlist_t *holds, nvlist_t **errlist)
+{
+ char pool[ZFS_MAX_DATASET_NAME_LEN];
+ nvpair_t *elem;
+
+ /* determine the pool name */
+ elem = nvlist_next_nvpair(holds, NULL);
+ if (elem == NULL)
+ return (0);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/@")] = '\0';
+
+ return (lzc_ioctl(ZFS_IOC_RELEASE, pool, holds, errlist));
+}
+
+/*
+ * Retrieve list of user holds on the specified snapshot.
+ *
+ * On success, *holdsp will be set to a nvlist which the caller must free.
+ * The keys are the names of the holds, and the value is the creation time
+ * of the hold (uint64) in seconds since the epoch.
+ */
+int
+lzc_get_holds(const char *snapname, nvlist_t **holdsp)
+{
+ return (lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, NULL, holdsp));
+}
+
+/*
+ * Generate a zfs send stream for the specified snapshot and write it to
+ * the specified file descriptor.
+ *
+ * "snapname" is the full name of the snapshot to send (e.g. "pool/fs@snap")
+ *
+ * If "from" is NULL, a full (non-incremental) stream will be sent.
+ * If "from" is non-NULL, it must be the full name of a snapshot or
+ * bookmark to send an incremental from (e.g. "pool/fs@earlier_snap" or
+ * "pool/fs#earlier_bmark"). If non-NULL, the specified snapshot or
+ * bookmark must represent an earlier point in the history of "snapname").
+ * It can be an earlier snapshot in the same filesystem or zvol as "snapname",
+ * or it can be the origin of "snapname"'s filesystem, or an earlier
+ * snapshot in the origin, etc.
+ *
+ * "fd" is the file descriptor to write the send stream to.
+ *
+ * If "flags" contains LZC_SEND_FLAG_LARGE_BLOCK, the stream is permitted
+ * to contain DRR_WRITE records with drr_length > 128K, and DRR_OBJECT
+ * records with drr_blksz > 128K.
+ *
+ * If "flags" contains LZC_SEND_FLAG_EMBED_DATA, the stream is permitted
+ * to contain DRR_WRITE_EMBEDDED records with drr_etype==BP_EMBEDDED_TYPE_DATA,
+ * which the receiving system must support (as indicated by support
+ * for the "embedded_data" feature).
+ */
+int
+lzc_send(const char *snapname, const char *from, int fd,
+ enum lzc_send_flags flags)
+{
+ return (lzc_send_resume(snapname, from, fd, flags, 0, 0));
+}
+
+int
+lzc_send_resume(const char *snapname, const char *from, int fd,
+ enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff)
+{
+ nvlist_t *args;
+ int err;
+
+ args = fnvlist_alloc();
+ fnvlist_add_int32(args, "fd", fd);
+ if (from != NULL)
+ fnvlist_add_string(args, "fromsnap", from);
+ if (flags & LZC_SEND_FLAG_LARGE_BLOCK)
+ fnvlist_add_boolean(args, "largeblockok");
+ if (flags & LZC_SEND_FLAG_EMBED_DATA)
+ fnvlist_add_boolean(args, "embedok");
+ if (flags & LZC_SEND_FLAG_COMPRESS)
+ fnvlist_add_boolean(args, "compressok");
+ if (resumeobj != 0 || resumeoff != 0) {
+ fnvlist_add_uint64(args, "resume_object", resumeobj);
+ fnvlist_add_uint64(args, "resume_offset", resumeoff);
+ }
+ err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
+ nvlist_free(args);
+ return (err);
+}
+
+/*
+ * "from" can be NULL, a snapshot, or a bookmark.
+ *
+ * If from is NULL, a full (non-incremental) stream will be estimated. This
+ * is calculated very efficiently.
+ *
+ * If from is a snapshot, lzc_send_space uses the deadlists attached to
+ * each snapshot to efficiently estimate the stream size.
+ *
+ * If from is a bookmark, the indirect blocks in the destination snapshot
+ * are traversed, looking for blocks with a birth time since the creation TXG of
+ * the snapshot this bookmark was created from. This will result in
+ * significantly more I/O and be less efficient than a send space estimation on
+ * an equivalent snapshot.
+ */
+int
+lzc_send_space(const char *snapname, const char *from,
+ enum lzc_send_flags flags, uint64_t *spacep)
+{
+ nvlist_t *args;
+ nvlist_t *result;
+ int err;
+
+ args = fnvlist_alloc();
+ if (from != NULL)
+ fnvlist_add_string(args, "from", from);
+ if (flags & LZC_SEND_FLAG_LARGE_BLOCK)
+ fnvlist_add_boolean(args, "largeblockok");
+ if (flags & LZC_SEND_FLAG_EMBED_DATA)
+ fnvlist_add_boolean(args, "embedok");
+ if (flags & LZC_SEND_FLAG_COMPRESS)
+ fnvlist_add_boolean(args, "compressok");
+ err = lzc_ioctl(ZFS_IOC_SEND_SPACE, snapname, args, &result);
+ nvlist_free(args);
+ if (err == 0)
+ *spacep = fnvlist_lookup_uint64(result, "space");
+ nvlist_free(result);
+ return (err);
+}
+
+static int
+recv_read(int fd, void *buf, int ilen)
+{
+ char *cp = buf;
+ int rv;
+ int len = ilen;
+
+ do {
+ rv = read(fd, cp, len);
+ cp += rv;
+ len -= rv;
+ } while (rv > 0);
+
+ if (rv < 0 || len != 0)
+ return (EIO);
+
+ return (0);
+}
+
+static int
+recv_impl(const char *snapname, nvlist_t *props, const char *origin,
+ boolean_t force, boolean_t resumable, int fd,
+ const dmu_replay_record_t *begin_record)
+{
+ /*
+ * The receive ioctl is still legacy, so we need to construct our own
+ * zfs_cmd_t rather than using zfsc_ioctl().
+ */
+ zfs_cmd_t zc = { 0 };
+ char *atp;
+ char *packed = NULL;
+ size_t size;
+ int error;
+
+ ASSERT3S(g_refcount, >, 0);
+ VERIFY3S(g_fd, !=, -1);
+
+ /* zc_name is name of containing filesystem */
+ (void) strlcpy(zc.zc_name, snapname, sizeof (zc.zc_name));
+ atp = strchr(zc.zc_name, '@');
+ if (atp == NULL)
+ return (EINVAL);
+ *atp = '\0';
+
+ /* if the fs does not exist, try its parent. */
+ if (!lzc_exists(zc.zc_name)) {
+ char *slashp = strrchr(zc.zc_name, '/');
+ if (slashp == NULL)
+ return (ENOENT);
+ *slashp = '\0';
+
+ }
+
+ /* zc_value is full name of the snapshot to create */
+ (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
+
+ if (props != NULL) {
+ /* zc_nvlist_src is props to set */
+ packed = fnvlist_pack(props, &size);
+ zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
+ zc.zc_nvlist_src_size = size;
+ }
+
+ /* zc_string is name of clone origin (if DRR_FLAG_CLONE) */
+ if (origin != NULL)
+ (void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
+
+ /* zc_begin_record is non-byteswapped BEGIN record */
+ if (begin_record == NULL) {
+ error = recv_read(fd, &zc.zc_begin_record,
+ sizeof (zc.zc_begin_record));
+ if (error != 0)
+ goto out;
+ } else {
+ zc.zc_begin_record = *begin_record;
+ }
+
+ /* zc_cookie is fd to read from */
+ zc.zc_cookie = fd;
+
+ /* zc guid is force flag */
+ zc.zc_guid = force;
+
+ zc.zc_resumable = resumable;
+
+ /* zc_cleanup_fd is unused */
+ zc.zc_cleanup_fd = -1;
+
+ error = ioctl(g_fd, ZFS_IOC_RECV, &zc);
+ if (error != 0)
+ error = errno;
+
+out:
+ if (packed != NULL)
+ fnvlist_pack_free(packed, size);
+ free((void*)(uintptr_t)zc.zc_nvlist_dst);
+ return (error);
+}
+
+/*
+ * The simplest receive case: receive from the specified fd, creating the
+ * specified snapshot. Apply the specified properties as "received" properties
+ * (which can be overridden by locally-set properties). If the stream is a
+ * clone, its origin snapshot must be specified by 'origin'. The 'force'
+ * flag will cause the target filesystem to be rolled back or destroyed if
+ * necessary to receive.
+ *
+ * Return 0 on success or an errno on failure.
+ *
+ * Note: this interface does not work on dedup'd streams
+ * (those with DMU_BACKUP_FEATURE_DEDUP).
+ */
+int
+lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
+ boolean_t force, int fd)
+{
+ return (recv_impl(snapname, props, origin, force, B_FALSE, fd, NULL));
+}
+
+/*
+ * Like lzc_receive, but if the receive fails due to premature stream
+ * termination, the intermediate state will be preserved on disk. In this
+ * case, ECKSUM will be returned. The receive may subsequently be resumed
+ * with a resuming send stream generated by lzc_send_resume().
+ */
+int
+lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
+ boolean_t force, int fd)
+{
+ return (recv_impl(snapname, props, origin, force, B_TRUE, fd, NULL));
+}
+
+/*
+ * Like lzc_receive, but allows the caller to read the begin record and then to
+ * pass it in. That could be useful if the caller wants to derive, for example,
+ * the snapname or the origin parameters based on the information contained in
+ * the begin record.
+ * The begin record must be in its original form as read from the stream,
+ * in other words, it should not be byteswapped.
+ *
+ * The 'resumable' parameter allows to obtain the same behavior as with
+ * lzc_receive_resumable.
+ */
+int
+lzc_receive_with_header(const char *snapname, nvlist_t *props,
+ const char *origin, boolean_t force, boolean_t resumable, int fd,
+ const dmu_replay_record_t *begin_record)
+{
+ if (begin_record == NULL)
+ return (EINVAL);
+ return (recv_impl(snapname, props, origin, force, resumable, fd,
+ begin_record));
+}
+
+/*
+ * Roll back this filesystem or volume to its most recent snapshot.
+ * If snapnamebuf is not NULL, it will be filled in with the name
+ * of the most recent snapshot.
+ * Note that the latest snapshot may change if a new one is concurrently
+ * created or the current one is destroyed. lzc_rollback_to can be used
+ * to roll back to a specific latest snapshot.
+ *
+ * Return 0 on success or an errno on failure.
+ */
+int
+lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen)
+{
+ nvlist_t *args;
+ nvlist_t *result;
+ int err;
+
+ args = fnvlist_alloc();
+ err = lzc_ioctl(ZFS_IOC_ROLLBACK, fsname, args, &result);
+ nvlist_free(args);
+ if (err == 0 && snapnamebuf != NULL) {
+ const char *snapname = fnvlist_lookup_string(result, "target");
+ (void) strlcpy(snapnamebuf, snapname, snapnamelen);
+ }
+ nvlist_free(result);
+
+ return (err);
+}
+
+/*
+ * Roll back this filesystem or volume to the specified snapshot,
+ * if possible.
+ *
+ * Return 0 on success or an errno on failure.
+ */
+int
+lzc_rollback_to(const char *fsname, const char *snapname)
+{
+ nvlist_t *args;
+ nvlist_t *result;
+ int err;
+
+ args = fnvlist_alloc();
+ fnvlist_add_string(args, "target", snapname);
+ err = lzc_ioctl(ZFS_IOC_ROLLBACK, fsname, args, &result);
+ nvlist_free(args);
+ nvlist_free(result);
+ return (err);
+}
+
+/*
+ * Creates bookmarks.
+ *
+ * The bookmarks nvlist maps from name of the bookmark (e.g. "pool/fs#bmark") to
+ * the name of the snapshot (e.g. "pool/fs@snap"). All the bookmarks and
+ * snapshots must be in the same pool.
+ *
+ * The returned results nvlist will have an entry for each bookmark that failed.
+ * The value will be the (int32) error code.
+ *
+ * The return value will be 0 if all bookmarks were created, otherwise it will
+ * be the errno of a (undetermined) bookmarks that failed.
+ */
+int
+lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist)
+{
+ nvpair_t *elem;
+ int error;
+ char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+ /* determine the pool name */
+ elem = nvlist_next_nvpair(bookmarks, NULL);
+ if (elem == NULL)
+ return (0);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/#")] = '\0';
+
+ error = lzc_ioctl(ZFS_IOC_BOOKMARK, pool, bookmarks, errlist);
+
+ return (error);
+}
+
+/*
+ * Retrieve bookmarks.
+ *
+ * Retrieve the list of bookmarks for the given file system. The props
+ * parameter is an nvlist of property names (with no values) that will be
+ * returned for each bookmark.
+ *
+ * The following are valid properties on bookmarks, all of which are numbers
+ * (represented as uint64 in the nvlist)
+ *
+ * "guid" - globally unique identifier of the snapshot it refers to
+ * "createtxg" - txg when the snapshot it refers to was created
+ * "creation" - timestamp when the snapshot it refers to was created
+ *
+ * The format of the returned nvlist as follows:
+ * <short name of bookmark> -> {
+ * <name of property> -> {
+ * "value" -> uint64
+ * }
+ * }
+ */
+int
+lzc_get_bookmarks(const char *fsname, nvlist_t *props, nvlist_t **bmarks)
+{
+ return (lzc_ioctl(ZFS_IOC_GET_BOOKMARKS, fsname, props, bmarks));
+}
+
+/*
+ * Destroys bookmarks.
+ *
+ * The keys in the bmarks nvlist are the bookmarks to be destroyed.
+ * They must all be in the same pool. Bookmarks are specified as
+ * <fs>#<bmark>.
+ *
+ * Bookmarks that do not exist will be silently ignored.
+ *
+ * The return value will be 0 if all bookmarks that existed were destroyed.
+ *
+ * Otherwise the return value will be the errno of a (undetermined) bookmark
+ * that failed, no bookmarks will be destroyed, and the errlist will have an
+ * entry for each bookmarks that failed. The value in the errlist will be
+ * the (int32) error code.
+ */
+int
+lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist)
+{
+ nvpair_t *elem;
+ int error;
+ char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+ /* determine the pool name */
+ elem = nvlist_next_nvpair(bmarks, NULL);
+ if (elem == NULL)
+ return (0);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/#")] = '\0';
+
+ error = lzc_ioctl(ZFS_IOC_DESTROY_BOOKMARKS, pool, bmarks, errlist);
+
+ return (error);
+}
+
+static int
+lzc_channel_program_impl(const char *pool, const char *program, boolean_t sync,
+ uint64_t instrlimit, uint64_t memlimit, nvlist_t *argnvl, nvlist_t **outnvl)
+{
+ int error;
+ nvlist_t *args;
+
+ args = fnvlist_alloc();
+ fnvlist_add_string(args, ZCP_ARG_PROGRAM, program);
+ fnvlist_add_nvlist(args, ZCP_ARG_ARGLIST, argnvl);
+ fnvlist_add_boolean_value(args, ZCP_ARG_SYNC, sync);
+ fnvlist_add_uint64(args, ZCP_ARG_INSTRLIMIT, instrlimit);
+ fnvlist_add_uint64(args, ZCP_ARG_MEMLIMIT, memlimit);
+ error = lzc_ioctl(ZFS_IOC_CHANNEL_PROGRAM, pool, args, outnvl);
+ fnvlist_free(args);
+
+ return (error);
+}
+
+/*
+ * Executes a channel program.
+ *
+ * If this function returns 0 the channel program was successfully loaded and
+ * ran without failing. Note that individual commands the channel program ran
+ * may have failed and the channel program is responsible for reporting such
+ * errors through outnvl if they are important.
+ *
+ * This method may also return:
+ *
+ * EINVAL The program contains syntax errors, or an invalid memory or time
+ * limit was given. No part of the channel program was executed.
+ * If caused by syntax errors, 'outnvl' contains information about the
+ * errors.
+ *
+ * EDOM The program was executed, but encountered a runtime error, such as
+ * calling a function with incorrect arguments, invoking the error()
+ * function directly, failing an assert() command, etc. Some portion
+ * of the channel program may have executed and committed changes.
+ * Information about the failure can be found in 'outnvl'.
+ *
+ * ENOMEM The program fully executed, but the output buffer was not large
+ * enough to store the returned value. No output is returned through
+ * 'outnvl'.
+ *
+ * ENOSPC The program was terminated because it exceeded its memory usage
+ * limit. Some portion of the channel program may have executed and
+ * committed changes to disk. No output is returned through 'outnvl'.
+ *
+ * ETIMEDOUT The program was terminated because it exceeded its Lua instruction
+ * limit. Some portion of the channel program may have executed and
+ * committed changes to disk. No output is returned through 'outnvl'.
+ */
+int
+lzc_channel_program(const char *pool, const char *program, uint64_t instrlimit,
+ uint64_t memlimit, nvlist_t *argnvl, nvlist_t **outnvl)
+{
+ return (lzc_channel_program_impl(pool, program, B_TRUE, instrlimit,
+ memlimit, argnvl, outnvl));
+}
+
+/*
+ * Creates a checkpoint for the specified pool.
+ *
+ * If this function returns 0 the pool was successfully checkpointed.
+ *
+ * This method may also return:
+ *
+ * ZFS_ERR_CHECKPOINT_EXISTS
+ * The pool already has a checkpoint. A pools can only have one
+ * checkpoint at most, at any given time.
+ *
+ * ZFS_ERR_DISCARDING_CHECKPOINT
+ * ZFS is in the middle of discarding a checkpoint for this pool.
+ * The pool can be checkpointed again once the discard is done.
+ *
+ * ZFS_DEVRM_IN_PROGRESS
+ * A vdev is currently being removed. The pool cannot be
+ * checkpointed until the device removal is done.
+ *
+ * ZFS_VDEV_TOO_BIG
+ * One or more top-level vdevs exceed the maximum vdev size
+ * supported for this feature.
+ */
+int
+lzc_pool_checkpoint(const char *pool)
+{
+ int error;
+
+ nvlist_t *result = NULL;
+ nvlist_t *args = fnvlist_alloc();
+
+ error = lzc_ioctl(ZFS_IOC_POOL_CHECKPOINT, pool, args, &result);
+
+ fnvlist_free(args);
+ fnvlist_free(result);
+
+ return (error);
+}
+
+/*
+ * Discard the checkpoint from the specified pool.
+ *
+ * If this function returns 0 the checkpoint was successfully discarded.
+ *
+ * This method may also return:
+ *
+ * ZFS_ERR_NO_CHECKPOINT
+ * The pool does not have a checkpoint.
+ *
+ * ZFS_ERR_DISCARDING_CHECKPOINT
+ * ZFS is already in the middle of discarding the checkpoint.
+ */
+int
+lzc_pool_checkpoint_discard(const char *pool)
+{
+ int error;
+
+ nvlist_t *result = NULL;
+ nvlist_t *args = fnvlist_alloc();
+
+ error = lzc_ioctl(ZFS_IOC_POOL_DISCARD_CHECKPOINT, pool, args, &result);
+
+ fnvlist_free(args);
+ fnvlist_free(result);
+
+ return (error);
+}
+
+/*
+ * Executes a read-only channel program.
+ *
+ * A read-only channel program works programmatically the same way as a
+ * normal channel program executed with lzc_channel_program(). The only
+ * difference is it runs exclusively in open-context and therefore can
+ * return faster. The downside to that, is that the program cannot change
+ * on-disk state by calling functions from the zfs.sync submodule.
+ *
+ * The return values of this function (and their meaning) are exactly the
+ * same as the ones described in lzc_channel_program().
+ */
+int
+lzc_channel_program_nosync(const char *pool, const char *program,
+ uint64_t timeout, uint64_t memlimit, nvlist_t *argnvl, nvlist_t **outnvl)
+{
+ return (lzc_channel_program_impl(pool, program, B_FALSE, timeout,
+ memlimit, argnvl, outnvl));
+}
+
+/*
+ * Changes initializing state.
+ *
+ * vdevs should be a list of (<key>, guid) where guid is a uint64 vdev GUID.
+ * The key is ignored.
+ *
+ * If there are errors related to vdev arguments, per-vdev errors are returned
+ * in an nvlist with the key "vdevs". Each error is a (guid, errno) pair where
+ * guid is stringified with PRIu64, and errno is one of the following as
+ * an int64_t:
+ * - ENODEV if the device was not found
+ * - EINVAL if the devices is not a leaf or is not concrete (e.g. missing)
+ * - EROFS if the device is not writeable
+ * - EBUSY start requested but the device is already being initialized
+ * - ESRCH cancel/suspend requested but device is not being initialized
+ *
+ * If the errlist is empty, then return value will be:
+ * - EINVAL if one or more arguments was invalid
+ * - Other spa_open failures
+ * - 0 if the operation succeeded
+ */
+int
+lzc_initialize(const char *poolname, pool_initialize_func_t cmd_type,
+ nvlist_t *vdevs, nvlist_t **errlist)
+{
+ int error;
+ nvlist_t *args = fnvlist_alloc();
+ fnvlist_add_uint64(args, ZPOOL_INITIALIZE_COMMAND, (uint64_t)cmd_type);
+ fnvlist_add_nvlist(args, ZPOOL_INITIALIZE_VDEVS, vdevs);
+
+ error = lzc_ioctl(ZFS_IOC_POOL_INITIALIZE, poolname, args, errlist);
+
+ fnvlist_free(args);
+
+ return (error);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
new file mode 100644
index 000000000000..97d7ce81d8ab
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
@@ -0,0 +1,112 @@
+/*
+ * 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 (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ * Copyright 2017 RackTop Systems.
+ * Copyright (c) 2017 Datto Inc.
+ */
+
+#ifndef _LIBZFS_CORE_H
+#define _LIBZFS_CORE_H
+
+#include <libnvpair.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/fs/zfs.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int libzfs_core_init(void);
+void libzfs_core_fini(void);
+
+/*
+ * NB: this type should be kept binary compatible with dmu_objset_type_t.
+ */
+enum lzc_dataset_type {
+ LZC_DATSET_TYPE_ZFS = 2,
+ LZC_DATSET_TYPE_ZVOL
+};
+
+int lzc_remap(const char *fsname);
+int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
+int lzc_create(const char *, enum lzc_dataset_type, nvlist_t *);
+int lzc_clone(const char *, const char *, nvlist_t *);
+int lzc_promote(const char *, char *, int);
+int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **);
+int lzc_bookmark(nvlist_t *, nvlist_t **);
+int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **);
+int lzc_destroy_bookmarks(nvlist_t *, nvlist_t **);
+int lzc_initialize(const char *, pool_initialize_func_t, nvlist_t *,
+ nvlist_t **);
+
+int lzc_snaprange_space(const char *, const char *, uint64_t *);
+
+int lzc_hold(nvlist_t *, int, nvlist_t **);
+int lzc_release(nvlist_t *, nvlist_t **);
+int lzc_get_holds(const char *, nvlist_t **);
+
+enum lzc_send_flags {
+ LZC_SEND_FLAG_EMBED_DATA = 1 << 0,
+ LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1,
+ LZC_SEND_FLAG_COMPRESS = 1 << 2
+};
+
+int lzc_send(const char *, const char *, int, enum lzc_send_flags);
+int lzc_send_resume(const char *, const char *, int,
+ enum lzc_send_flags, uint64_t, uint64_t);
+int lzc_send_space(const char *, const char *, enum lzc_send_flags, uint64_t *);
+
+struct dmu_replay_record;
+
+int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
+int lzc_receive_resumable(const char *, nvlist_t *, const char *,
+ boolean_t, int);
+int lzc_receive_with_header(const char *, nvlist_t *, const char *, boolean_t,
+ boolean_t, int, const struct dmu_replay_record *);
+
+boolean_t lzc_exists(const char *);
+
+int lzc_rollback(const char *, char *, int);
+int lzc_rollback_to(const char *, const char *);
+
+int lzc_sync(const char *, nvlist_t *, nvlist_t **);
+
+int lzc_rename(const char *, const char *);
+int lzc_destroy(const char *);
+
+int lzc_channel_program(const char *, const char *, uint64_t,
+ uint64_t, nvlist_t *, nvlist_t **);
+int lzc_channel_program_nosync(const char *, const char *, uint64_t,
+ uint64_t, nvlist_t *, nvlist_t **);
+
+int lzc_pool_checkpoint(const char *);
+int lzc_pool_checkpoint_discard(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBZFS_CORE_H */
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.c b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.c
new file mode 100644
index 000000000000..a3b872ee29da
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.c
@@ -0,0 +1,189 @@
+/*
+ * 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 (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ */
+
+#include <sys/zfs_ioctl.h>
+#include <zfs_ioctl_compat.h>
+#include "libzfs_core_compat.h"
+
+extern int zfs_ioctl_version;
+
+int
+lzc_compat_pre(zfs_cmd_t *zc, zfs_ioc_t *ioc, nvlist_t **source)
+{
+ nvlist_t *nvl = NULL;
+ nvpair_t *pair, *hpair;
+ char *buf, *val;
+ zfs_ioc_t vecnum;
+ uint32_t type32;
+ int32_t cleanup_fd;
+ int error = 0;
+ int pos;
+
+ if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
+ return (0);
+
+ vecnum = *ioc;
+
+ switch (vecnum) {
+ case ZFS_IOC_CREATE:
+ type32 = fnvlist_lookup_int32(*source, "type");
+ zc->zc_objset_type = (uint64_t)type32;
+ nvlist_lookup_nvlist(*source, "props", &nvl);
+ *source = nvl;
+ break;
+ case ZFS_IOC_CLONE:
+ buf = fnvlist_lookup_string(*source, "origin");
+ strlcpy(zc->zc_value, buf, MAXPATHLEN);
+ nvlist_lookup_nvlist(*source, "props", &nvl);
+ *ioc = ZFS_IOC_CREATE;
+ *source = nvl;
+ break;
+ case ZFS_IOC_SNAPSHOT:
+ nvl = fnvlist_lookup_nvlist(*source, "snaps");
+ pair = nvlist_next_nvpair(nvl, NULL);
+ if (pair != NULL) {
+ buf = nvpair_name(pair);
+ pos = strcspn(buf, "@");
+ strlcpy(zc->zc_name, buf, pos + 1);
+ strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
+ } else
+ error = EINVAL;
+ /* old kernel cannot create multiple snapshots */
+ if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
+ error = EOPNOTSUPP;
+ nvlist_free(nvl);
+ nvl = NULL;
+ nvlist_lookup_nvlist(*source, "props", &nvl);
+ *source = nvl;
+ break;
+ case ZFS_IOC_SPACE_SNAPS:
+ buf = fnvlist_lookup_string(*source, "firstsnap");
+ strlcpy(zc->zc_value, buf, MAXPATHLEN);
+ break;
+ case ZFS_IOC_DESTROY_SNAPS:
+ nvl = fnvlist_lookup_nvlist(*source, "snaps");
+ pair = nvlist_next_nvpair(nvl, NULL);
+ if (pair != NULL) {
+ buf = nvpair_name(pair);
+ pos = strcspn(buf, "@");
+ strlcpy(zc->zc_name, buf, pos + 1);
+ } else
+ error = EINVAL;
+ /* old kernel cannot atomically destroy multiple snaps */
+ if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
+ error = EOPNOTSUPP;
+ *source = nvl;
+ break;
+ case ZFS_IOC_HOLD:
+ nvl = fnvlist_lookup_nvlist(*source, "holds");
+ pair = nvlist_next_nvpair(nvl, NULL);
+ if (pair != NULL) {
+ buf = nvpair_name(pair);
+ pos = strcspn(buf, "@");
+ strlcpy(zc->zc_name, buf, pos + 1);
+ strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
+ if (nvpair_value_string(pair, &val) == 0)
+ strlcpy(zc->zc_string, val, MAXNAMELEN);
+ else
+ error = EINVAL;
+ } else
+ error = EINVAL;
+ /* old kernel cannot atomically create multiple holds */
+ if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
+ error = EOPNOTSUPP;
+ nvlist_free(nvl);
+ if (nvlist_lookup_int32(*source, "cleanup_fd",
+ &cleanup_fd) == 0)
+ zc->zc_cleanup_fd = cleanup_fd;
+ else
+ zc->zc_cleanup_fd = -1;
+ break;
+ case ZFS_IOC_RELEASE:
+ pair = nvlist_next_nvpair(*source, NULL);
+ if (pair != NULL) {
+ buf = nvpair_name(pair);
+ pos = strcspn(buf, "@");
+ strlcpy(zc->zc_name, buf, pos + 1);
+ strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
+ if (nvpair_value_nvlist(pair, &nvl) == 0) {
+ hpair = nvlist_next_nvpair(nvl, NULL);
+ if (hpair != NULL)
+ strlcpy(zc->zc_string,
+ nvpair_name(hpair), MAXNAMELEN);
+ else
+ error = EINVAL;
+ if (!error && nvlist_next_nvpair(nvl,
+ hpair) != NULL)
+ error = EOPNOTSUPP;
+ } else
+ error = EINVAL;
+ } else
+ error = EINVAL;
+ /* old kernel cannot atomically release multiple holds */
+ if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+void
+lzc_compat_post(zfs_cmd_t *zc, const zfs_ioc_t ioc)
+{
+ if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
+ return;
+
+ switch (ioc) {
+ case ZFS_IOC_CREATE:
+ case ZFS_IOC_CLONE:
+ case ZFS_IOC_SNAPSHOT:
+ case ZFS_IOC_SPACE_SNAPS:
+ case ZFS_IOC_DESTROY_SNAPS:
+ zc->zc_nvlist_dst_filled = B_FALSE;
+ break;
+ }
+}
+
+int
+lzc_compat_outnvl(zfs_cmd_t *zc, const zfs_ioc_t ioc, nvlist_t **outnvl)
+{
+ nvlist_t *nvl;
+
+ if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
+ return (0);
+
+ switch (ioc) {
+ case ZFS_IOC_SPACE_SNAPS:
+ nvl = fnvlist_alloc();
+ fnvlist_add_uint64(nvl, "used", zc->zc_cookie);
+ fnvlist_add_uint64(nvl, "compressed", zc->zc_objset_type);
+ fnvlist_add_uint64(nvl, "uncompressed", zc->zc_perm_action);
+ *outnvl = nvl;
+ break;
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.h b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.h
new file mode 100644
index 000000000000..6527c4b2576f
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.h
@@ -0,0 +1,47 @@
+/*
+ * 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 (c) 2013 by Martin Matuska <mm@FreeBSD.org>. All rights reserved.
+ */
+
+#ifndef _LIBZFS_CORE_COMPAT_H
+#define _LIBZFS_CORE_COMPAT_H
+
+#include <libnvpair.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int lzc_compat_pre(zfs_cmd_t *, zfs_ioc_t *, nvlist_t **);
+void lzc_compat_post(zfs_cmd_t *, const zfs_ioc_t);
+int lzc_compat_outnvl(zfs_cmd_t *, const zfs_ioc_t, nvlist_t **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBZFS_CORE_COMPAT_H */
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
new file mode 100644
index 000000000000..9b54e419705b
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
@@ -0,0 +1,1238 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+#include <libgen.h>
+#include <sys/assfail.h>
+#include <sys/spa.h>
+#include <sys/stat.h>
+#include <sys/processor.h>
+#include <sys/zfs_context.h>
+#include <sys/rrwlock.h>
+#include <sys/zmod.h>
+#include <sys/utsname.h>
+#include <sys/systeminfo.h>
+#include <libzfs.h>
+
+/*
+ * Emulation of kernel services in userland.
+ */
+
+#ifndef __FreeBSD__
+int aok;
+#endif
+uint64_t physmem;
+vnode_t *rootdir = (vnode_t *)0xabcd1234;
+char hw_serial[HW_HOSTID_LEN];
+#ifdef illumos
+kmutex_t cpu_lock;
+#endif
+
+/* If set, all blocks read will be copied to the specified directory. */
+char *vn_dumpdir = NULL;
+
+struct utsname utsname = {
+ "userland", "libzpool", "1", "1", "na"
+};
+
+/* this only exists to have its address taken */
+struct proc p0;
+
+/*
+ * =========================================================================
+ * threads
+ * =========================================================================
+ */
+/*ARGSUSED*/
+kthread_t *
+zk_thread_create(void (*func)(), void *arg)
+{
+ thread_t tid;
+
+ VERIFY(thr_create(0, 0, (void *(*)(void *))func, arg, THR_DETACHED,
+ &tid) == 0);
+
+ return ((void *)(uintptr_t)tid);
+}
+
+/*
+ * =========================================================================
+ * kstats
+ * =========================================================================
+ */
+/*ARGSUSED*/
+kstat_t *
+kstat_create(char *module, int instance, char *name, char *class,
+ uchar_t type, ulong_t ndata, uchar_t ks_flag)
+{
+ return (NULL);
+}
+
+/*ARGSUSED*/
+void
+kstat_named_init(kstat_named_t *knp, const char *name, uchar_t type)
+{}
+
+/*ARGSUSED*/
+void
+kstat_install(kstat_t *ksp)
+{}
+
+/*ARGSUSED*/
+void
+kstat_delete(kstat_t *ksp)
+{}
+
+/*
+ * =========================================================================
+ * mutexes
+ * =========================================================================
+ */
+void
+zmutex_init(kmutex_t *mp)
+{
+ mp->m_owner = NULL;
+ mp->initialized = B_TRUE;
+ (void) _mutex_init(&mp->m_lock, USYNC_THREAD, NULL);
+}
+
+void
+zmutex_destroy(kmutex_t *mp)
+{
+ ASSERT(mp->initialized == B_TRUE);
+ ASSERT(mp->m_owner == NULL);
+ (void) _mutex_destroy(&(mp)->m_lock);
+ mp->m_owner = (void *)-1UL;
+ mp->initialized = B_FALSE;
+}
+
+int
+zmutex_owned(kmutex_t *mp)
+{
+ ASSERT(mp->initialized == B_TRUE);
+
+ return (mp->m_owner == curthread);
+}
+
+void
+mutex_enter(kmutex_t *mp)
+{
+ ASSERT(mp->initialized == B_TRUE);
+ ASSERT(mp->m_owner != (void *)-1UL);
+ ASSERT(mp->m_owner != curthread);
+ VERIFY(mutex_lock(&mp->m_lock) == 0);
+ ASSERT(mp->m_owner == NULL);
+ mp->m_owner = curthread;
+}
+
+int
+mutex_tryenter(kmutex_t *mp)
+{
+ ASSERT(mp->initialized == B_TRUE);
+ ASSERT(mp->m_owner != (void *)-1UL);
+ if (0 == mutex_trylock(&mp->m_lock)) {
+ ASSERT(mp->m_owner == NULL);
+ mp->m_owner = curthread;
+ return (1);
+ } else {
+ return (0);
+ }
+}
+
+void
+mutex_exit(kmutex_t *mp)
+{
+ ASSERT(mp->initialized == B_TRUE);
+ ASSERT(mutex_owner(mp) == curthread);
+ mp->m_owner = NULL;
+ VERIFY(mutex_unlock(&mp->m_lock) == 0);
+}
+
+void *
+mutex_owner(kmutex_t *mp)
+{
+ ASSERT(mp->initialized == B_TRUE);
+ return (mp->m_owner);
+}
+
+/*
+ * =========================================================================
+ * rwlocks
+ * =========================================================================
+ */
+/*ARGSUSED*/
+void
+rw_init(krwlock_t *rwlp, char *name, int type, void *arg)
+{
+ rwlock_init(&rwlp->rw_lock, USYNC_THREAD, NULL);
+ rwlp->rw_owner = NULL;
+ rwlp->initialized = B_TRUE;
+ rwlp->rw_count = 0;
+}
+
+void
+rw_destroy(krwlock_t *rwlp)
+{
+ ASSERT(rwlp->rw_count == 0);
+ rwlock_destroy(&rwlp->rw_lock);
+ rwlp->rw_owner = (void *)-1UL;
+ rwlp->initialized = B_FALSE;
+}
+
+void
+rw_enter(krwlock_t *rwlp, krw_t rw)
+{
+ //ASSERT(!RW_LOCK_HELD(rwlp));
+ ASSERT(rwlp->initialized == B_TRUE);
+ ASSERT(rwlp->rw_owner != (void *)-1UL);
+ ASSERT(rwlp->rw_owner != curthread);
+
+ if (rw == RW_READER) {
+ VERIFY(rw_rdlock(&rwlp->rw_lock) == 0);
+ ASSERT(rwlp->rw_count >= 0);
+ atomic_add_int(&rwlp->rw_count, 1);
+ } else {
+ VERIFY(rw_wrlock(&rwlp->rw_lock) == 0);
+ ASSERT(rwlp->rw_count == 0);
+ rwlp->rw_count = -1;
+ rwlp->rw_owner = curthread;
+ }
+}
+
+void
+rw_exit(krwlock_t *rwlp)
+{
+ ASSERT(rwlp->initialized == B_TRUE);
+ ASSERT(rwlp->rw_owner != (void *)-1UL);
+
+ if (rwlp->rw_owner == curthread) {
+ /* Write locked. */
+ ASSERT(rwlp->rw_count == -1);
+ rwlp->rw_count = 0;
+ rwlp->rw_owner = NULL;
+ } else {
+ /* Read locked. */
+ ASSERT(rwlp->rw_count > 0);
+ atomic_add_int(&rwlp->rw_count, -1);
+ }
+ VERIFY(rw_unlock(&rwlp->rw_lock) == 0);
+}
+
+int
+rw_tryenter(krwlock_t *rwlp, krw_t rw)
+{
+ int rv;
+
+ ASSERT(rwlp->initialized == B_TRUE);
+ ASSERT(rwlp->rw_owner != (void *)-1UL);
+ ASSERT(rwlp->rw_owner != curthread);
+
+ if (rw == RW_READER)
+ rv = rw_tryrdlock(&rwlp->rw_lock);
+ else
+ rv = rw_trywrlock(&rwlp->rw_lock);
+
+ if (rv == 0) {
+ ASSERT(rwlp->rw_owner == NULL);
+ if (rw == RW_READER) {
+ ASSERT(rwlp->rw_count >= 0);
+ atomic_add_int(&rwlp->rw_count, 1);
+ } else {
+ ASSERT(rwlp->rw_count == 0);
+ rwlp->rw_count = -1;
+ rwlp->rw_owner = curthread;
+ }
+ return (1);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+rw_tryupgrade(krwlock_t *rwlp)
+{
+ ASSERT(rwlp->initialized == B_TRUE);
+ ASSERT(rwlp->rw_owner != (void *)-1UL);
+
+ return (0);
+}
+
+int
+rw_lock_held(krwlock_t *rwlp)
+{
+
+ return (rwlp->rw_count != 0);
+}
+
+/*
+ * =========================================================================
+ * condition variables
+ * =========================================================================
+ */
+/*ARGSUSED*/
+void
+cv_init(kcondvar_t *cv, char *name, int type, void *arg)
+{
+ VERIFY(cond_init(cv, name, NULL) == 0);
+}
+
+void
+cv_destroy(kcondvar_t *cv)
+{
+ VERIFY(cond_destroy(cv) == 0);
+}
+
+void
+cv_wait(kcondvar_t *cv, kmutex_t *mp)
+{
+ ASSERT(mutex_owner(mp) == curthread);
+ mp->m_owner = NULL;
+ int ret = cond_wait(cv, &mp->m_lock);
+ VERIFY(ret == 0 || ret == EINTR);
+ mp->m_owner = curthread;
+}
+
+/*
+ * NB: this emulates FreeBSD cv_wait_sig(9), not the illumos one.
+ * Meanings of the return code are different.
+ * NB: this does not actually catch any signals.
+ */
+int
+cv_wait_sig(kcondvar_t *cv, kmutex_t *mp)
+{
+ cv_wait(cv, mp);
+ return (0);
+}
+
+clock_t
+cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
+{
+ int error;
+ struct timespec ts;
+ struct timeval tv;
+ clock_t delta;
+
+ abstime += ddi_get_lbolt();
+top:
+ delta = abstime - ddi_get_lbolt();
+ if (delta <= 0)
+ return (-1);
+
+ if (gettimeofday(&tv, NULL) != 0)
+ assert(!"gettimeofday() failed");
+
+ ts.tv_sec = tv.tv_sec + delta / hz;
+ ts.tv_nsec = tv.tv_usec * 1000 + (delta % hz) * (NANOSEC / hz);
+ ASSERT(ts.tv_nsec >= 0);
+
+ if (ts.tv_nsec >= NANOSEC) {
+ ts.tv_sec++;
+ ts.tv_nsec -= NANOSEC;
+ }
+
+ ASSERT(mutex_owner(mp) == curthread);
+ mp->m_owner = NULL;
+ error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
+ mp->m_owner = curthread;
+
+ if (error == EINTR)
+ goto top;
+
+ if (error == ETIMEDOUT)
+ return (-1);
+
+ ASSERT(error == 0);
+
+ return (1);
+}
+
+/*ARGSUSED*/
+clock_t
+cv_timedwait_hires(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim, hrtime_t res,
+ int flag)
+{
+ int error;
+ timespec_t ts;
+ hrtime_t delta;
+
+ ASSERT(flag == 0 || flag == CALLOUT_FLAG_ABSOLUTE);
+
+top:
+ delta = tim;
+ if (flag & CALLOUT_FLAG_ABSOLUTE)
+ delta -= gethrtime();
+
+ if (delta <= 0)
+ return (-1);
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += delta / NANOSEC;
+ ts.tv_nsec += delta % NANOSEC;
+ if (ts.tv_nsec >= NANOSEC) {
+ ts.tv_sec++;
+ ts.tv_nsec -= NANOSEC;
+ }
+
+ ASSERT(mutex_owner(mp) == curthread);
+ mp->m_owner = NULL;
+ error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
+ mp->m_owner = curthread;
+
+ if (error == ETIMEDOUT)
+ return (-1);
+
+ if (error == EINTR)
+ goto top;
+
+ ASSERT(error == 0);
+
+ return (1);
+}
+
+void
+cv_signal(kcondvar_t *cv)
+{
+ VERIFY(cond_signal(cv) == 0);
+}
+
+void
+cv_broadcast(kcondvar_t *cv)
+{
+ VERIFY(cond_broadcast(cv) == 0);
+}
+
+/*
+ * =========================================================================
+ * vnode operations
+ * =========================================================================
+ */
+/*
+ * Note: for the xxxat() versions of these functions, we assume that the
+ * starting vp is always rootdir (which is true for spa_directory.c, the only
+ * ZFS consumer of these interfaces). We assert this is true, and then emulate
+ * them by adding '/' in front of the path.
+ */
+
+/*ARGSUSED*/
+int
+vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
+{
+ int fd;
+ int dump_fd;
+ vnode_t *vp;
+ int old_umask;
+ char realpath[MAXPATHLEN];
+ struct stat64 st;
+
+ /*
+ * If we're accessing a real disk from userland, we need to use
+ * the character interface to avoid caching. This is particularly
+ * important if we're trying to look at a real in-kernel storage
+ * pool from userland, e.g. via zdb, because otherwise we won't
+ * see the changes occurring under the segmap cache.
+ * On the other hand, the stupid character device returns zero
+ * for its size. So -- gag -- we open the block device to get
+ * its size, and remember it for subsequent VOP_GETATTR().
+ */
+ if (strncmp(path, "/dev/", 5) == 0) {
+ char *dsk;
+ fd = open64(path, O_RDONLY);
+ if (fd == -1)
+ return (errno);
+ if (fstat64(fd, &st) == -1) {
+ close(fd);
+ return (errno);
+ }
+ close(fd);
+ (void) sprintf(realpath, "%s", path);
+ dsk = strstr(path, "/dsk/");
+ if (dsk != NULL)
+ (void) sprintf(realpath + (dsk - path) + 1, "r%s",
+ dsk + 1);
+ } else {
+ (void) sprintf(realpath, "%s", path);
+ if (!(flags & FCREAT) && stat64(realpath, &st) == -1)
+ return (errno);
+ }
+
+ if (flags & FCREAT)
+ old_umask = umask(0);
+
+ /*
+ * The construct 'flags - FREAD' conveniently maps combinations of
+ * FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR.
+ */
+ fd = open64(realpath, flags - FREAD, mode);
+
+ if (flags & FCREAT)
+ (void) umask(old_umask);
+
+ if (vn_dumpdir != NULL) {
+ char dumppath[MAXPATHLEN];
+ (void) snprintf(dumppath, sizeof (dumppath),
+ "%s/%s", vn_dumpdir, basename(realpath));
+ dump_fd = open64(dumppath, O_CREAT | O_WRONLY, 0666);
+ if (dump_fd == -1)
+ return (errno);
+ } else {
+ dump_fd = -1;
+ }
+
+ if (fd == -1)
+ return (errno);
+
+ if (fstat64(fd, &st) == -1) {
+ close(fd);
+ return (errno);
+ }
+
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ *vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL);
+
+ vp->v_fd = fd;
+ vp->v_size = st.st_size;
+ vp->v_path = spa_strdup(path);
+ vp->v_dump_fd = dump_fd;
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
+ int x3, vnode_t *startvp, int fd)
+{
+ char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL);
+ int ret;
+
+ ASSERT(startvp == rootdir);
+ (void) sprintf(realpath, "/%s", path);
+
+ /* fd ignored for now, need if want to simulate nbmand support */
+ ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3);
+
+ umem_free(realpath, strlen(path) + 2);
+
+ return (ret);
+}
+
+/*ARGSUSED*/
+int
+vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
+ int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
+{
+ ssize_t iolen, split;
+
+ if (uio == UIO_READ) {
+ iolen = pread64(vp->v_fd, addr, len, offset);
+ if (vp->v_dump_fd != -1) {
+ int status =
+ pwrite64(vp->v_dump_fd, addr, iolen, offset);
+ ASSERT(status != -1);
+ }
+ } else {
+ /*
+ * To simulate partial disk writes, we split writes into two
+ * system calls so that the process can be killed in between.
+ */
+ int sectors = len >> SPA_MINBLOCKSHIFT;
+ split = (sectors > 0 ? rand() % sectors : 0) <<
+ SPA_MINBLOCKSHIFT;
+ iolen = pwrite64(vp->v_fd, addr, split, offset);
+ iolen += pwrite64(vp->v_fd, (char *)addr + split,
+ len - split, offset + split);
+ }
+
+ if (iolen == -1)
+ return (errno);
+ if (residp)
+ *residp = len - iolen;
+ else if (iolen != len)
+ return (EIO);
+ return (0);
+}
+
+void
+vn_close(vnode_t *vp, int openflag, cred_t *cr, kthread_t *td)
+{
+ close(vp->v_fd);
+ if (vp->v_dump_fd != -1)
+ close(vp->v_dump_fd);
+ spa_strfree(vp->v_path);
+ umem_free(vp, sizeof (vnode_t));
+}
+
+/*
+ * At a minimum we need to update the size since vdev_reopen()
+ * will no longer call vn_openat().
+ */
+int
+fop_getattr(vnode_t *vp, vattr_t *vap)
+{
+ struct stat64 st;
+
+ if (fstat64(vp->v_fd, &st) == -1) {
+ close(vp->v_fd);
+ return (errno);
+ }
+
+ vap->va_size = st.st_size;
+ return (0);
+}
+
+#ifdef ZFS_DEBUG
+
+/*
+ * =========================================================================
+ * Figure out which debugging statements to print
+ * =========================================================================
+ */
+
+static char *dprintf_string;
+static int dprintf_print_all;
+
+int
+dprintf_find_string(const char *string)
+{
+ char *tmp_str = dprintf_string;
+ int len = strlen(string);
+
+ /*
+ * Find out if this is a string we want to print.
+ * String format: file1.c,function_name1,file2.c,file3.c
+ */
+
+ while (tmp_str != NULL) {
+ if (strncmp(tmp_str, string, len) == 0 &&
+ (tmp_str[len] == ',' || tmp_str[len] == '\0'))
+ return (1);
+ tmp_str = strchr(tmp_str, ',');
+ if (tmp_str != NULL)
+ tmp_str++; /* Get rid of , */
+ }
+ return (0);
+}
+
+void
+dprintf_setup(int *argc, char **argv)
+{
+ int i, j;
+
+ /*
+ * Debugging can be specified two ways: by setting the
+ * environment variable ZFS_DEBUG, or by including a
+ * "debug=..." argument on the command line. The command
+ * line setting overrides the environment variable.
+ */
+
+ for (i = 1; i < *argc; i++) {
+ int len = strlen("debug=");
+ /* First look for a command line argument */
+ if (strncmp("debug=", argv[i], len) == 0) {
+ dprintf_string = argv[i] + len;
+ /* Remove from args */
+ for (j = i; j < *argc; j++)
+ argv[j] = argv[j+1];
+ argv[j] = NULL;
+ (*argc)--;
+ }
+ }
+
+ if (dprintf_string == NULL) {
+ /* Look for ZFS_DEBUG environment variable */
+ dprintf_string = getenv("ZFS_DEBUG");
+ }
+
+ /*
+ * Are we just turning on all debugging?
+ */
+ if (dprintf_find_string("on"))
+ dprintf_print_all = 1;
+
+ if (dprintf_string != NULL)
+ zfs_flags |= ZFS_DEBUG_DPRINTF;
+}
+
+int
+sysctl_handle_64(SYSCTL_HANDLER_ARGS)
+{
+ return (0);
+}
+
+/*
+ * =========================================================================
+ * debug printfs
+ * =========================================================================
+ */
+void
+__dprintf(const char *file, const char *func, int line, const char *fmt, ...)
+{
+ const char *newfile;
+ va_list adx;
+
+ /*
+ * Get rid of annoying "../common/" prefix to filename.
+ */
+ newfile = strrchr(file, '/');
+ if (newfile != NULL) {
+ newfile = newfile + 1; /* Get rid of leading / */
+ } else {
+ newfile = file;
+ }
+
+ if (dprintf_print_all ||
+ dprintf_find_string(newfile) ||
+ dprintf_find_string(func)) {
+ /* Print out just the function name if requested */
+ flockfile(stdout);
+ if (dprintf_find_string("pid"))
+ (void) printf("%d ", getpid());
+ if (dprintf_find_string("tid"))
+ (void) printf("%lu ", thr_self());
+#if 0
+ if (dprintf_find_string("cpu"))
+ (void) printf("%u ", getcpuid());
+#endif
+ if (dprintf_find_string("time"))
+ (void) printf("%llu ", gethrtime());
+ if (dprintf_find_string("long"))
+ (void) printf("%s, line %d: ", newfile, line);
+ (void) printf("%s: ", func);
+ va_start(adx, fmt);
+ (void) vprintf(fmt, adx);
+ va_end(adx);
+ funlockfile(stdout);
+ }
+}
+
+#endif /* ZFS_DEBUG */
+
+/*
+ * =========================================================================
+ * cmn_err() and panic()
+ * =========================================================================
+ */
+static char ce_prefix[CE_IGNORE][10] = { "", "NOTICE: ", "WARNING: ", "" };
+static char ce_suffix[CE_IGNORE][2] = { "", "\n", "\n", "" };
+
+void
+vpanic(const char *fmt, va_list adx)
+{
+ char buf[512];
+ (void) vsnprintf(buf, 512, fmt, adx);
+ assfail(buf, NULL, 0);
+ abort(); /* necessary to make vpanic meet noreturn requirements */
+}
+
+void
+panic(const char *fmt, ...)
+{
+ va_list adx;
+
+ va_start(adx, fmt);
+ vpanic(fmt, adx);
+ va_end(adx);
+}
+
+void
+vcmn_err(int ce, const char *fmt, va_list adx)
+{
+ if (ce == CE_PANIC)
+ vpanic(fmt, adx);
+ if (ce != CE_NOTE) { /* suppress noise in userland stress testing */
+ (void) fprintf(stderr, "%s", ce_prefix[ce]);
+ (void) vfprintf(stderr, fmt, adx);
+ (void) fprintf(stderr, "%s", ce_suffix[ce]);
+ }
+}
+
+/*PRINTFLIKE2*/
+void
+cmn_err(int ce, const char *fmt, ...)
+{
+ va_list adx;
+
+ va_start(adx, fmt);
+ vcmn_err(ce, fmt, adx);
+ va_end(adx);
+}
+
+/*
+ * =========================================================================
+ * kobj interfaces
+ * =========================================================================
+ */
+struct _buf *
+kobj_open_file(char *name)
+{
+ struct _buf *file;
+ vnode_t *vp;
+
+ /* set vp as the _fd field of the file */
+ if (vn_openat(name, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0, rootdir,
+ -1) != 0)
+ return ((void *)-1UL);
+
+ file = umem_zalloc(sizeof (struct _buf), UMEM_NOFAIL);
+ file->_fd = (intptr_t)vp;
+ return (file);
+}
+
+int
+kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off)
+{
+ ssize_t resid;
+
+ vn_rdwr(UIO_READ, (vnode_t *)file->_fd, buf, size, (offset_t)off,
+ UIO_SYSSPACE, 0, 0, 0, &resid);
+
+ return (size - resid);
+}
+
+void
+kobj_close_file(struct _buf *file)
+{
+ vn_close((vnode_t *)file->_fd, 0, NULL, NULL);
+ umem_free(file, sizeof (struct _buf));
+}
+
+int
+kobj_get_filesize(struct _buf *file, uint64_t *size)
+{
+ struct stat64 st;
+ vnode_t *vp = (vnode_t *)file->_fd;
+
+ if (fstat64(vp->v_fd, &st) == -1) {
+ vn_close(vp, 0, NULL, NULL);
+ return (errno);
+ }
+ *size = st.st_size;
+ return (0);
+}
+
+/*
+ * =========================================================================
+ * misc routines
+ * =========================================================================
+ */
+
+void
+delay(clock_t ticks)
+{
+ poll(0, 0, ticks * (1000 / hz));
+}
+
+#if 0
+/*
+ * Find highest one bit set.
+ * Returns bit number + 1 of highest bit that is set, otherwise returns 0.
+ */
+int
+highbit64(uint64_t i)
+{
+ int h = 1;
+
+ if (i == 0)
+ return (0);
+ if (i & 0xffffffff00000000ULL) {
+ h += 32; i >>= 32;
+ }
+ if (i & 0xffff0000) {
+ h += 16; i >>= 16;
+ }
+ if (i & 0xff00) {
+ h += 8; i >>= 8;
+ }
+ if (i & 0xf0) {
+ h += 4; i >>= 4;
+ }
+ if (i & 0xc) {
+ h += 2; i >>= 2;
+ }
+ if (i & 0x2) {
+ h += 1;
+ }
+ return (h);
+}
+#endif
+
+static int random_fd = -1, urandom_fd = -1;
+
+static int
+random_get_bytes_common(uint8_t *ptr, size_t len, int fd)
+{
+ size_t resid = len;
+ ssize_t bytes;
+
+ ASSERT(fd != -1);
+
+ while (resid != 0) {
+ bytes = read(fd, ptr, resid);
+ ASSERT3S(bytes, >=, 0);
+ ptr += bytes;
+ resid -= bytes;
+ }
+
+ return (0);
+}
+
+int
+random_get_bytes(uint8_t *ptr, size_t len)
+{
+ return (random_get_bytes_common(ptr, len, random_fd));
+}
+
+int
+random_get_pseudo_bytes(uint8_t *ptr, size_t len)
+{
+ return (random_get_bytes_common(ptr, len, urandom_fd));
+}
+
+int
+ddi_strtoul(const char *hw_serial, char **nptr, int base, unsigned long *result)
+{
+ char *end;
+
+ *result = strtoul(hw_serial, &end, base);
+ if (*result == 0)
+ return (errno);
+ return (0);
+}
+
+int
+ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result)
+{
+ char *end;
+
+ *result = strtoull(str, &end, base);
+ if (*result == 0)
+ return (errno);
+ return (0);
+}
+
+#ifdef illumos
+/* ARGSUSED */
+cyclic_id_t
+cyclic_add(cyc_handler_t *hdlr, cyc_time_t *when)
+{
+ return (1);
+}
+
+/* ARGSUSED */
+void
+cyclic_remove(cyclic_id_t id)
+{
+}
+
+/* ARGSUSED */
+int
+cyclic_reprogram(cyclic_id_t id, hrtime_t expiration)
+{
+ return (1);
+}
+#endif
+
+/*
+ * =========================================================================
+ * kernel emulation setup & teardown
+ * =========================================================================
+ */
+static int
+umem_out_of_memory(void)
+{
+ char errmsg[] = "out of memory -- generating core dump\n";
+
+ write(fileno(stderr), errmsg, sizeof (errmsg));
+ abort();
+ return (0);
+}
+
+void
+kernel_init(int mode)
+{
+ extern uint_t rrw_tsd_key;
+
+ umem_nofail_callback(umem_out_of_memory);
+
+ physmem = sysconf(_SC_PHYS_PAGES);
+
+ dprintf("physmem = %llu pages (%.2f GB)\n", physmem,
+ (double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30));
+
+ (void) snprintf(hw_serial, sizeof (hw_serial), "%ld",
+ (mode & FWRITE) ? get_system_hostid() : 0);
+
+ VERIFY((random_fd = open("/dev/random", O_RDONLY)) != -1);
+ VERIFY((urandom_fd = open("/dev/urandom", O_RDONLY)) != -1);
+
+ system_taskq_init();
+
+#ifdef illumos
+ mutex_init(&cpu_lock, NULL, MUTEX_DEFAULT, NULL);
+#endif
+
+ spa_init(mode);
+
+ tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
+}
+
+void
+kernel_fini(void)
+{
+ spa_fini();
+
+ system_taskq_fini();
+
+ close(random_fd);
+ close(urandom_fd);
+
+ random_fd = -1;
+ urandom_fd = -1;
+}
+
+/* ARGSUSED */
+uint32_t
+zone_get_hostid(void *zonep)
+{
+ /*
+ * We're emulating the system's hostid in userland.
+ */
+ return (strtoul(hw_serial, NULL, 10));
+}
+
+int
+z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
+{
+ int ret;
+ uLongf len = *dstlen;
+
+ if ((ret = uncompress(dst, &len, src, srclen)) == Z_OK)
+ *dstlen = (size_t)len;
+
+ return (ret);
+}
+
+int
+z_compress_level(void *dst, size_t *dstlen, const void *src, size_t srclen,
+ int level)
+{
+ int ret;
+ uLongf len = *dstlen;
+
+ if ((ret = compress2(dst, &len, src, srclen, level)) == Z_OK)
+ *dstlen = (size_t)len;
+
+ return (ret);
+}
+
+uid_t
+crgetuid(cred_t *cr)
+{
+ return (0);
+}
+
+uid_t
+crgetruid(cred_t *cr)
+{
+ return (0);
+}
+
+gid_t
+crgetgid(cred_t *cr)
+{
+ return (0);
+}
+
+int
+crgetngroups(cred_t *cr)
+{
+ return (0);
+}
+
+gid_t *
+crgetgroups(cred_t *cr)
+{
+ return (NULL);
+}
+
+int
+zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
+{
+ return (0);
+}
+
+int
+zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
+{
+ return (0);
+}
+
+int
+zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
+{
+ return (0);
+}
+
+ksiddomain_t *
+ksid_lookupdomain(const char *dom)
+{
+ ksiddomain_t *kd;
+
+ kd = umem_zalloc(sizeof (ksiddomain_t), UMEM_NOFAIL);
+ kd->kd_name = spa_strdup(dom);
+ return (kd);
+}
+
+void
+ksiddomain_rele(ksiddomain_t *ksid)
+{
+ spa_strfree(ksid->kd_name);
+ umem_free(ksid, sizeof (ksiddomain_t));
+}
+
+/*
+ * Do not change the length of the returned string; it must be freed
+ * with strfree().
+ */
+char *
+kmem_asprintf(const char *fmt, ...)
+{
+ int size;
+ va_list adx;
+ char *buf;
+
+ va_start(adx, fmt);
+ size = vsnprintf(NULL, 0, fmt, adx) + 1;
+ va_end(adx);
+
+ buf = kmem_alloc(size, KM_SLEEP);
+
+ va_start(adx, fmt);
+ size = vsnprintf(buf, size, fmt, adx);
+ va_end(adx);
+
+ return (buf);
+}
+
+/* ARGSUSED */
+int
+zfs_onexit_fd_hold(int fd, minor_t *minorp)
+{
+ *minorp = 0;
+ return (0);
+}
+
+/* ARGSUSED */
+void
+zfs_onexit_fd_rele(int fd)
+{
+}
+
+/* ARGSUSED */
+int
+zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data,
+ uint64_t *action_handle)
+{
+ return (0);
+}
+
+/* ARGSUSED */
+int
+zfs_onexit_del_cb(minor_t minor, uint64_t action_handle, boolean_t fire)
+{
+ return (0);
+}
+
+/* ARGSUSED */
+int
+zfs_onexit_cb_data(minor_t minor, uint64_t action_handle, void **data)
+{
+ return (0);
+}
+
+#ifdef __FreeBSD__
+/* ARGSUSED */
+int
+zvol_create_minors(const char *name)
+{
+ return (0);
+}
+#endif
+
+#ifdef illumos
+void
+bioinit(buf_t *bp)
+{
+ bzero(bp, sizeof (buf_t));
+}
+
+void
+biodone(buf_t *bp)
+{
+ if (bp->b_iodone != NULL) {
+ (*(bp->b_iodone))(bp);
+ return;
+ }
+ ASSERT((bp->b_flags & B_DONE) == 0);
+ bp->b_flags |= B_DONE;
+}
+
+void
+bioerror(buf_t *bp, int error)
+{
+ ASSERT(bp != NULL);
+ ASSERT(error >= 0);
+
+ if (error != 0) {
+ bp->b_flags |= B_ERROR;
+ } else {
+ bp->b_flags &= ~B_ERROR;
+ }
+ bp->b_error = error;
+}
+
+
+int
+geterror(struct buf *bp)
+{
+ int error = 0;
+
+ if (bp->b_flags & B_ERROR) {
+ error = bp->b_error;
+ if (!error)
+ error = EIO;
+ }
+ return (error);
+}
+#endif
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
new file mode 100644
index 000000000000..652458ea309c
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
@@ -0,0 +1,838 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_ZFS_CONTEXT_H
+#define _SYS_ZFS_CONTEXT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _SYS_MUTEX_H
+#define _SYS_RWLOCK_H
+#define _SYS_CONDVAR_H
+#define _SYS_SYSTM_H
+#define _SYS_T_LOCK_H
+#define _SYS_VNODE_H
+#define _SYS_VFS_H
+#define _SYS_SUNDDI_H
+#define _SYS_CALLB_H
+#define _SYS_SCHED_H_
+
+#include <solaris.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <thread.h>
+#include <assert.h>
+#include <limits.h>
+#include <dirent.h>
+#include <time.h>
+#include <math.h>
+#include <umem.h>
+#include <inttypes.h>
+#include <fsshare.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <sys/debug.h>
+#include <sys/note.h>
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/atomic.h>
+#include <sys/sysmacros.h>
+#include <sys/bitmap.h>
+#include <sys/resource.h>
+#include <sys/byteorder.h>
+#include <sys/list.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <sys/zfs_debug.h>
+#include <sys/sdt.h>
+#include <sys/kstat.h>
+#include <sys/u8_textprep.h>
+#include <sys/kernel.h>
+#include <sys/disk.h>
+#include <sys/sysevent.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dev.h>
+#include <machine/atomic.h>
+#include <sys/debug.h>
+#ifdef illumos
+#include "zfs.h"
+#endif
+
+#define ZFS_EXPORTS_PATH "/etc/zfs/exports"
+
+/*
+ * Debugging
+ */
+
+/*
+ * Note that we are not using the debugging levels.
+ */
+
+#define CE_CONT 0 /* continuation */
+#define CE_NOTE 1 /* notice */
+#define CE_WARN 2 /* warning */
+#define CE_PANIC 3 /* panic */
+#define CE_IGNORE 4 /* print nothing */
+
+/*
+ * ZFS debugging
+ */
+
+#define ZFS_LOG(...) do { } while (0)
+
+typedef u_longlong_t rlim64_t;
+#define RLIM64_INFINITY ((rlim64_t)-3)
+
+#ifdef ZFS_DEBUG
+extern void dprintf_setup(int *argc, char **argv);
+#endif /* ZFS_DEBUG */
+
+extern void cmn_err(int, const char *, ...);
+extern void vcmn_err(int, const char *, __va_list);
+extern void panic(const char *, ...) __NORETURN;
+extern void vpanic(const char *, __va_list) __NORETURN;
+
+#define fm_panic panic
+
+extern int aok;
+
+/*
+ * DTrace SDT probes have different signatures in userland than they do in
+ * the kernel. If they're being used in kernel code, re-define them out of
+ * existence for their counterparts in libzpool.
+ *
+ * Here's an example of how to use the set-error probes in userland:
+ * zfs$target:::set-error /arg0 == EBUSY/ {stack();}
+ *
+ * Here's an example of how to use DTRACE_PROBE probes in userland:
+ * If there is a probe declared as follows:
+ * DTRACE_PROBE2(zfs__probe_name, uint64_t, blkid, dnode_t *, dn);
+ * Then you can use it as follows:
+ * zfs$target:::probe2 /copyinstr(arg0) == "zfs__probe_name"/
+ * {printf("%u %p\n", arg1, arg2);}
+ */
+
+#ifdef DTRACE_PROBE
+#undef DTRACE_PROBE
+#endif /* DTRACE_PROBE */
+#ifdef illumos
+#define DTRACE_PROBE(a) \
+ ZFS_PROBE0(#a)
+#endif
+
+#ifdef DTRACE_PROBE1
+#undef DTRACE_PROBE1
+#endif /* DTRACE_PROBE1 */
+#ifdef illumos
+#define DTRACE_PROBE1(a, b, c) \
+ ZFS_PROBE1(#a, (unsigned long)c)
+#endif
+
+#ifdef DTRACE_PROBE2
+#undef DTRACE_PROBE2
+#endif /* DTRACE_PROBE2 */
+#ifdef illumos
+#define DTRACE_PROBE2(a, b, c, d, e) \
+ ZFS_PROBE2(#a, (unsigned long)c, (unsigned long)e)
+#endif
+
+#ifdef DTRACE_PROBE3
+#undef DTRACE_PROBE3
+#endif /* DTRACE_PROBE3 */
+#ifdef illumos
+#define DTRACE_PROBE3(a, b, c, d, e, f, g) \
+ ZFS_PROBE3(#a, (unsigned long)c, (unsigned long)e, (unsigned long)g)
+#endif
+
+#ifdef DTRACE_PROBE4
+#undef DTRACE_PROBE4
+#endif /* DTRACE_PROBE4 */
+#ifdef illumos
+#define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) \
+ ZFS_PROBE4(#a, (unsigned long)c, (unsigned long)e, (unsigned long)g, \
+ (unsigned long)i)
+#endif
+
+#ifdef illumos
+/*
+ * We use the comma operator so that this macro can be used without much
+ * additional code. For example, "return (EINVAL);" becomes
+ * "return (SET_ERROR(EINVAL));". Note that the argument will be evaluated
+ * twice, so it should not have side effects (e.g. something like:
+ * "return (SET_ERROR(log_error(EINVAL, info)));" would log the error twice).
+ */
+#define SET_ERROR(err) (ZFS_SET_ERROR(err), err)
+#else /* !illumos */
+
+#define DTRACE_PROBE(a) ((void)0)
+#define DTRACE_PROBE1(a, b, c) ((void)0)
+#define DTRACE_PROBE2(a, b, c, d, e) ((void)0)
+#define DTRACE_PROBE3(a, b, c, d, e, f, g) ((void)0)
+#define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) ((void)0)
+
+#define SET_ERROR(err) (err)
+#endif /* !illumos */
+
+/*
+ * Threads
+ */
+#define curthread ((void *)(uintptr_t)thr_self())
+
+#define kpreempt(x) sched_yield()
+
+typedef struct kthread kthread_t;
+
+#define thread_create(stk, stksize, func, arg, len, pp, state, pri) \
+ zk_thread_create(func, arg)
+#define thread_exit() thr_exit(NULL)
+#define thread_join(t) panic("libzpool cannot join threads")
+
+#define newproc(f, a, cid, pri, ctp, pid) (ENOSYS)
+
+/* in libzpool, p0 exists only to have its address taken */
+struct proc {
+ uintptr_t this_is_never_used_dont_dereference_it;
+};
+
+extern struct proc p0;
+#define curproc (&p0)
+
+#define PS_NONE -1
+
+extern kthread_t *zk_thread_create(void (*func)(void*), void *arg);
+
+#define issig(why) (FALSE)
+#define ISSIG(thr, why) (FALSE)
+
+/*
+ * Mutexes
+ */
+typedef struct kmutex {
+ void *m_owner;
+ boolean_t initialized;
+ mutex_t m_lock;
+} kmutex_t;
+
+#define MUTEX_DEFAULT USYNC_THREAD
+#undef MUTEX_HELD
+#undef MUTEX_NOT_HELD
+#define MUTEX_HELD(m) ((m)->m_owner == curthread)
+#define MUTEX_NOT_HELD(m) (!MUTEX_HELD(m))
+#define _mutex_held(m) pthread_mutex_isowned_np(m)
+
+/*
+ * Argh -- we have to get cheesy here because the kernel and userland
+ * have different signatures for the same routine.
+ */
+//extern int _mutex_init(mutex_t *mp, int type, void *arg);
+//extern int _mutex_destroy(mutex_t *mp);
+//extern int _mutex_owned(mutex_t *mp);
+
+#define mutex_init(mp, b, c, d) zmutex_init((kmutex_t *)(mp))
+#define mutex_destroy(mp) zmutex_destroy((kmutex_t *)(mp))
+#define mutex_owned(mp) zmutex_owned((kmutex_t *)(mp))
+
+extern void zmutex_init(kmutex_t *mp);
+extern void zmutex_destroy(kmutex_t *mp);
+extern int zmutex_owned(kmutex_t *mp);
+extern void mutex_enter(kmutex_t *mp);
+extern void mutex_exit(kmutex_t *mp);
+extern int mutex_tryenter(kmutex_t *mp);
+extern void *mutex_owner(kmutex_t *mp);
+
+/*
+ * RW locks
+ */
+typedef struct krwlock {
+ int rw_count;
+ void *rw_owner;
+ boolean_t initialized;
+ rwlock_t rw_lock;
+} krwlock_t;
+
+typedef int krw_t;
+
+#define RW_READER 0
+#define RW_WRITER 1
+#define RW_DEFAULT USYNC_THREAD
+
+#undef RW_READ_HELD
+#define RW_READ_HELD(x) ((x)->rw_owner == NULL && (x)->rw_count > 0)
+
+#undef RW_WRITE_HELD
+#define RW_WRITE_HELD(x) ((x)->rw_owner == curthread)
+#define RW_LOCK_HELD(x) rw_lock_held(x)
+
+#undef RW_LOCK_HELD
+#define RW_LOCK_HELD(x) (RW_READ_HELD(x) || RW_WRITE_HELD(x))
+
+extern void rw_init(krwlock_t *rwlp, char *name, int type, void *arg);
+extern void rw_destroy(krwlock_t *rwlp);
+extern void rw_enter(krwlock_t *rwlp, krw_t rw);
+extern int rw_tryenter(krwlock_t *rwlp, krw_t rw);
+extern int rw_tryupgrade(krwlock_t *rwlp);
+extern void rw_exit(krwlock_t *rwlp);
+extern int rw_lock_held(krwlock_t *rwlp);
+#define rw_downgrade(rwlp) do { } while (0)
+
+extern uid_t crgetuid(cred_t *cr);
+extern uid_t crgetruid(cred_t *cr);
+extern gid_t crgetgid(cred_t *cr);
+extern int crgetngroups(cred_t *cr);
+extern gid_t *crgetgroups(cred_t *cr);
+
+/*
+ * Condition variables
+ */
+typedef cond_t kcondvar_t;
+
+#define CV_DEFAULT USYNC_THREAD
+#define CALLOUT_FLAG_ABSOLUTE 0x2
+
+extern void cv_init(kcondvar_t *cv, char *name, int type, void *arg);
+extern void cv_destroy(kcondvar_t *cv);
+extern void cv_wait(kcondvar_t *cv, kmutex_t *mp);
+extern int cv_wait_sig(kcondvar_t *cv, kmutex_t *mp);
+extern clock_t cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime);
+#define cv_timedwait_sig(cvp, mp, t) cv_timedwait(cvp, mp, t)
+extern clock_t cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim,
+ hrtime_t res, int flag);
+#define cv_timedwait_sig_hires(cvp, mp, t, r, f) \
+ cv_timedwait_hires(cvp, mp, t, r, f)
+extern void cv_signal(kcondvar_t *cv);
+extern void cv_broadcast(kcondvar_t *cv);
+
+/*
+ * Thread-specific data
+ */
+#define tsd_get(k) pthread_getspecific(k)
+#define tsd_set(k, v) pthread_setspecific(k, v)
+#define tsd_create(kp, d) pthread_key_create(kp, d)
+#define tsd_destroy(kp) /* nothing */
+
+/*
+ * Kernel memory
+ */
+#define KM_SLEEP UMEM_NOFAIL
+#define KM_PUSHPAGE KM_SLEEP
+#define KM_NOSLEEP UMEM_DEFAULT
+#define KM_NORMALPRI 0 /* not needed with UMEM_DEFAULT */
+#define KMC_NODEBUG UMC_NODEBUG
+#define KMC_NOTOUCH 0 /* not needed for userland caches */
+#define KM_NODEBUG 0
+#define kmem_alloc(_s, _f) umem_alloc(_s, _f)
+#define kmem_zalloc(_s, _f) umem_zalloc(_s, _f)
+#define kmem_free(_b, _s) umem_free(_b, _s)
+#define kmem_size() (physmem * PAGESIZE)
+#define kmem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i) \
+ umem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i)
+#define kmem_cache_destroy(_c) umem_cache_destroy(_c)
+#define kmem_cache_alloc(_c, _f) umem_cache_alloc(_c, _f)
+#define kmem_cache_free(_c, _b) umem_cache_free(_c, _b)
+#define kmem_debugging() 0
+#define kmem_cache_reap_active() (B_FALSE)
+#define kmem_cache_reap_soon(_c) /* nothing */
+#define kmem_cache_set_move(_c, _cb) /* nothing */
+#define POINTER_INVALIDATE(_pp) /* nothing */
+#define POINTER_IS_VALID(_p) 0
+
+typedef umem_cache_t kmem_cache_t;
+
+typedef enum kmem_cbrc {
+ KMEM_CBRC_YES,
+ KMEM_CBRC_NO,
+ KMEM_CBRC_LATER,
+ KMEM_CBRC_DONT_NEED,
+ KMEM_CBRC_DONT_KNOW
+} kmem_cbrc_t;
+
+/*
+ * Task queues
+ */
+typedef struct taskq taskq_t;
+typedef uintptr_t taskqid_t;
+typedef void (task_func_t)(void *);
+
+typedef struct taskq_ent {
+ struct taskq_ent *tqent_next;
+ struct taskq_ent *tqent_prev;
+ task_func_t *tqent_func;
+ void *tqent_arg;
+ uintptr_t tqent_flags;
+} taskq_ent_t;
+
+#define TQENT_FLAG_PREALLOC 0x1 /* taskq_dispatch_ent used */
+
+#define TASKQ_PREPOPULATE 0x0001
+#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */
+#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */
+#define TASKQ_THREADS_CPU_PCT 0x0008 /* Scale # threads by # cpus */
+#define TASKQ_DC_BATCH 0x0010 /* Mark threads as batch */
+
+#define TQ_SLEEP KM_SLEEP /* Can block for memory */
+#define TQ_NOSLEEP KM_NOSLEEP /* cannot block for memory; may fail */
+#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
+#define TQ_FRONT 0x08 /* Queue in front */
+
+#define TASKQID_INVALID ((taskqid_t)0)
+
+extern taskq_t *system_taskq;
+
+extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
+#define taskq_create_proc(a, b, c, d, e, p, f) \
+ (taskq_create(a, b, c, d, e, f))
+#define taskq_create_sysdc(a, b, d, e, p, dc, f) \
+ (taskq_create(a, b, maxclsyspri, d, e, f))
+extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
+extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t,
+ taskq_ent_t *);
+extern void taskq_destroy(taskq_t *);
+extern void taskq_wait(taskq_t *);
+extern void taskq_wait_id(taskq_t *, taskqid_t);
+extern int taskq_member(taskq_t *, void *);
+extern void system_taskq_init(void);
+extern void system_taskq_fini(void);
+
+#define taskq_dispatch_safe(tq, func, arg, flags, task) \
+ taskq_dispatch((tq), (func), (arg), (flags))
+
+#define XVA_MAPSIZE 3
+#define XVA_MAGIC 0x78766174
+
+/*
+ * vnodes
+ */
+typedef struct vnode {
+ uint64_t v_size;
+ int v_fd;
+ char *v_path;
+ int v_dump_fd;
+} vnode_t;
+
+extern char *vn_dumpdir;
+#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */
+
+typedef struct xoptattr {
+ timestruc_t xoa_createtime; /* Create time of file */
+ uint8_t xoa_archive;
+ uint8_t xoa_system;
+ uint8_t xoa_readonly;
+ uint8_t xoa_hidden;
+ uint8_t xoa_nounlink;
+ uint8_t xoa_immutable;
+ uint8_t xoa_appendonly;
+ uint8_t xoa_nodump;
+ uint8_t xoa_settable;
+ uint8_t xoa_opaque;
+ uint8_t xoa_av_quarantined;
+ uint8_t xoa_av_modified;
+ uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+ uint8_t xoa_reparse;
+ uint8_t xoa_offline;
+ uint8_t xoa_sparse;
+} xoptattr_t;
+
+typedef struct vattr {
+ uint_t va_mask; /* bit-mask of attributes */
+ u_offset_t va_size; /* file size in bytes */
+} vattr_t;
+
+
+typedef struct xvattr {
+ vattr_t xva_vattr; /* Embedded vattr structure */
+ uint32_t xva_magic; /* Magic Number */
+ uint32_t xva_mapsize; /* Size of attr bitmap (32-bit words) */
+ uint32_t *xva_rtnattrmapp; /* Ptr to xva_rtnattrmap[] */
+ uint32_t xva_reqattrmap[XVA_MAPSIZE]; /* Requested attrs */
+ uint32_t xva_rtnattrmap[XVA_MAPSIZE]; /* Returned attrs */
+ xoptattr_t xva_xoptattrs; /* Optional attributes */
+} xvattr_t;
+
+typedef struct vsecattr {
+ uint_t vsa_mask; /* See below */
+ int vsa_aclcnt; /* ACL entry count */
+ void *vsa_aclentp; /* pointer to ACL entries */
+ int vsa_dfaclcnt; /* default ACL entry count */
+ void *vsa_dfaclentp; /* pointer to default ACL entries */
+ size_t vsa_aclentsz; /* ACE size in bytes of vsa_aclentp */
+} vsecattr_t;
+
+#define AT_TYPE 0x00001
+#define AT_MODE 0x00002
+#define AT_UID 0x00004
+#define AT_GID 0x00008
+#define AT_FSID 0x00010
+#define AT_NODEID 0x00020
+#define AT_NLINK 0x00040
+#define AT_SIZE 0x00080
+#define AT_ATIME 0x00100
+#define AT_MTIME 0x00200
+#define AT_CTIME 0x00400
+#define AT_RDEV 0x00800
+#define AT_BLKSIZE 0x01000
+#define AT_NBLOCKS 0x02000
+#define AT_SEQ 0x08000
+#define AT_XVATTR 0x10000
+
+#define CRCREAT 0
+
+extern int fop_getattr(vnode_t *vp, vattr_t *vap);
+
+#define VOP_CLOSE(vp, f, c, o, cr, ct) 0
+#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct) 0
+#define VOP_GETATTR(vp, vap, cr) fop_getattr((vp), (vap));
+
+#define VOP_FSYNC(vp, f, cr, ct) fsync((vp)->v_fd)
+
+#define VN_RELE(vp) vn_close(vp, 0, NULL, NULL)
+#define VN_RELE_ASYNC(vp, taskq) vn_close(vp, 0, NULL, NULL)
+
+#define vn_lock(vp, type)
+#define VOP_UNLOCK(vp, type)
+
+extern int vn_open(char *path, int x1, int oflags, int mode, vnode_t **vpp,
+ int x2, int x3);
+extern int vn_openat(char *path, int x1, int oflags, int mode, vnode_t **vpp,
+ int x2, int x3, vnode_t *vp, int fd);
+extern int vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len,
+ offset_t offset, int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp);
+extern void vn_close(vnode_t *vp, int openflag, cred_t *cr, kthread_t *td);
+
+#define vn_remove(path, x1, x2) remove(path)
+#define vn_rename(from, to, seg) rename((from), (to))
+#define vn_is_readonly(vp) B_FALSE
+
+extern vnode_t *rootdir;
+
+#include <sys/file.h> /* for FREAD, FWRITE, etc */
+#define FTRUNC O_TRUNC
+
+/*
+ * Random stuff
+ */
+#define ddi_get_lbolt() (gethrtime() >> 23)
+#define ddi_get_lbolt64() (gethrtime() >> 23)
+#define hz 119 /* frequency when using gethrtime() >> 23 for lbolt */
+
+extern void delay(clock_t ticks);
+
+#define SEC_TO_TICK(sec) ((sec) * hz)
+#define NSEC_TO_TICK(nsec) ((nsec) / (NANOSEC / hz))
+
+#define gethrestime_sec() time(NULL)
+#define gethrestime(t) \
+ do {\
+ (t)->tv_sec = gethrestime_sec();\
+ (t)->tv_nsec = 0;\
+ } while (0);
+
+#define max_ncpus 64
+#define boot_ncpus (sysconf(_SC_NPROCESSORS_ONLN))
+
+#define minclsyspri 60
+#define maxclsyspri 99
+
+#define CPU_SEQID (thr_self() & (max_ncpus - 1))
+
+#define kcred NULL
+#define CRED() NULL
+
+#ifndef ptob
+#define ptob(x) ((x) * PAGESIZE)
+#endif
+
+extern uint64_t physmem;
+
+extern int highbit64(uint64_t i);
+extern int random_get_bytes(uint8_t *ptr, size_t len);
+extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);
+
+extern void kernel_init(int);
+extern void kernel_fini(void);
+
+struct spa;
+extern void nicenum(uint64_t num, char *buf, size_t);
+extern void show_pool_stats(struct spa *);
+extern int set_global_var(char *arg);
+
+typedef struct callb_cpr {
+ kmutex_t *cc_lockp;
+} callb_cpr_t;
+
+#define CALLB_CPR_INIT(cp, lockp, func, name) { \
+ (cp)->cc_lockp = lockp; \
+}
+
+#define CALLB_CPR_SAFE_BEGIN(cp) { \
+ ASSERT(MUTEX_HELD((cp)->cc_lockp)); \
+}
+
+#define CALLB_CPR_SAFE_END(cp, lockp) { \
+ ASSERT(MUTEX_HELD((cp)->cc_lockp)); \
+}
+
+#define CALLB_CPR_EXIT(cp) { \
+ ASSERT(MUTEX_HELD((cp)->cc_lockp)); \
+ mutex_exit((cp)->cc_lockp); \
+}
+
+#define zone_dataset_visible(x, y) (1)
+#define INGLOBALZONE(z) (1)
+extern uint32_t zone_get_hostid(void *zonep);
+
+extern char *kmem_asprintf(const char *fmt, ...);
+#define strfree(str) kmem_free((str), strlen(str) + 1)
+
+/*
+ * Hostname information
+ */
+extern struct utsname utsname;
+extern char hw_serial[]; /* for userland-emulated hostid access */
+extern int ddi_strtoul(const char *str, char **nptr, int base,
+ unsigned long *result);
+
+extern int ddi_strtoull(const char *str, char **nptr, int base,
+ u_longlong_t *result);
+
+/* ZFS Boot Related stuff. */
+
+struct _buf {
+ intptr_t _fd;
+};
+
+struct bootstat {
+ uint64_t st_size;
+};
+
+typedef struct ace_object {
+ uid_t a_who;
+ uint32_t a_access_mask;
+ uint16_t a_flags;
+ uint16_t a_type;
+ uint8_t a_obj_type[16];
+ uint8_t a_inherit_obj_type[16];
+} ace_object_t;
+
+
+#define ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05
+#define ACE_ACCESS_DENIED_OBJECT_ACE_TYPE 0x06
+#define ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07
+#define ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08
+
+extern struct _buf *kobj_open_file(char *name);
+extern int kobj_read_file(struct _buf *file, char *buf, unsigned size,
+ unsigned off);
+extern void kobj_close_file(struct _buf *file);
+extern int kobj_get_filesize(struct _buf *file, uint64_t *size);
+extern int zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr);
+extern int zfs_secpolicy_rename_perms(const char *from, const char *to,
+ cred_t *cr);
+extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
+extern zoneid_t getzoneid(void);
+/* Random compatibility stuff. */
+#define pwrite64(d, p, n, o) pwrite(d, p, n, o)
+#define readdir64(d) readdir(d)
+#define SIGPENDING(td) (0)
+#define root_mount_wait() do { } while (0)
+#define root_mounted() (1)
+
+#define noinline __attribute__((noinline))
+#define likely(x) __builtin_expect((x), 1)
+
+struct file {
+ void *dummy;
+};
+
+#define FCREAT O_CREAT
+#define FOFFMAX 0x0
+
+/* SID stuff */
+typedef struct ksiddomain {
+ uint_t kd_ref;
+ uint_t kd_len;
+ char *kd_name;
+} ksiddomain_t;
+
+ksiddomain_t *ksid_lookupdomain(const char *);
+void ksiddomain_rele(ksiddomain_t *);
+
+typedef uint32_t idmap_rid_t;
+
+#define DDI_SLEEP KM_SLEEP
+#define ddi_log_sysevent(_a, _b, _c, _d, _e, _f, _g) (0)
+
+#define SX_SYSINIT(name, lock, desc)
+
+#define SYSCTL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1, \
+ intptr_t arg2, struct sysctl_req *req
+
+/*
+ * This describes the access space for a sysctl request. This is needed
+ * so that we can use the interface from the kernel or from user-space.
+ */
+struct sysctl_req {
+ struct thread *td; /* used for access checking */
+ int lock; /* wiring state */
+ void *oldptr;
+ size_t oldlen;
+ size_t oldidx;
+ int (*oldfunc)(struct sysctl_req *, const void *, size_t);
+ void *newptr;
+ size_t newlen;
+ size_t newidx;
+ int (*newfunc)(struct sysctl_req *, void *, size_t);
+ size_t validlen;
+ int flags;
+};
+
+SLIST_HEAD(sysctl_oid_list, sysctl_oid);
+
+/*
+ * This describes one "oid" in the MIB tree. Potentially more nodes can
+ * be hidden behind it, expanded by the handler.
+ */
+struct sysctl_oid {
+ struct sysctl_oid_list *oid_parent;
+ SLIST_ENTRY(sysctl_oid) oid_link;
+ int oid_number;
+ u_int oid_kind;
+ void *oid_arg1;
+ intptr_t oid_arg2;
+ const char *oid_name;
+ int (*oid_handler)(SYSCTL_HANDLER_ARGS);
+ const char *oid_fmt;
+ int oid_refcnt;
+ u_int oid_running;
+ const char *oid_descr;
+};
+
+#define SYSCTL_DECL(...)
+#define SYSCTL_NODE(...)
+#define SYSCTL_INT(...)
+#define SYSCTL_UINT(...)
+#define SYSCTL_ULONG(...)
+#define SYSCTL_PROC(...)
+#define SYSCTL_QUAD(...)
+#define SYSCTL_UQUAD(...)
+#ifdef TUNABLE_INT
+#undef TUNABLE_INT
+#undef TUNABLE_ULONG
+#undef TUNABLE_QUAD
+#endif
+#define TUNABLE_INT(...)
+#define TUNABLE_ULONG(...)
+#define TUNABLE_QUAD(...)
+
+int sysctl_handle_64(SYSCTL_HANDLER_ARGS);
+
+/* Errors */
+
+#ifndef ERESTART
+#define ERESTART (-1)
+#endif
+
+#ifdef illumos
+/*
+ * Cyclic information
+ */
+extern kmutex_t cpu_lock;
+
+typedef uintptr_t cyclic_id_t;
+typedef uint16_t cyc_level_t;
+typedef void (*cyc_func_t)(void *);
+
+#define CY_LOW_LEVEL 0
+#define CY_INFINITY INT64_MAX
+#define CYCLIC_NONE ((cyclic_id_t)0)
+
+typedef struct cyc_time {
+ hrtime_t cyt_when;
+ hrtime_t cyt_interval;
+} cyc_time_t;
+
+typedef struct cyc_handler {
+ cyc_func_t cyh_func;
+ void *cyh_arg;
+ cyc_level_t cyh_level;
+} cyc_handler_t;
+
+extern cyclic_id_t cyclic_add(cyc_handler_t *, cyc_time_t *);
+extern void cyclic_remove(cyclic_id_t);
+extern int cyclic_reprogram(cyclic_id_t, hrtime_t);
+#endif /* illumos */
+
+#ifdef illumos
+/*
+ * Buf structure
+ */
+#define B_BUSY 0x0001
+#define B_DONE 0x0002
+#define B_ERROR 0x0004
+#define B_READ 0x0040 /* read when I/O occurs */
+#define B_WRITE 0x0100 /* non-read pseudo-flag */
+
+typedef struct buf {
+ int b_flags;
+ size_t b_bcount;
+ union {
+ caddr_t b_addr;
+ } b_un;
+
+ lldaddr_t _b_blkno;
+#define b_lblkno _b_blkno._f
+ size_t b_resid;
+ size_t b_bufsize;
+ int (*b_iodone)(struct buf *);
+ int b_error;
+ void *b_private;
+} buf_t;
+
+extern void bioinit(buf_t *);
+extern void biodone(buf_t *);
+extern void bioerror(buf_t *, int);
+extern int geterror(buf_t *);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZFS_CONTEXT_H */
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c b/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c
new file mode 100644
index 000000000000..595d766e93df
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c
@@ -0,0 +1,353 @@
+/*
+ * 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 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+
+int taskq_now;
+taskq_t *system_taskq;
+
+#define TASKQ_ACTIVE 0x00010000
+#define TASKQ_NAMELEN 31
+
+struct taskq {
+ char tq_name[TASKQ_NAMELEN + 1];
+ kmutex_t tq_lock;
+ krwlock_t tq_threadlock;
+ kcondvar_t tq_dispatch_cv;
+ kcondvar_t tq_wait_cv;
+ thread_t *tq_threadlist;
+ int tq_flags;
+ int tq_active;
+ int tq_nthreads;
+ int tq_nalloc;
+ int tq_minalloc;
+ int tq_maxalloc;
+ kcondvar_t tq_maxalloc_cv;
+ int tq_maxalloc_wait;
+ taskq_ent_t *tq_freelist;
+ taskq_ent_t tq_task;
+};
+
+static taskq_ent_t *
+task_alloc(taskq_t *tq, int tqflags)
+{
+ taskq_ent_t *t;
+ int rv;
+
+again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
+ tq->tq_freelist = t->tqent_next;
+ } else {
+ if (tq->tq_nalloc >= tq->tq_maxalloc) {
+ if (!(tqflags & KM_SLEEP))
+ return (NULL);
+
+ /*
+ * We don't want to exceed tq_maxalloc, but we can't
+ * wait for other tasks to complete (and thus free up
+ * task structures) without risking deadlock with
+ * the caller. So, we just delay for one second
+ * to throttle the allocation rate. If we have tasks
+ * complete before one second timeout expires then
+ * taskq_ent_free will signal us and we will
+ * immediately retry the allocation.
+ */
+ tq->tq_maxalloc_wait++;
+#ifdef __FreeBSD__
+ rv = cv_timedwait(&tq->tq_maxalloc_cv,
+ &tq->tq_lock, hz);
+#else
+ rv = cv_timedwait(&tq->tq_maxalloc_cv,
+ &tq->tq_lock, ddi_get_lbolt() + hz);
+#endif
+ tq->tq_maxalloc_wait--;
+ if (rv > 0)
+ goto again; /* signaled */
+ }
+ mutex_exit(&tq->tq_lock);
+
+ t = kmem_alloc(sizeof (taskq_ent_t), tqflags & KM_SLEEP);
+
+ mutex_enter(&tq->tq_lock);
+ if (t != NULL)
+ tq->tq_nalloc++;
+ }
+ return (t);
+}
+
+static void
+task_free(taskq_t *tq, taskq_ent_t *t)
+{
+ if (tq->tq_nalloc <= tq->tq_minalloc) {
+ t->tqent_next = tq->tq_freelist;
+ tq->tq_freelist = t;
+ } else {
+ tq->tq_nalloc--;
+ mutex_exit(&tq->tq_lock);
+ kmem_free(t, sizeof (taskq_ent_t));
+ mutex_enter(&tq->tq_lock);
+ }
+
+ if (tq->tq_maxalloc_wait)
+ cv_signal(&tq->tq_maxalloc_cv);
+}
+
+taskqid_t
+taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
+{
+ taskq_ent_t *t;
+
+ if (taskq_now) {
+ func(arg);
+ return (1);
+ }
+
+ mutex_enter(&tq->tq_lock);
+ ASSERT(tq->tq_flags & TASKQ_ACTIVE);
+ if ((t = task_alloc(tq, tqflags)) == NULL) {
+ mutex_exit(&tq->tq_lock);
+ return (0);
+ }
+ if (tqflags & TQ_FRONT) {
+ t->tqent_next = tq->tq_task.tqent_next;
+ t->tqent_prev = &tq->tq_task;
+ } else {
+ t->tqent_next = &tq->tq_task;
+ t->tqent_prev = tq->tq_task.tqent_prev;
+ }
+ t->tqent_next->tqent_prev = t;
+ t->tqent_prev->tqent_next = t;
+ t->tqent_func = func;
+ t->tqent_arg = arg;
+ t->tqent_flags = 0;
+ cv_signal(&tq->tq_dispatch_cv);
+ mutex_exit(&tq->tq_lock);
+ return (1);
+}
+
+void
+taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
+ taskq_ent_t *t)
+{
+ ASSERT(func != NULL);
+ ASSERT(!(tq->tq_flags & TASKQ_DYNAMIC));
+
+ /*
+ * Mark it as a prealloc'd task. This is important
+ * to ensure that we don't free it later.
+ */
+ t->tqent_flags |= TQENT_FLAG_PREALLOC;
+ /*
+ * Enqueue the task to the underlying queue.
+ */
+ mutex_enter(&tq->tq_lock);
+
+ if (flags & TQ_FRONT) {
+ t->tqent_next = tq->tq_task.tqent_next;
+ t->tqent_prev = &tq->tq_task;
+ } else {
+ t->tqent_next = &tq->tq_task;
+ t->tqent_prev = tq->tq_task.tqent_prev;
+ }
+ t->tqent_next->tqent_prev = t;
+ t->tqent_prev->tqent_next = t;
+ t->tqent_func = func;
+ t->tqent_arg = arg;
+ cv_signal(&tq->tq_dispatch_cv);
+ mutex_exit(&tq->tq_lock);
+}
+
+void
+taskq_wait(taskq_t *tq)
+{
+ mutex_enter(&tq->tq_lock);
+ while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0)
+ cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
+ mutex_exit(&tq->tq_lock);
+}
+
+void
+taskq_wait_id(taskq_t *tq, taskqid_t id)
+{
+ taskq_wait(tq);
+}
+
+static void *
+taskq_thread(void *arg)
+{
+ taskq_t *tq = arg;
+ taskq_ent_t *t;
+ boolean_t prealloc;
+
+ mutex_enter(&tq->tq_lock);
+ while (tq->tq_flags & TASKQ_ACTIVE) {
+ if ((t = tq->tq_task.tqent_next) == &tq->tq_task) {
+ if (--tq->tq_active == 0)
+ cv_broadcast(&tq->tq_wait_cv);
+ cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
+ tq->tq_active++;
+ continue;
+ }
+ t->tqent_prev->tqent_next = t->tqent_next;
+ t->tqent_next->tqent_prev = t->tqent_prev;
+ t->tqent_next = NULL;
+ t->tqent_prev = NULL;
+ prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC;
+ mutex_exit(&tq->tq_lock);
+
+ rw_enter(&tq->tq_threadlock, RW_READER);
+ t->tqent_func(t->tqent_arg);
+ rw_exit(&tq->tq_threadlock);
+
+ mutex_enter(&tq->tq_lock);
+ if (!prealloc)
+ task_free(tq, t);
+ }
+ tq->tq_nthreads--;
+ cv_broadcast(&tq->tq_wait_cv);
+ mutex_exit(&tq->tq_lock);
+ return (NULL);
+}
+
+/*ARGSUSED*/
+taskq_t *
+taskq_create(const char *name, int nthreads, pri_t pri,
+ int minalloc, int maxalloc, uint_t flags)
+{
+ taskq_t *tq = kmem_zalloc(sizeof (taskq_t), KM_SLEEP);
+ int t;
+
+ if (flags & TASKQ_THREADS_CPU_PCT) {
+ int pct;
+ ASSERT3S(nthreads, >=, 0);
+ ASSERT3S(nthreads, <=, 100);
+ pct = MIN(nthreads, 100);
+ pct = MAX(pct, 0);
+
+ nthreads = (sysconf(_SC_NPROCESSORS_ONLN) * pct) / 100;
+ nthreads = MAX(nthreads, 1); /* need at least 1 thread */
+ } else {
+ ASSERT3S(nthreads, >=, 1);
+ }
+
+ rw_init(&tq->tq_threadlock, NULL, RW_DEFAULT, NULL);
+ mutex_init(&tq->tq_lock, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&tq->tq_dispatch_cv, NULL, CV_DEFAULT, NULL);
+ cv_init(&tq->tq_wait_cv, NULL, CV_DEFAULT, NULL);
+ cv_init(&tq->tq_maxalloc_cv, NULL, CV_DEFAULT, NULL);
+ (void) strncpy(tq->tq_name, name, TASKQ_NAMELEN + 1);
+ tq->tq_flags = flags | TASKQ_ACTIVE;
+ tq->tq_active = nthreads;
+ tq->tq_nthreads = nthreads;
+ tq->tq_minalloc = minalloc;
+ tq->tq_maxalloc = maxalloc;
+ tq->tq_task.tqent_next = &tq->tq_task;
+ tq->tq_task.tqent_prev = &tq->tq_task;
+ tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP);
+
+ if (flags & TASKQ_PREPOPULATE) {
+ mutex_enter(&tq->tq_lock);
+ while (minalloc-- > 0)
+ task_free(tq, task_alloc(tq, KM_SLEEP));
+ mutex_exit(&tq->tq_lock);
+ }
+
+ for (t = 0; t < nthreads; t++)
+ (void) thr_create(0, 0, taskq_thread,
+ tq, THR_BOUND, &tq->tq_threadlist[t]);
+
+ return (tq);
+}
+
+void
+taskq_destroy(taskq_t *tq)
+{
+ int t;
+ int nthreads = tq->tq_nthreads;
+
+ taskq_wait(tq);
+
+ mutex_enter(&tq->tq_lock);
+
+ tq->tq_flags &= ~TASKQ_ACTIVE;
+ cv_broadcast(&tq->tq_dispatch_cv);
+
+ while (tq->tq_nthreads != 0)
+ cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
+
+ tq->tq_minalloc = 0;
+ while (tq->tq_nalloc != 0) {
+ ASSERT(tq->tq_freelist != NULL);
+ task_free(tq, task_alloc(tq, KM_SLEEP));
+ }
+
+ mutex_exit(&tq->tq_lock);
+
+ for (t = 0; t < nthreads; t++)
+ (void) thr_join(tq->tq_threadlist[t], NULL, NULL);
+
+ kmem_free(tq->tq_threadlist, nthreads * sizeof (thread_t));
+
+ rw_destroy(&tq->tq_threadlock);
+ mutex_destroy(&tq->tq_lock);
+ cv_destroy(&tq->tq_dispatch_cv);
+ cv_destroy(&tq->tq_wait_cv);
+ cv_destroy(&tq->tq_maxalloc_cv);
+
+ kmem_free(tq, sizeof (taskq_t));
+}
+
+int
+taskq_member(taskq_t *tq, void *t)
+{
+ int i;
+
+ if (taskq_now)
+ return (1);
+
+ for (i = 0; i < tq->tq_nthreads; i++)
+ if (tq->tq_threadlist[i] == (thread_t)(uintptr_t)t)
+ return (1);
+
+ return (0);
+}
+
+void
+system_taskq_init(void)
+{
+ system_taskq = taskq_create("system_taskq", 64, minclsyspri, 4, 512,
+ TASKQ_DYNAMIC | TASKQ_PREPOPULATE);
+}
+
+void
+system_taskq_fini(void)
+{
+ taskq_destroy(system_taskq);
+ system_taskq = NULL; /* defensive */
+}
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/util.c b/cddl/contrib/opensolaris/lib/libzpool/common/util.c
new file mode 100644
index 000000000000..d2ed31a46832
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/util.c
@@ -0,0 +1,196 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2017, Intel Corporation.
+ */
+
+#include <assert.h>
+#include <sys/zfs_context.h>
+#include <sys/avl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/spa.h>
+#include <sys/fs/zfs.h>
+#include <sys/refcount.h>
+#include <dlfcn.h>
+
+/*
+ * Routines needed by more than one client of libzpool.
+ */
+
+static void
+show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent)
+{
+ vdev_stat_t *vs;
+ vdev_stat_t v0 = { 0 };
+ uint64_t sec;
+ uint64_t is_log = 0;
+ nvlist_t **child;
+ uint_t c, children;
+ char used[6], avail[6];
+ char rops[6], wops[6], rbytes[6], wbytes[6], rerr[6], werr[6], cerr[6];
+
+ if (indent == 0 && desc != NULL) {
+ (void) printf(" "
+ " capacity operations bandwidth ---- errors ----\n");
+ (void) printf("description "
+ "used avail read write read write read write cksum\n");
+ }
+
+ if (desc != NULL) {
+ char *suffix = "", *bias = NULL;
+ char bias_suffix[32];
+
+ (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &is_log);
+ (void) nvlist_lookup_string(nv, ZPOOL_CONFIG_ALLOCATION_BIAS,
+ &bias);
+ if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &c) != 0)
+ vs = &v0;
+
+ if (bias != NULL) {
+ (void) snprintf(bias_suffix, sizeof (bias_suffix),
+ " (%s)", bias);
+ suffix = bias_suffix;
+ } else if (is_log) {
+ suffix = " (log)";
+ }
+
+ sec = MAX(1, vs->vs_timestamp / NANOSEC);
+
+ nicenum(vs->vs_alloc, used, sizeof (used));
+ nicenum(vs->vs_space - vs->vs_alloc, avail, sizeof (avail));
+ nicenum(vs->vs_ops[ZIO_TYPE_READ] / sec, rops, sizeof (rops));
+ nicenum(vs->vs_ops[ZIO_TYPE_WRITE] / sec, wops, sizeof (wops));
+ nicenum(vs->vs_bytes[ZIO_TYPE_READ] / sec, rbytes,
+ sizeof (rbytes));
+ nicenum(vs->vs_bytes[ZIO_TYPE_WRITE] / sec, wbytes,
+ sizeof (wbytes));
+ nicenum(vs->vs_read_errors, rerr, sizeof (rerr));
+ nicenum(vs->vs_write_errors, werr, sizeof (werr));
+ nicenum(vs->vs_checksum_errors, cerr, sizeof (cerr));
+
+ (void) printf("%*s%s%*s%*s%*s %5s %5s %5s %5s %5s %5s %5s\n",
+ indent, "",
+ desc,
+ (int)(indent+strlen(desc)-25-(vs->vs_space ? 0 : 12)),
+ suffix,
+ vs->vs_space ? 6 : 0, vs->vs_space ? used : "",
+ vs->vs_space ? 6 : 0, vs->vs_space ? avail : "",
+ rops, wops, rbytes, wbytes, rerr, werr, cerr);
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ctype, &child, &children) != 0)
+ return;
+
+ for (c = 0; c < children; c++) {
+ nvlist_t *cnv = child[c];
+ char *cname, *tname;
+ uint64_t np;
+ if (nvlist_lookup_string(cnv, ZPOOL_CONFIG_PATH, &cname) &&
+ nvlist_lookup_string(cnv, ZPOOL_CONFIG_TYPE, &cname))
+ cname = "<unknown>";
+ tname = calloc(1, strlen(cname) + 2);
+ (void) strcpy(tname, cname);
+ if (nvlist_lookup_uint64(cnv, ZPOOL_CONFIG_NPARITY, &np) == 0)
+ tname[strlen(tname)] = '0' + np;
+ show_vdev_stats(tname, ctype, cnv, indent + 2);
+ free(tname);
+ }
+}
+
+void
+show_pool_stats(spa_t *spa)
+{
+ nvlist_t *config, *nvroot;
+ char *name;
+
+ VERIFY(spa_get_stats(spa_name(spa), &config, NULL, 0) == 0);
+
+ VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ VERIFY(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+ &name) == 0);
+
+ show_vdev_stats(name, ZPOOL_CONFIG_CHILDREN, nvroot, 0);
+ show_vdev_stats(NULL, ZPOOL_CONFIG_L2CACHE, nvroot, 0);
+ show_vdev_stats(NULL, ZPOOL_CONFIG_SPARES, nvroot, 0);
+
+ nvlist_free(config);
+}
+
+/*
+ * Sets given global variable in libzpool to given unsigned 32-bit value.
+ * arg: "<variable>=<value>"
+ */
+int
+set_global_var(char *arg)
+{
+ void *zpoolhdl;
+ char *varname = arg, *varval;
+ u_longlong_t val;
+
+#ifndef _LITTLE_ENDIAN
+ /*
+ * On big endian systems changing a 64-bit variable would set the high
+ * 32 bits instead of the low 32 bits, which could cause unexpected
+ * results.
+ */
+ fprintf(stderr, "Setting global variables is only supported on "
+ "little-endian systems\n", varname);
+ return (ENOTSUP);
+#endif
+ if ((varval = strchr(arg, '=')) != NULL) {
+ *varval = '\0';
+ varval++;
+ val = strtoull(varval, NULL, 0);
+ if (val > UINT32_MAX) {
+ fprintf(stderr, "Value for global variable '%s' must "
+ "be a 32-bit unsigned integer\n", varname);
+ return (EOVERFLOW);
+ }
+ } else {
+ return (EINVAL);
+ }
+
+ zpoolhdl = dlopen("libzpool.so", RTLD_LAZY);
+ if (zpoolhdl != NULL) {
+ uint32_t *var;
+ var = dlsym(zpoolhdl, varname);
+ if (var == NULL) {
+ fprintf(stderr, "Global variable '%s' does not exist "
+ "in libzpool.so\n", varname);
+ return (EINVAL);
+ }
+ *var = (uint32_t)val;
+
+ dlclose(zpoolhdl);
+ } else {
+ fprintf(stderr, "Failed to open libzpool.so to set global "
+ "variable\n");
+ return (EIO);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/zfs.d b/cddl/contrib/opensolaris/lib/libzpool/common/zfs.d
new file mode 100644
index 000000000000..1351733c807b
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/zfs.d
@@ -0,0 +1,36 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+provider zfs {
+ probe probe0(char *probename);
+ probe probe1(char *probename, unsigned long arg1);
+ probe probe2(char *probename, unsigned long arg1, unsigned long arg2);
+ probe probe3(char *probename, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3);
+ probe probe4(char *probename, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4);
+
+ probe set__error(int err);
+};
+
+#pragma D attributes Evolving/Evolving/ISA provider zfs provider
+#pragma D attributes Private/Private/Unknown provider zfs module
+#pragma D attributes Private/Private/Unknown provider zfs function
+#pragma D attributes Evolving/Evolving/ISA provider zfs name
+#pragma D attributes Evolving/Evolving/ISA provider zfs args
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/__init__.py b/cddl/contrib/opensolaris/lib/pyzfs/common/__init__.py
new file mode 100644
index 000000000000..76b0998a3e7e
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/__init__.py
@@ -0,0 +1,27 @@
+#! /usr/bin/python2.6
+#
+# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+"""
+package which provides an administrative interface to ZFS
+"""
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py b/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py
new file mode 100644
index 000000000000..7ad4b49cc374
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py
@@ -0,0 +1,398 @@
+#! /usr/bin/python2.6
+#
+# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+"""This module implements the "zfs allow" and "zfs unallow" subcommands.
+The only public interface is the zfs.allow.do_allow() function."""
+
+import zfs.util
+import zfs.dataset
+import optparse
+import sys
+import pwd
+import grp
+import errno
+
+_ = zfs.util._
+
+class FSPerms(object):
+ """This class represents all the permissions that are set on a
+ particular filesystem (not including those inherited)."""
+
+ __slots__ = "create", "sets", "local", "descend", "ld"
+ __repr__ = zfs.util.default_repr
+
+ def __init__(self, raw):
+ """Create a FSPerms based on the dict of raw permissions
+ from zfs.ioctl.get_fsacl()."""
+ # set of perms
+ self.create = set()
+
+ # below are { "Ntype name": set(perms) }
+ # where N is a number that we just use for sorting,
+ # type is "user", "group", "everyone", or "" (for sets)
+ # name is a user, group, or set name, or "" (for everyone)
+ self.sets = dict()
+ self.local = dict()
+ self.descend = dict()
+ self.ld = dict()
+
+ # see the comment in dsl_deleg.c for the definition of whokey
+ for whokey in raw.keys():
+ perms = raw[whokey].keys()
+ whotypechr = whokey[0].lower()
+ ws = whokey[3:]
+ if whotypechr == "c":
+ self.create.update(perms)
+ elif whotypechr == "s":
+ nwho = "1" + ws
+ self.sets.setdefault(nwho, set()).update(perms)
+ else:
+ if whotypechr == "u":
+ try:
+ name = pwd.getpwuid(int(ws)).pw_name
+ except KeyError:
+ name = ws
+ nwho = "1user " + name
+ elif whotypechr == "g":
+ try:
+ name = grp.getgrgid(int(ws)).gr_name
+ except KeyError:
+ name = ws
+ nwho = "2group " + name
+ elif whotypechr == "e":
+ nwho = "3everyone"
+ else:
+ raise ValueError(whotypechr)
+
+ if whokey[1] == "l":
+ d = self.local
+ elif whokey[1] == "d":
+ d = self.descend
+ else:
+ raise ValueError(whokey[1])
+
+ d.setdefault(nwho, set()).update(perms)
+
+ # Find perms that are in both local and descend, and
+ # move them to ld.
+ for nwho in self.local:
+ if nwho not in self.descend:
+ continue
+ # note: these are set operations
+ self.ld[nwho] = self.local[nwho] & self.descend[nwho]
+ self.local[nwho] -= self.ld[nwho]
+ self.descend[nwho] -= self.ld[nwho]
+
+ @staticmethod
+ def __ldstr(d, header):
+ s = ""
+ for (nwho, perms) in sorted(d.items()):
+ # local and descend may have entries where perms
+ # is an empty set, due to consolidating all
+ # permissions into ld
+ if perms:
+ s += "\t%s %s\n" % \
+ (nwho[1:], ",".join(sorted(perms)))
+ if s:
+ s = header + s
+ return s
+
+ def __str__(self):
+ s = self.__ldstr(self.sets, _("Permission sets:\n"))
+
+ if self.create:
+ s += _("Create time permissions:\n")
+ s += "\t%s\n" % ",".join(sorted(self.create))
+
+ s += self.__ldstr(self.local, _("Local permissions:\n"))
+ s += self.__ldstr(self.descend, _("Descendent permissions:\n"))
+ s += self.__ldstr(self.ld, _("Local+Descendent permissions:\n"))
+ return s.rstrip()
+
+def args_to_perms(parser, options, who, perms):
+ """Return a dict of raw perms {"whostr" -> {"perm" -> None}}
+ based on the command-line input."""
+
+ # perms is not set if we are doing a "zfs unallow <who> <fs>" to
+ # remove all of someone's permissions
+ if perms:
+ setperms = dict(((p, None) for p in perms if p[0] == "@"))
+ baseperms = dict(((canonicalized_perm(p), None)
+ for p in perms if p[0] != "@"))
+ else:
+ setperms = None
+ baseperms = None
+
+ d = dict()
+
+ def storeperm(typechr, inheritchr, arg):
+ assert typechr in "ugecs"
+ assert inheritchr in "ld-"
+
+ def mkwhokey(t):
+ return "%c%c$%s" % (t, inheritchr, arg)
+
+ if baseperms or not perms:
+ d[mkwhokey(typechr)] = baseperms
+ if setperms or not perms:
+ d[mkwhokey(typechr.upper())] = setperms
+
+ def decodeid(w, toidfunc, fmt):
+ try:
+ return int(w)
+ except ValueError:
+ try:
+ return toidfunc(w)[2]
+ except KeyError:
+ parser.error(fmt % w)
+
+ if options.set:
+ storeperm("s", "-", who)
+ elif options.create:
+ storeperm("c", "-", "")
+ else:
+ for w in who:
+ if options.user:
+ id = decodeid(w, pwd.getpwnam,
+ _("invalid user %s"))
+ typechr = "u"
+ elif options.group:
+ id = decodeid(w, grp.getgrnam,
+ _("invalid group %s"))
+ typechr = "g"
+ elif w == "everyone":
+ id = ""
+ typechr = "e"
+ else:
+ try:
+ id = pwd.getpwnam(w)[2]
+ typechr = "u"
+ except KeyError:
+ try:
+ id = grp.getgrnam(w)[2]
+ typechr = "g"
+ except KeyError:
+ parser.error(_("invalid user/group %s") % w)
+ if options.local:
+ storeperm(typechr, "l", id)
+ if options.descend:
+ storeperm(typechr, "d", id)
+ return d
+
+perms_subcmd = dict(
+ create=_("Must also have the 'mount' ability"),
+ destroy=_("Must also have the 'mount' ability"),
+ snapshot="",
+ rollback="",
+ clone=_("""Must also have the 'create' ability and 'mount'
+\t\t\t\tability in the origin file system"""),
+ promote=_("""Must also have the 'mount'
+\t\t\t\tand 'promote' ability in the origin file system"""),
+ rename=_("""Must also have the 'mount' and 'create'
+\t\t\t\tability in the new parent"""),
+ receive=_("Must also have the 'mount' and 'create' ability"),
+ allow=_("Must also have the permission that is being\n\t\t\t\tallowed"),
+ mount=_("Allows mount/umount of ZFS datasets"),
+ share=_("Allows sharing file systems over NFS or SMB\n\t\t\t\tprotocols"),
+ send="",
+ hold=_("Allows adding a user hold to a snapshot"),
+ release=_("Allows releasing a user hold which\n\t\t\t\tmight destroy the snapshot"),
+ diff=_("Allows lookup of paths within a dataset,\n\t\t\t\tgiven an object number. Ordinary users need this\n\t\t\t\tin order to use zfs diff"),
+ bookmark="",
+)
+
+perms_other = dict(
+ userprop=_("Allows changing any user property"),
+ userquota=_("Allows accessing any userquota@... property"),
+ groupquota=_("Allows accessing any groupquota@... property"),
+ userused=_("Allows reading any userused@... property"),
+ groupused=_("Allows reading any groupused@... property"),
+)
+
+def hasset(ds, setname):
+ """Return True if the given setname (string) is defined for this
+ ds (Dataset)."""
+ # It would be nice to cache the result of get_fsacl().
+ for raw in ds.get_fsacl().values():
+ for whokey in raw.keys():
+ if whokey[0].lower() == "s" and whokey[3:] == setname:
+ return True
+ return False
+
+def canonicalized_perm(permname):
+ """Return the canonical name (string) for this permission (string).
+ Raises ZFSError if it is not a valid permission."""
+ if permname in perms_subcmd.keys() or permname in perms_other.keys():
+ return permname
+ try:
+ return zfs.dataset.getpropobj(permname).name
+ except KeyError:
+ raise zfs.util.ZFSError(errno.EINVAL, permname,
+ _("invalid permission"))
+
+def print_perms():
+ """Print the set of supported permissions."""
+ print(_("\nThe following permissions are supported:\n"))
+ fmt = "%-16s %-14s\t%s"
+ print(fmt % (_("NAME"), _("TYPE"), _("NOTES")))
+
+ for (name, note) in sorted(perms_subcmd.iteritems()):
+ print(fmt % (name, _("subcommand"), note))
+
+ for (name, note) in sorted(perms_other.iteritems()):
+ print(fmt % (name, _("other"), note))
+
+ for (name, prop) in sorted(zfs.dataset.proptable.iteritems()):
+ if prop.visible and prop.delegatable():
+ print(fmt % (name, _("property"), ""))
+
+def do_allow():
+ """Implements the "zfs allow" and "zfs unallow" subcommands."""
+ un = (sys.argv[1] == "unallow")
+
+ def usage(msg=None):
+ parser.print_help()
+ print_perms()
+ if msg:
+ print
+ parser.exit("zfs: error: " + msg)
+ else:
+ parser.exit()
+
+ if un:
+ u = _("""unallow [-rldug] <"everyone"|user|group>[,...]
+ [<perm|@setname>[,...]] <filesystem|volume>
+ unallow [-rld] -e [<perm|@setname>[,...]] <filesystem|volume>
+ unallow [-r] -c [<perm|@setname>[,...]] <filesystem|volume>
+ unallow [-r] -s @setname [<perm|@setname>[,...]] <filesystem|volume>""")
+ verb = _("remove")
+ sstr = _("undefine permission set")
+ else:
+ u = _("""allow <filesystem|volume>
+ allow [-ldug] <"everyone"|user|group>[,...] <perm|@setname>[,...]
+ <filesystem|volume>
+ allow [-ld] -e <perm|@setname>[,...] <filesystem|volume>
+ allow -c <perm|@setname>[,...] <filesystem|volume>
+ allow -s @setname <perm|@setname>[,...] <filesystem|volume>""")
+ verb = _("set")
+ sstr = _("define permission set")
+
+ parser = optparse.OptionParser(usage=u, prog="zfs")
+
+ parser.add_option("-l", action="store_true", dest="local",
+ help=_("%s permission locally") % verb)
+ parser.add_option("-d", action="store_true", dest="descend",
+ help=_("%s permission for descendents") % verb)
+ parser.add_option("-u", action="store_true", dest="user",
+ help=_("%s permission for user") % verb)
+ parser.add_option("-g", action="store_true", dest="group",
+ help=_("%s permission for group") % verb)
+ parser.add_option("-e", action="store_true", dest="everyone",
+ help=_("%s permission for everyone") % verb)
+ parser.add_option("-c", action="store_true", dest="create",
+ help=_("%s create time permissions") % verb)
+ parser.add_option("-s", action="store_true", dest="set", help=sstr)
+ if un:
+ parser.add_option("-r", action="store_true", dest="recursive",
+ help=_("remove permissions recursively"))
+
+ if len(sys.argv) == 3 and not un:
+ # just print the permissions on this fs
+
+ if sys.argv[2] == "-h":
+ # hack to make "zfs allow -h" work
+ usage()
+ ds = zfs.dataset.Dataset(sys.argv[2], snaps=False)
+
+ p = dict()
+ for (fs, raw) in ds.get_fsacl().items():
+ p[fs] = FSPerms(raw)
+
+ for fs in sorted(p.keys(), reverse=True):
+ s = _("---- Permissions on %s ") % fs
+ print(s + "-" * (70-len(s)))
+ print(p[fs])
+ return
+
+
+ (options, args) = parser.parse_args(sys.argv[2:])
+
+ if sum((bool(options.everyone), bool(options.user),
+ bool(options.group))) > 1:
+ parser.error(_("-u, -g, and -e are mutually exclusive"))
+
+ def mungeargs(expected_len):
+ if un and len(args) == expected_len-1:
+ return (None, args[expected_len-2])
+ elif len(args) == expected_len:
+ return (args[expected_len-2].split(","),
+ args[expected_len-1])
+ else:
+ usage(_("wrong number of parameters"))
+
+ if options.set:
+ if options.local or options.descend or options.user or \
+ options.group or options.everyone or options.create:
+ parser.error(_("invalid option combined with -s"))
+ if args[0][0] != "@":
+ parser.error(_("invalid set name: missing '@' prefix"))
+
+ (perms, fsname) = mungeargs(3)
+ who = args[0]
+ elif options.create:
+ if options.local or options.descend or options.user or \
+ options.group or options.everyone or options.set:
+ parser.error(_("invalid option combined with -c"))
+
+ (perms, fsname) = mungeargs(2)
+ who = None
+ elif options.everyone:
+ if options.user or options.group or \
+ options.create or options.set:
+ parser.error(_("invalid option combined with -e"))
+
+ (perms, fsname) = mungeargs(2)
+ who = ["everyone"]
+ else:
+ (perms, fsname) = mungeargs(3)
+ who = args[0].split(",")
+
+ if not options.local and not options.descend:
+ options.local = True
+ options.descend = True
+
+ d = args_to_perms(parser, options, who, perms)
+
+ ds = zfs.dataset.Dataset(fsname, snaps=False)
+
+ if not un and perms:
+ for p in perms:
+ if p[0] == "@" and not hasset(ds, p):
+ parser.error(_("set %s is not defined") % p)
+
+ ds.set_fsacl(un, d)
+ if un and options.recursive:
+ for child in ds.descendents():
+ child.set_fsacl(un, d)
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/dataset.py b/cddl/contrib/opensolaris/lib/pyzfs/common/dataset.py
new file mode 100644
index 000000000000..26192e4075d2
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/dataset.py
@@ -0,0 +1,234 @@
+#! /usr/bin/python2.6
+#
+# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+"""Implements the Dataset class, providing methods for manipulating ZFS
+datasets. Also implements the Property class, which describes ZFS
+properties."""
+
+import zfs.ioctl
+import zfs.util
+import errno
+
+_ = zfs.util._
+
+class Property(object):
+ """This class represents a ZFS property. It contains
+ information about the property -- if it's readonly, a number vs
+ string vs index, etc. Only native properties are represented by
+ this class -- not user properties (eg "user:prop") or userspace
+ properties (eg "userquota@joe")."""
+
+ __slots__ = "name", "number", "type", "default", "attr", "validtypes", \
+ "values", "colname", "rightalign", "visible", "indextable"
+ __repr__ = zfs.util.default_repr
+
+ def __init__(self, t):
+ """t is the tuple of information about this property
+ from zfs.ioctl.get_proptable, which should match the
+ members of zprop_desc_t (see zfs_prop.h)."""
+
+ self.name = t[0]
+ self.number = t[1]
+ self.type = t[2]
+ if self.type == "string":
+ self.default = t[3]
+ else:
+ self.default = t[4]
+ self.attr = t[5]
+ self.validtypes = t[6]
+ self.values = t[7]
+ self.colname = t[8]
+ self.rightalign = t[9]
+ self.visible = t[10]
+ self.indextable = t[11]
+
+ def delegatable(self):
+ """Return True if this property can be delegated with
+ "zfs allow"."""
+ return self.attr != "readonly"
+
+proptable = dict()
+for name, t in zfs.ioctl.get_proptable().iteritems():
+ proptable[name] = Property(t)
+del name, t
+
+def getpropobj(name):
+ """Return the Property object that is identified by the given
+ name string. It can be the full name, or the column name."""
+ try:
+ return proptable[name]
+ except KeyError:
+ for p in proptable.itervalues():
+ if p.colname and p.colname.lower() == name:
+ return p
+ raise
+
+class Dataset(object):
+ """Represents a ZFS dataset (filesystem, snapshot, zvol, clone, etc).
+
+ Generally, this class provides interfaces to the C functions in
+ zfs.ioctl which actually interface with the kernel to manipulate
+ datasets.
+
+ Unless otherwise noted, any method can raise a ZFSError to
+ indicate failure."""
+
+ __slots__ = "name", "__props"
+ __repr__ = zfs.util.default_repr
+
+ def __init__(self, name, props=None,
+ types=("filesystem", "volume"), snaps=True):
+ """Open the named dataset, checking that it exists and
+ is of the specified type.
+
+ name is the string name of this dataset.
+
+ props is the property settings dict from zfs.ioctl.next_dataset.
+
+ types is an iterable of strings specifying which types
+ of datasets are permitted. Accepted strings are
+ "filesystem" and "volume". Defaults to accepting all
+ types.
+
+ snaps is a boolean specifying if snapshots are acceptable.
+
+ Raises a ZFSError if the dataset can't be accessed (eg
+ doesn't exist) or is not of the specified type.
+ """
+
+ self.name = name
+
+ e = zfs.util.ZFSError(errno.EINVAL,
+ _("cannot open %s") % name,
+ _("operation not applicable to datasets of this type"))
+ if "@" in name and not snaps:
+ raise e
+ if not props:
+ props = zfs.ioctl.dataset_props(name)
+ self.__props = props
+ if "volume" not in types and self.getprop("type") == 3:
+ raise e
+ if "filesystem" not in types and self.getprop("type") == 2:
+ raise e
+
+ def getprop(self, propname):
+ """Return the value of the given property for this dataset.
+
+ Currently only works for native properties (those with a
+ Property object.)
+
+ Raises KeyError if propname does not specify a native property.
+ Does not raise ZFSError.
+ """
+
+ p = getpropobj(propname)
+ try:
+ return self.__props[p.name]["value"]
+ except KeyError:
+ return p.default
+
+ def parent(self):
+ """Return a Dataset representing the parent of this one."""
+ return Dataset(self.name[:self.name.rindex("/")])
+
+ def descendents(self):
+ """A generator function which iterates over all
+ descendent Datasets (not including snapshots."""
+
+ cookie = 0
+ while True:
+ # next_dataset raises StopIteration when done
+ (name, cookie, props) = \
+ zfs.ioctl.next_dataset(self.name, False, cookie)
+ ds = Dataset(name, props)
+ yield ds
+ for child in ds.descendents():
+ yield child
+
+ def userspace(self, prop):
+ """A generator function which iterates over a
+ userspace-type property.
+
+ prop specifies which property ("userused@",
+ "userquota@", "groupused@", or "groupquota@").
+
+ returns 3-tuple of domain (string), rid (int), and space (int).
+ """
+
+ d = zfs.ioctl.userspace_many(self.name, prop)
+ for ((domain, rid), space) in d.iteritems():
+ yield (domain, rid, space)
+
+ def userspace_upgrade(self):
+ """Initialize the accounting information for
+ userused@... and groupused@... properties."""
+ return zfs.ioctl.userspace_upgrade(self.name)
+
+ def set_fsacl(self, un, d):
+ """Add to the "zfs allow"-ed permissions on this Dataset.
+
+ un is True if the specified permissions should be removed.
+
+ d is a dict specifying which permissions to add/remove:
+ { "whostr" -> None # remove all perms for this entity
+ "whostr" -> { "perm" -> None} # add/remove these perms
+ } """
+ return zfs.ioctl.set_fsacl(self.name, un, d)
+
+ def get_fsacl(self):
+ """Get the "zfs allow"-ed permissions on the Dataset.
+
+ Return a dict("whostr": { "perm" -> None })."""
+
+ return zfs.ioctl.get_fsacl(self.name)
+
+ def get_holds(self):
+ """Get the user holds on this Dataset.
+
+ Return a dict("tag": timestamp)."""
+
+ return zfs.ioctl.get_holds(self.name)
+
+def snapshots_fromcmdline(dsnames, recursive):
+ for dsname in dsnames:
+ if not "@" in dsname:
+ raise zfs.util.ZFSError(errno.EINVAL,
+ _("cannot open %s") % dsname,
+ _("operation only applies to snapshots"))
+ try:
+ ds = Dataset(dsname)
+ yield ds
+ except zfs.util.ZFSError, e:
+ if not recursive or e.errno != errno.ENOENT:
+ raise
+ if recursive:
+ (base, snapname) = dsname.split('@')
+ parent = Dataset(base)
+ for child in parent.descendents():
+ try:
+ yield Dataset(child.name + "@" +
+ snapname)
+ except zfs.util.ZFSError, e:
+ if e.errno != errno.ENOENT:
+ raise
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/groupspace.py b/cddl/contrib/opensolaris/lib/pyzfs/common/groupspace.py
new file mode 100644
index 000000000000..9f380fdb89f1
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/groupspace.py
@@ -0,0 +1,28 @@
+#! /usr/bin/python2.6
+#
+# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import zfs.userspace
+
+do_groupspace = zfs.userspace.do_userspace
+
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/holds.py b/cddl/contrib/opensolaris/lib/pyzfs/common/holds.py
new file mode 100644
index 000000000000..800e28f974dd
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/holds.py
@@ -0,0 +1,75 @@
+#! /usr/bin/python2.6
+#
+# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+"""This module implements the "zfs holds" subcommand.
+The only public interface is the zfs.holds.do_holds() function."""
+
+import optparse
+import sys
+import errno
+import time
+import zfs.util
+import zfs.dataset
+import zfs.table
+
+_ = zfs.util._
+
+def do_holds():
+ """Implements the "zfs holds" subcommand."""
+ def usage(msg=None):
+ parser.print_help()
+ if msg:
+ print
+ parser.exit("zfs: error: " + msg)
+ else:
+ parser.exit()
+
+ u = _("""holds [-r] <snapshot> ...""")
+
+ parser = optparse.OptionParser(usage=u, prog="zfs")
+
+ parser.add_option("-r", action="store_true", dest="recursive",
+ help=_("list holds recursively"))
+
+ (options, args) = parser.parse_args(sys.argv[2:])
+
+ if len(args) < 1:
+ usage(_("missing snapshot argument"))
+
+ fields = ("name", "tag", "timestamp")
+ rjustfields = ()
+ printing = False
+ gotone = False
+ t = zfs.table.Table(fields, rjustfields)
+ for ds in zfs.dataset.snapshots_fromcmdline(args, options.recursive):
+ gotone = True
+ for tag, tm in ds.get_holds().iteritems():
+ val = {"name": ds.name, "tag": tag,
+ "timestamp": time.ctime(tm)}
+ t.addline(ds.name, val)
+ printing = True
+ if printing:
+ t.printme()
+ elif not gotone:
+ raise zfs.util.ZFSError(errno.ENOENT, _("no matching datasets"))
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c b/cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c
new file mode 100644
index 000000000000..d1f82a7dc888
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c
@@ -0,0 +1,544 @@
+/*
+ * 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 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <Python.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/fs/zfs.h>
+#include <strings.h>
+#include <unistd.h>
+#include <libnvpair.h>
+#include <libintl.h>
+#include <libzfs.h>
+#include <libzfs_impl.h>
+#include "zfs_prop.h"
+
+static PyObject *ZFSError;
+static int zfsdevfd;
+
+#ifdef __lint
+#define dgettext(x, y) y
+#endif
+
+#define _(s) dgettext(TEXT_DOMAIN, s)
+
+/*PRINTFLIKE1*/
+static void
+seterr(char *fmt, ...)
+{
+ char errstr[1024];
+ va_list v;
+
+ va_start(v, fmt);
+ (void) vsnprintf(errstr, sizeof (errstr), fmt, v);
+ va_end(v);
+
+ PyErr_SetObject(ZFSError, Py_BuildValue("is", errno, errstr));
+}
+
+static char cmdstr[HIS_MAX_RECORD_LEN];
+
+static int
+ioctl_with_cmdstr(int ioc, zfs_cmd_t *zc)
+{
+ int err;
+
+ if (cmdstr[0])
+ zc->zc_history = (uint64_t)(uintptr_t)cmdstr;
+ err = ioctl(zfsdevfd, ioc, zc);
+ cmdstr[0] = '\0';
+ return (err);
+}
+
+static PyObject *
+nvl2py(nvlist_t *nvl)
+{
+ PyObject *pyo;
+ nvpair_t *nvp;
+
+ pyo = PyDict_New();
+
+ for (nvp = nvlist_next_nvpair(nvl, NULL); nvp;
+ nvp = nvlist_next_nvpair(nvl, nvp)) {
+ PyObject *pyval;
+ char *sval;
+ uint64_t ival;
+ boolean_t bval;
+ nvlist_t *nval;
+
+ switch (nvpair_type(nvp)) {
+ case DATA_TYPE_STRING:
+ (void) nvpair_value_string(nvp, &sval);
+ pyval = Py_BuildValue("s", sval);
+ break;
+
+ case DATA_TYPE_UINT64:
+ (void) nvpair_value_uint64(nvp, &ival);
+ pyval = Py_BuildValue("K", ival);
+ break;
+
+ case DATA_TYPE_NVLIST:
+ (void) nvpair_value_nvlist(nvp, &nval);
+ pyval = nvl2py(nval);
+ break;
+
+ case DATA_TYPE_BOOLEAN:
+ Py_INCREF(Py_None);
+ pyval = Py_None;
+ break;
+
+ case DATA_TYPE_BOOLEAN_VALUE:
+ (void) nvpair_value_boolean_value(nvp, &bval);
+ pyval = Py_BuildValue("i", bval);
+ break;
+
+ default:
+ PyErr_SetNone(PyExc_ValueError);
+ Py_DECREF(pyo);
+ return (NULL);
+ }
+
+ PyDict_SetItemString(pyo, nvpair_name(nvp), pyval);
+ Py_DECREF(pyval);
+ }
+
+ return (pyo);
+}
+
+static nvlist_t *
+dict2nvl(PyObject *d)
+{
+ nvlist_t *nvl;
+ int err;
+ PyObject *key, *value;
+ int pos = 0;
+
+ if (!PyDict_Check(d)) {
+ PyErr_SetObject(PyExc_ValueError, d);
+ return (NULL);
+ }
+
+ err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
+ assert(err == 0);
+
+ while (PyDict_Next(d, &pos, &key, &value)) {
+ char *keystr = PyString_AsString(key);
+ if (keystr == NULL) {
+ PyErr_SetObject(PyExc_KeyError, key);
+ nvlist_free(nvl);
+ return (NULL);
+ }
+
+ if (PyDict_Check(value)) {
+ nvlist_t *valnvl = dict2nvl(value);
+ err = nvlist_add_nvlist(nvl, keystr, valnvl);
+ nvlist_free(valnvl);
+ } else if (value == Py_None) {
+ err = nvlist_add_boolean(nvl, keystr);
+ } else if (PyString_Check(value)) {
+ char *valstr = PyString_AsString(value);
+ err = nvlist_add_string(nvl, keystr, valstr);
+ } else if (PyInt_Check(value)) {
+ uint64_t valint = PyInt_AsUnsignedLongLongMask(value);
+ err = nvlist_add_uint64(nvl, keystr, valint);
+ } else if (PyBool_Check(value)) {
+ boolean_t valbool = value == Py_True ? B_TRUE : B_FALSE;
+ err = nvlist_add_boolean_value(nvl, keystr, valbool);
+ } else {
+ PyErr_SetObject(PyExc_ValueError, value);
+ nvlist_free(nvl);
+ return (NULL);
+ }
+ assert(err == 0);
+ }
+
+ return (nvl);
+}
+
+static PyObject *
+fakepropval(uint64_t value)
+{
+ PyObject *d = PyDict_New();
+ PyDict_SetItemString(d, "value", Py_BuildValue("K", value));
+ return (d);
+}
+
+static void
+add_ds_props(zfs_cmd_t *zc, PyObject *nvl)
+{
+ dmu_objset_stats_t *s = &zc->zc_objset_stats;
+ PyDict_SetItemString(nvl, "numclones",
+ fakepropval(s->dds_num_clones));
+ PyDict_SetItemString(nvl, "issnap",
+ fakepropval(s->dds_is_snapshot));
+ PyDict_SetItemString(nvl, "inconsistent",
+ fakepropval(s->dds_inconsistent));
+}
+
+/* On error, returns NULL but does not set python exception. */
+static PyObject *
+ioctl_with_dstnv(int ioc, zfs_cmd_t *zc)
+{
+ int nvsz = 2048;
+ void *nvbuf;
+ PyObject *pynv = NULL;
+
+again:
+ nvbuf = malloc(nvsz);
+ zc->zc_nvlist_dst_size = nvsz;
+ zc->zc_nvlist_dst = (uintptr_t)nvbuf;
+
+ if (ioctl(zfsdevfd, ioc, zc) == 0) {
+ nvlist_t *nvl;
+
+ errno = nvlist_unpack(nvbuf, zc->zc_nvlist_dst_size, &nvl, 0);
+ if (errno == 0) {
+ pynv = nvl2py(nvl);
+ nvlist_free(nvl);
+ }
+ } else if (errno == ENOMEM) {
+ free(nvbuf);
+ nvsz = zc->zc_nvlist_dst_size;
+ goto again;
+ }
+ free(nvbuf);
+ return (pynv);
+}
+
+static PyObject *
+py_next_dataset(PyObject *self, PyObject *args)
+{
+ int ioc;
+ uint64_t cookie;
+ zfs_cmd_t zc = { 0 };
+ int snaps;
+ char *name;
+ PyObject *nvl;
+ PyObject *ret = NULL;
+
+ if (!PyArg_ParseTuple(args, "siK", &name, &snaps, &cookie))
+ return (NULL);
+
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+ zc.zc_cookie = cookie;
+
+ if (snaps)
+ ioc = ZFS_IOC_SNAPSHOT_LIST_NEXT;
+ else
+ ioc = ZFS_IOC_DATASET_LIST_NEXT;
+
+ nvl = ioctl_with_dstnv(ioc, &zc);
+ if (nvl) {
+ add_ds_props(&zc, nvl);
+ ret = Py_BuildValue("sKO", zc.zc_name, zc.zc_cookie, nvl);
+ Py_DECREF(nvl);
+ } else if (errno == ESRCH) {
+ PyErr_SetNone(PyExc_StopIteration);
+ } else {
+ if (snaps)
+ seterr(_("cannot get snapshots of %s"), name);
+ else
+ seterr(_("cannot get child datasets of %s"), name);
+ }
+ return (ret);
+}
+
+static PyObject *
+py_dataset_props(PyObject *self, PyObject *args)
+{
+ zfs_cmd_t zc = { 0 };
+ int snaps;
+ char *name;
+ PyObject *nvl;
+
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return (NULL);
+
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+
+ nvl = ioctl_with_dstnv(ZFS_IOC_OBJSET_STATS, &zc);
+ if (nvl) {
+ add_ds_props(&zc, nvl);
+ } else {
+ seterr(_("cannot access dataset %s"), name);
+ }
+ return (nvl);
+}
+
+static PyObject *
+py_get_fsacl(PyObject *self, PyObject *args)
+{
+ zfs_cmd_t zc = { 0 };
+ char *name;
+ PyObject *nvl;
+
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return (NULL);
+
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+
+ nvl = ioctl_with_dstnv(ZFS_IOC_GET_FSACL, &zc);
+ if (nvl == NULL)
+ seterr(_("cannot get permissions on %s"), name);
+
+ return (nvl);
+}
+
+static PyObject *
+py_set_fsacl(PyObject *self, PyObject *args)
+{
+ int un;
+ size_t nvsz;
+ zfs_cmd_t zc = { 0 };
+ char *name, *nvbuf;
+ PyObject *dict, *file;
+ nvlist_t *nvl;
+ int err;
+
+ if (!PyArg_ParseTuple(args, "siO!", &name, &un,
+ &PyDict_Type, &dict))
+ return (NULL);
+
+ nvl = dict2nvl(dict);
+ if (nvl == NULL)
+ return (NULL);
+
+ err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
+ assert(err == 0);
+ nvbuf = malloc(nvsz);
+ err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
+ assert(err == 0);
+
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+ zc.zc_nvlist_src_size = nvsz;
+ zc.zc_nvlist_src = (uintptr_t)nvbuf;
+ zc.zc_perm_action = un;
+
+ err = ioctl_with_cmdstr(ZFS_IOC_SET_FSACL, &zc);
+ free(nvbuf);
+ if (err) {
+ seterr(_("cannot set permissions on %s"), name);
+ return (NULL);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+py_get_holds(PyObject *self, PyObject *args)
+{
+ zfs_cmd_t zc = { 0 };
+ char *name;
+ PyObject *nvl;
+
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return (NULL);
+
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+
+ nvl = ioctl_with_dstnv(ZFS_IOC_GET_HOLDS, &zc);
+ if (nvl == NULL)
+ seterr(_("cannot get holds for %s"), name);
+
+ return (nvl);
+}
+
+static PyObject *
+py_userspace_many(PyObject *self, PyObject *args)
+{
+ zfs_cmd_t zc = { 0 };
+ zfs_userquota_prop_t type;
+ char *name, *propname;
+ int bufsz = 1<<20;
+ void *buf;
+ PyObject *dict, *file;
+ int error;
+
+ if (!PyArg_ParseTuple(args, "ss", &name, &propname))
+ return (NULL);
+
+ for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++)
+ if (strcmp(propname, zfs_userquota_prop_prefixes[type]) == 0)
+ break;
+ if (type == ZFS_NUM_USERQUOTA_PROPS) {
+ PyErr_SetString(PyExc_KeyError, propname);
+ return (NULL);
+ }
+
+ dict = PyDict_New();
+ buf = malloc(bufsz);
+
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+ zc.zc_objset_type = type;
+ zc.zc_cookie = 0;
+
+ while (1) {
+ zfs_useracct_t *zua = buf;
+
+ zc.zc_nvlist_dst = (uintptr_t)buf;
+ zc.zc_nvlist_dst_size = bufsz;
+
+ error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_MANY, &zc);
+ if (error || zc.zc_nvlist_dst_size == 0)
+ break;
+
+ while (zc.zc_nvlist_dst_size > 0) {
+ PyObject *pykey, *pyval;
+
+ pykey = Py_BuildValue("sI",
+ zua->zu_domain, zua->zu_rid);
+ pyval = Py_BuildValue("K", zua->zu_space);
+ PyDict_SetItem(dict, pykey, pyval);
+ Py_DECREF(pykey);
+ Py_DECREF(pyval);
+
+ zua++;
+ zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
+ }
+ }
+
+ free(buf);
+
+ if (error != 0) {
+ Py_DECREF(dict);
+ seterr(_("cannot get %s property on %s"), propname, name);
+ return (NULL);
+ }
+
+ return (dict);
+}
+
+static PyObject *
+py_userspace_upgrade(PyObject *self, PyObject *args)
+{
+ zfs_cmd_t zc = { 0 };
+ char *name;
+ int error;
+
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return (NULL);
+
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+ error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_UPGRADE, &zc);
+
+ if (error != 0) {
+ seterr(_("cannot initialize user accounting information on %s"),
+ name);
+ return (NULL);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+py_set_cmdstr(PyObject *self, PyObject *args)
+{
+ char *str;
+
+ if (!PyArg_ParseTuple(args, "s", &str))
+ return (NULL);
+
+ (void) strlcpy(cmdstr, str, sizeof (cmdstr));
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+py_get_proptable(PyObject *self, PyObject *args)
+{
+ zprop_desc_t *t = zfs_prop_get_table();
+ PyObject *d = PyDict_New();
+ zfs_prop_t i;
+
+ for (i = 0; i < ZFS_NUM_PROPS; i++) {
+ zprop_desc_t *p = &t[i];
+ PyObject *tuple;
+ static const char *typetable[] =
+ {"number", "string", "index"};
+ static const char *attrtable[] =
+ {"default", "readonly", "inherit", "onetime"};
+ PyObject *indextable;
+
+ if (p->pd_proptype == PROP_TYPE_INDEX) {
+ const zprop_index_t *it = p->pd_table;
+ indextable = PyDict_New();
+ int j;
+ for (j = 0; it[j].pi_name; j++) {
+ PyDict_SetItemString(indextable,
+ it[j].pi_name,
+ Py_BuildValue("K", it[j].pi_value));
+ }
+ } else {
+ Py_INCREF(Py_None);
+ indextable = Py_None;
+ }
+
+ tuple = Py_BuildValue("sissKsissiiO",
+ p->pd_name, p->pd_propnum, typetable[p->pd_proptype],
+ p->pd_strdefault, p->pd_numdefault,
+ attrtable[p->pd_attr], p->pd_types,
+ p->pd_values, p->pd_colname,
+ p->pd_rightalign, p->pd_visible, indextable);
+ PyDict_SetItemString(d, p->pd_name, tuple);
+ Py_DECREF(tuple);
+ }
+
+ return (d);
+}
+
+static PyMethodDef zfsmethods[] = {
+ {"next_dataset", py_next_dataset, METH_VARARGS,
+ "Get next child dataset or snapshot."},
+ {"get_fsacl", py_get_fsacl, METH_VARARGS, "Get allowed permissions."},
+ {"set_fsacl", py_set_fsacl, METH_VARARGS, "Set allowed permissions."},
+ {"userspace_many", py_userspace_many, METH_VARARGS,
+ "Get user space accounting."},
+ {"userspace_upgrade", py_userspace_upgrade, METH_VARARGS,
+ "Upgrade fs to enable user space accounting."},
+ {"set_cmdstr", py_set_cmdstr, METH_VARARGS,
+ "Set command string for history logging."},
+ {"dataset_props", py_dataset_props, METH_VARARGS,
+ "Get dataset properties."},
+ {"get_proptable", py_get_proptable, METH_NOARGS,
+ "Get property table."},
+ {"get_holds", py_get_holds, METH_VARARGS, "Get user holds."},
+ {NULL, NULL, 0, NULL}
+};
+
+void
+initioctl(void)
+{
+ PyObject *zfs_ioctl = Py_InitModule("zfs.ioctl", zfsmethods);
+ PyObject *zfs_util = PyImport_ImportModule("zfs.util");
+ PyObject *devfile;
+
+ if (zfs_util == NULL)
+ return;
+
+ ZFSError = PyObject_GetAttrString(zfs_util, "ZFSError");
+ devfile = PyObject_GetAttrString(zfs_util, "dev");
+ zfsdevfd = PyObject_AsFileDescriptor(devfile);
+
+ zfs_prop_init();
+}
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/table.py b/cddl/contrib/opensolaris/lib/pyzfs/common/table.py
new file mode 100644
index 000000000000..d2a45a142c29
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/table.py
@@ -0,0 +1,70 @@
+#! /usr/bin/python2.6
+#
+# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import zfs.util
+
+class Table:
+ __slots__ = "fields", "rjustfields", "maxfieldlen", "lines"
+ __repr__ = zfs.util.default_repr
+
+ def __init__(self, fields, rjustfields=()):
+ # XXX maybe have a defaults, too?
+ self.fields = fields
+ self.rjustfields = rjustfields
+ self.maxfieldlen = dict.fromkeys(fields, 0)
+ self.lines = list()
+
+ def __updatemax(self, k, v):
+ self.maxfieldlen[k] = max(self.maxfieldlen.get(k, None), v)
+
+ def addline(self, sortkey, values):
+ """values is a dict from field name to value"""
+
+ va = list()
+ for f in self.fields:
+ v = str(values[f])
+ va.append(v)
+ self.__updatemax(f, len(v))
+ self.lines.append((sortkey, va))
+
+ def printme(self, headers=True):
+ if headers:
+ d = dict([(f, f.upper()) for f in self.fields])
+ self.addline(None, d)
+
+ self.lines.sort()
+ for (k, va) in self.lines:
+ line = str()
+ for i in range(len(self.fields)):
+ if not headers:
+ line += va[i]
+ line += "\t"
+ else:
+ if self.fields[i] in self.rjustfields:
+ fmt = "%*s "
+ else:
+ fmt = "%-*s "
+ mfl = self.maxfieldlen[self.fields[i]]
+ line += fmt % (mfl, va[i])
+ print(line)
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/unallow.py b/cddl/contrib/opensolaris/lib/pyzfs/common/unallow.py
new file mode 100644
index 000000000000..cbdd4dd73f6f
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/unallow.py
@@ -0,0 +1,27 @@
+#! /usr/bin/python2.6
+#
+# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import zfs.allow
+
+do_unallow = zfs.allow.do_allow
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/userspace.py b/cddl/contrib/opensolaris/lib/pyzfs/common/userspace.py
new file mode 100644
index 000000000000..33646bca5b7f
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/userspace.py
@@ -0,0 +1,246 @@
+#! /usr/bin/python2.6
+#
+# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+"""This module implements the "zfs userspace" and "zfs groupspace" subcommands.
+The only public interface is the zfs.userspace.do_userspace() function."""
+
+import optparse
+import sys
+import pwd
+import grp
+import errno
+import solaris.misc
+import zfs.util
+import zfs.ioctl
+import zfs.dataset
+import zfs.table
+
+_ = zfs.util._
+
+# map from property name prefix -> (field name, isgroup)
+props = {
+ "userused@": ("used", False),
+ "userquota@": ("quota", False),
+ "groupused@": ("used", True),
+ "groupquota@": ("quota", True),
+}
+
+def skiptype(options, prop):
+ """Return True if this property (eg "userquota@") should be skipped."""
+ (field, isgroup) = props[prop]
+ if field not in options.fields:
+ return True
+ if isgroup and "posixgroup" not in options.types and \
+ "smbgroup" not in options.types:
+ return True
+ if not isgroup and "posixuser" not in options.types and \
+ "smbuser" not in options.types:
+ return True
+ return False
+
+def new_entry(options, isgroup, domain, rid):
+ """Return a dict("field": value) for this domain (string) + rid (int)"""
+
+ if domain:
+ idstr = "%s-%u" % (domain, rid)
+ else:
+ idstr = "%u" % rid
+
+ (typename, mapfunc) = {
+ (1, 1): ("SMB Group", lambda id: solaris.misc.sid_to_name(id, 0)),
+ (1, 0): ("POSIX Group", lambda id: grp.getgrgid(int(id)).gr_name),
+ (0, 1): ("SMB User", lambda id: solaris.misc.sid_to_name(id, 1)),
+ (0, 0): ("POSIX User", lambda id: pwd.getpwuid(int(id)).pw_name)
+ }[isgroup, bool(domain)]
+
+ if typename.lower().replace(" ", "") not in options.types:
+ return None
+
+ v = dict()
+ v["type"] = typename
+
+ # python's getpwuid/getgrgid is confused by ephemeral uids
+ if not options.noname and rid < 1<<31:
+ try:
+ v["name"] = mapfunc(idstr)
+ except KeyError:
+ pass
+
+ if "name" not in v:
+ v["name"] = idstr
+ if not domain:
+ # it's just a number, so pad it with spaces so
+ # that it will sort numerically
+ v["name.sort"] = "%20d" % rid
+ # fill in default values
+ v["used"] = "0"
+ v["used.sort"] = 0
+ v["quota"] = "none"
+ v["quota.sort"] = 0
+ return v
+
+def process_one_raw(acct, options, prop, elem):
+ """Update the acct dict to incorporate the
+ information from this elem from Dataset.userspace(prop)."""
+
+ (domain, rid, value) = elem
+ (field, isgroup) = props[prop]
+
+ if options.translate and domain:
+ try:
+ rid = solaris.misc.sid_to_id("%s-%u" % (domain, rid),
+ not isgroup)
+ domain = None
+ except KeyError:
+ pass;
+ key = (isgroup, domain, rid)
+
+ try:
+ v = acct[key]
+ except KeyError:
+ v = new_entry(options, isgroup, domain, rid)
+ if not v:
+ return
+ acct[key] = v
+
+ # Add our value to an existing value, which may be present if
+ # options.translate is set.
+ value = v[field + ".sort"] = value + v[field + ".sort"]
+
+ if options.parsable:
+ v[field] = str(value)
+ else:
+ v[field] = zfs.util.nicenum(value)
+
+def do_userspace():
+ """Implements the "zfs userspace" and "zfs groupspace" subcommands."""
+
+ def usage(msg=None):
+ parser.print_help()
+ if msg:
+ print
+ parser.exit("zfs: error: " + msg)
+ else:
+ parser.exit()
+
+ if sys.argv[1] == "userspace":
+ defaulttypes = "posixuser,smbuser"
+ else:
+ defaulttypes = "posixgroup,smbgroup"
+
+ fields = ("type", "name", "used", "quota")
+ rjustfields = ("used", "quota")
+ types = ("all", "posixuser", "smbuser", "posixgroup", "smbgroup")
+
+ u = _("%s [-niHp] [-o field[,...]] [-sS field] ... \n") % sys.argv[1]
+ u += _(" [-t type[,...]] <filesystem|snapshot>")
+ parser = optparse.OptionParser(usage=u, prog="zfs")
+
+ parser.add_option("-n", action="store_true", dest="noname",
+ help=_("Print numeric ID instead of user/group name"))
+ parser.add_option("-i", action="store_true", dest="translate",
+ help=_("translate SID to posix (possibly ephemeral) ID"))
+ parser.add_option("-H", action="store_true", dest="noheaders",
+ help=_("no headers, tab delimited output"))
+ parser.add_option("-p", action="store_true", dest="parsable",
+ help=_("exact (parsable) numeric output"))
+ parser.add_option("-o", dest="fields", metavar="field[,...]",
+ default="type,name,used,quota",
+ help=_("print only these fields (eg type,name,used,quota)"))
+ parser.add_option("-s", dest="sortfields", metavar="field",
+ type="choice", choices=fields, default=list(),
+ action="callback", callback=zfs.util.append_with_opt,
+ help=_("sort field"))
+ parser.add_option("-S", dest="sortfields", metavar="field",
+ type="choice", choices=fields, #-s sets the default
+ action="callback", callback=zfs.util.append_with_opt,
+ help=_("reverse sort field"))
+ parser.add_option("-t", dest="types", metavar="type[,...]",
+ default=defaulttypes,
+ help=_("print only these types (eg posixuser,smbuser,posixgroup,smbgroup,all)"))
+
+ (options, args) = parser.parse_args(sys.argv[2:])
+ if len(args) != 1:
+ usage(_("wrong number of arguments"))
+ dsname = args[0]
+
+ options.fields = options.fields.split(",")
+ for f in options.fields:
+ if f not in fields:
+ usage(_("invalid field %s") % f)
+
+ options.types = options.types.split(",")
+ for t in options.types:
+ if t not in types:
+ usage(_("invalid type %s") % t)
+
+ if not options.sortfields:
+ options.sortfields = [("-s", "type"), ("-s", "name")]
+
+ if "all" in options.types:
+ options.types = types[1:]
+
+ ds = zfs.dataset.Dataset(dsname, types=("filesystem"))
+
+ if ds.getprop("jailed") and solaris.misc.isglobalzone():
+ options.noname = True
+
+ if not ds.getprop("useraccounting"):
+ print(_("Initializing accounting information on old filesystem, please wait..."))
+ ds.userspace_upgrade()
+
+ # gather and process accounting information
+ # Due to -i, we need to keep a dict, so we can potentially add
+ # together the posix ID and SID's usage. Grr.
+ acct = dict()
+ for prop in props.keys():
+ if skiptype(options, prop):
+ continue;
+ for elem in ds.userspace(prop):
+ process_one_raw(acct, options, prop, elem)
+
+ def cmpkey(val):
+ l = list()
+ for (opt, field) in options.sortfields:
+ try:
+ n = val[field + ".sort"]
+ except KeyError:
+ n = val[field]
+ if opt == "-S":
+ # reverse sorting
+ try:
+ n = -n
+ except TypeError:
+ # it's a string; decompose it
+ # into an array of integers,
+ # each one the negative of that
+ # character
+ n = [-ord(c) for c in n]
+ l.append(n)
+ return l
+
+ t = zfs.table.Table(options.fields, rjustfields)
+ for val in acct.itervalues():
+ t.addline(cmpkey(val), val)
+ t.printme(not options.noheaders)
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/util.py b/cddl/contrib/opensolaris/lib/pyzfs/common/util.py
new file mode 100644
index 000000000000..a33c6693ee00
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/util.py
@@ -0,0 +1,141 @@
+#! /usr/bin/python2.6
+#
+# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+"""This module provides utility functions for ZFS.
+zfs.util.dev -- a file object of /dev/zfs """
+
+import gettext
+import errno
+import os
+import solaris.misc
+# Note: this module (zfs.util) should not import zfs.ioctl, because that
+# would introduce a circular dependency
+
+errno.ECANCELED = 47
+errno.ENOTSUP = 48
+
+dev = open("/dev/zfs", "w")
+
+try:
+ _ = gettext.translation("SUNW_OST_OSLIB", "/usr/lib/locale",
+ fallback=True).gettext
+except:
+ _ = solaris.misc.gettext
+
+def default_repr(self):
+ """A simple __repr__ function."""
+ if self.__slots__:
+ str = "<" + self.__class__.__name__
+ for v in self.__slots__:
+ str += " %s: %r" % (v, getattr(self, v))
+ return str + ">"
+ else:
+ return "<%s %s>" % \
+ (self.__class__.__name__, repr(self.__dict__))
+
+class ZFSError(StandardError):
+ """This exception class represents a potentially user-visible
+ ZFS error. If uncaught, it will be printed and the process will
+ exit with exit code 1.
+
+ errno -- the error number (eg, from ioctl(2))."""
+
+ __slots__ = "why", "task", "errno"
+ __repr__ = default_repr
+
+ def __init__(self, eno, task=None, why=None):
+ """Create a ZFS exception.
+ eno -- the error number (errno)
+ task -- a string describing the task that failed
+ why -- a string describing why it failed (defaults to
+ strerror(eno))"""
+
+ self.errno = eno
+ self.task = task
+ self.why = why
+
+ def __str__(self):
+ s = ""
+ if self.task:
+ s += self.task + ": "
+ if self.why:
+ s += self.why
+ else:
+ s += self.strerror
+ return s
+
+ __strs = {
+ errno.EPERM: _("permission denied"),
+ errno.ECANCELED:
+ _("delegated administration is disabled on pool"),
+ errno.EINTR: _("signal received"),
+ errno.EIO: _("I/O error"),
+ errno.ENOENT: _("dataset does not exist"),
+ errno.ENOSPC: _("out of space"),
+ errno.EEXIST: _("dataset already exists"),
+ errno.EBUSY: _("dataset is busy"),
+ errno.EROFS:
+ _("snapshot permissions cannot be modified"),
+ errno.ENAMETOOLONG: _("dataset name is too long"),
+ errno.ENOTSUP: _("unsupported version"),
+ errno.EAGAIN: _("pool I/O is currently suspended"),
+ }
+
+ __strs[errno.EACCES] = __strs[errno.EPERM]
+ __strs[errno.ENXIO] = __strs[errno.EIO]
+ __strs[errno.ENODEV] = __strs[errno.EIO]
+ __strs[errno.EDQUOT] = __strs[errno.ENOSPC]
+
+ @property
+ def strerror(self):
+ return ZFSError.__strs.get(self.errno, os.strerror(self.errno))
+
+def nicenum(num):
+ """Return a nice string (eg "1.23M") for this integer."""
+ index = 0;
+ n = num;
+
+ while n >= 1024:
+ n /= 1024
+ index += 1
+
+ u = " KMGTPE"[index]
+ if index == 0:
+ return "%u" % n;
+ elif n >= 100 or num & ((1024*index)-1) == 0:
+ # it's an exact multiple of its index, or it wouldn't
+ # fit as floating point, so print as an integer
+ return "%u%c" % (n, u)
+ else:
+ # due to rounding, it's tricky to tell what precision to
+ # use; try each precision and see which one fits
+ for i in (2, 1, 0):
+ s = "%.*f%c" % (i, float(num) / (1<<(10*index)), u)
+ if len(s) <= 5:
+ return s
+
+def append_with_opt(option, opt, value, parser):
+ """A function for OptionParser which appends a tuple (opt, value)."""
+ getattr(parser.values, option.dest).append((opt, value))
+
diff --git a/cddl/contrib/opensolaris/tools/ctf/common/ctf_headers.h b/cddl/contrib/opensolaris/tools/ctf/common/ctf_headers.h
new file mode 100644
index 000000000000..b00b8fd9a650
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/common/ctf_headers.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _CTF_HEADERS_H
+#define _CTF_HEADERS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Because the ON tools are executed on the system where they are built,
+ * the tools need to include the headers installed on the build system,
+ * rather than those in the ON source tree. However, some of the headers
+ * required by the tools are part of the ON source tree, but not delivered
+ * as part of Solaris. These include the following:
+ *
+ * $(SRC)/lib/libctf/common/libctf.h
+ * $(SRC)/uts/common/sys/ctf_api.h
+ * $(SRC)/uts/common/sys/ctf.h
+ *
+ * These headers get installed in the proto area in the build environment
+ * under $(ROOT)/usr/include and $(ROOT)/usr/include/sys. Though these
+ * headers are not part of the release, in releases including and prior to
+ * Solaris 9, they did get installed on the build system via bfu. Therefore,
+ * we can not simply force the order of inclusion with -I/usr/include first
+ * in Makefile.ctf because we might actually get downlevel versions of the
+ * ctf headers. Depending on the order of the -I includes, we can also have
+ * a problem with mismatched headers when building the ctf tools with some
+ * headers getting pulled in from /usr/include and others from
+ * $(SRC)/uts/common/sys.
+ *
+ * To address the problem, we have done two things:
+ * 1) Created this header with a specific order of inclusion for the
+ * ctf headers. Because the <libctf.h> header includes <sys/ctf_api.h>
+ * which in turn includes <sys/ctf.h> we need to include these in
+ * reverse order to guarantee that we get the correct versions of
+ * the headers.
+ * 2) In $(SRC)/tools/ctf/Makefile.ctf, we order the -I includes such
+ * that we first search the directories where the ctf headers
+ * live, followed by /usr/include, followed by $(SRC)/uts/common.
+ * This last -I include is needed in order to prevent a build failure
+ * when <sys/ctf_api.h> is included via a nested #include rather than
+ * an explicit path #include.
+ */
+
+#include <uts/common/sys/ctf.h>
+#include <uts/common/sys/ctf_api.h>
+#include <lib/libctf/common/libctf.h>
+
+#endif /* _CTF_HEADERS_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/common/list.c b/cddl/contrib/opensolaris/tools/ctf/common/list.c
new file mode 100644
index 000000000000..4958f270a994
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/common/list.c
@@ -0,0 +1,228 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for manipulating linked lists
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "list.h"
+#include "memory.h"
+
+struct list {
+ void *l_data;
+ struct list *l_next;
+};
+
+/* Add an element to a list */
+void
+list_add(list_t **list, void *data)
+{
+ list_t *le;
+
+ le = xmalloc(sizeof (list_t));
+ le->l_data = data;
+ le->l_next = *list;
+ *list = le;
+}
+
+/* Add an element to a sorted list */
+void
+slist_add(list_t **list, void *data, int (*cmp)(void *, void *))
+{
+ list_t **nextp;
+
+ for (nextp = list; *nextp; nextp = &((*nextp)->l_next)) {
+ if (cmp((*nextp)->l_data, data) > 0)
+ break;
+ }
+
+ list_add(nextp, data);
+}
+
+/*ARGSUSED2*/
+static int
+list_defcmp(void *d1, void *d2, void *private __unused)
+{
+ return (d1 != d2);
+}
+
+void *
+list_remove(list_t **list, void *data, int (*cmp)(void *, void *, void *),
+ void *private)
+{
+ list_t *le, **le2;
+ void *led;
+
+ if (!cmp)
+ cmp = list_defcmp;
+
+ for (le = *list, le2 = list; le; le2 = &le->l_next, le = le->l_next) {
+ if (cmp(le->l_data, data, private) == 0) {
+ *le2 = le->l_next;
+ led = le->l_data;
+ free(le);
+ return (led);
+ }
+ }
+
+ return (NULL);
+}
+
+void
+list_free(list_t *list, void (*datafree)(void *, void *), void *private)
+{
+ list_t *le;
+
+ while (list) {
+ le = list;
+ list = list->l_next;
+ if (le->l_data && datafree)
+ datafree(le->l_data, private);
+ free(le);
+ }
+}
+
+/*
+ * This iterator is specifically designed to tolerate the deletion of the
+ * node being iterated over.
+ */
+int
+list_iter(list_t *list, int (*func)(void *, void *), void *private)
+{
+ list_t *lnext;
+ int cumrc = 0;
+ int cbrc;
+
+ while (list) {
+ lnext = list->l_next;
+ if ((cbrc = func(list->l_data, private)) < 0)
+ return (cbrc);
+ cumrc += cbrc;
+ list = lnext;
+ }
+
+ return (cumrc);
+}
+
+/*ARGSUSED*/
+static int
+list_count_cb(void *data __unused, void *private __unused)
+{
+ return (1);
+}
+
+int
+list_count(list_t *list)
+{
+ return (list_iter(list, list_count_cb, NULL));
+}
+
+int
+list_empty(list_t *list)
+{
+ return (list == NULL);
+}
+
+void *
+list_find(list_t *list, void *tmpl, int (*cmp)(void *, void *))
+{
+ for (; list; list = list->l_next) {
+ if (cmp(list->l_data, tmpl) == 0)
+ return (list->l_data);
+ }
+
+ return (NULL);
+}
+
+void *
+list_first(list_t *list)
+{
+ return (list ? list->l_data : NULL);
+}
+
+void
+list_concat(list_t **list1, list_t *list2)
+{
+ list_t *l, *last;
+
+ for (l = *list1, last = NULL; l; last = l, l = l->l_next)
+ continue;
+
+ if (last == NULL)
+ *list1 = list2;
+ else
+ last->l_next = list2;
+}
+
+/*
+ * Merges two sorted lists. Equal nodes (as determined by cmp) are retained.
+ */
+void
+slist_merge(list_t **list1p, list_t *list2, int (*cmp)(void *, void *))
+{
+ list_t *list1, *next2;
+ list_t *last1 = NULL;
+
+ if (*list1p == NULL) {
+ *list1p = list2;
+ return;
+ }
+
+ list1 = *list1p;
+ while (list2 != NULL) {
+ if (cmp(list1->l_data, list2->l_data) > 0) {
+ next2 = list2->l_next;
+
+ if (last1 == NULL) {
+ /* Insert at beginning */
+ *list1p = last1 = list2;
+ list2->l_next = list1;
+ } else {
+ list2->l_next = list1;
+ last1->l_next = list2;
+ last1 = list2;
+ }
+
+ list2 = next2;
+ } else {
+
+ last1 = list1;
+ list1 = list1->l_next;
+
+ if (list1 == NULL) {
+ /* Add the rest to the end of list1 */
+ last1->l_next = list2;
+ list2 = NULL;
+ }
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/common/list.h b/cddl/contrib/opensolaris/tools/ctf/common/list.h
new file mode 100644
index 000000000000..2e41271d0ff0
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/common/list.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ * 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 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIST_H
+#define _LIST_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for manipulating linked lists
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct list list_t;
+
+void list_add(list_t **, void *);
+void slist_add(list_t **, void *, int (*)(void *, void *));
+void *list_remove(list_t **, void *, int (*)(void *, void *, void *), void *);
+void list_free(list_t *, void (*)(void *, void *), void *);
+void *list_find(list_t *, void *, int (*)(void *, void *));
+void *list_first(list_t *);
+int list_iter(list_t *, int (*)(void *, void *), void *);
+int list_count(list_t *);
+int list_empty(list_t *);
+void list_concat(list_t **, list_t *);
+void slist_merge(list_t **, list_t *, int (*)(void *, void *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIST_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/common/memory.c b/cddl/contrib/opensolaris/tools/ctf/common/memory.c
new file mode 100644
index 000000000000..e16044a8b672
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/common/memory.c
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ *
+ * 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 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for memory management
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "memory.h"
+
+static void
+memory_bailout(void)
+{
+ (void) fprintf(stderr, "Out of memory\n");
+ exit(1);
+}
+
+void *
+xmalloc(size_t size)
+{
+ void *mem;
+
+ if ((mem = malloc(size)) == NULL)
+ memory_bailout();
+
+ return (mem);
+}
+
+void *
+xcalloc(size_t size)
+{
+ void *mem;
+
+ mem = xmalloc(size);
+ bzero(mem, size);
+
+ return (mem);
+}
+
+char *
+xstrdup(const char *str)
+{
+ char *newstr;
+
+ if ((newstr = strdup(str)) == NULL)
+ memory_bailout();
+
+ return (newstr);
+}
+
+char *
+xstrndup(char *str, size_t len)
+{
+ char *newstr;
+
+ if ((newstr = malloc(len + 1)) == NULL)
+ memory_bailout();
+
+ (void) strncpy(newstr, str, len);
+ newstr[len] = '\0';
+
+ return (newstr);
+}
+
+void *
+xrealloc(void *ptr, size_t size)
+{
+ void *mem;
+
+ if ((mem = realloc(ptr, size)) == NULL)
+ memory_bailout();
+
+ return (mem);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/common/memory.h b/cddl/contrib/opensolaris/tools/ctf/common/memory.h
new file mode 100644
index 000000000000..88ca31bec65a
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/common/memory.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ *
+ * 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 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MEMORY_H
+#define _MEMORY_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for memory management
+ */
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *xmalloc(size_t);
+void *xcalloc(size_t);
+char *xstrdup(const char *);
+char *xstrndup(char *, size_t);
+void *xrealloc(void *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MEMORY_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/common/symbol.c b/cddl/contrib/opensolaris/tools/ctf/common/symbol.c
new file mode 100644
index 000000000000..29796acb2c61
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/common/symbol.c
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "symbol.h"
+
+int
+ignore_symbol(GElf_Sym *sym, const char *name)
+{
+ uchar_t type = GELF_ST_TYPE(sym->st_info);
+
+ /*
+ * As an optimization, we do not output function or data object
+ * records for undefined or anonymous symbols.
+ */
+ if (sym->st_shndx == SHN_UNDEF || sym->st_name == 0)
+ return (1);
+
+ /*
+ * _START_ and _END_ are added to the symbol table by the
+ * linker, and will never have associated type information.
+ */
+ if (strcmp(name, "_START_") == 0 || strcmp(name, "_END_") == 0)
+ return (1);
+
+ /*
+ * Do not output records for absolute-valued object symbols
+ * that have value zero. The compiler insists on generating
+ * things like this for __fsr_init_value settings, etc.
+ */
+ if (type == STT_OBJECT && sym->st_shndx == SHN_ABS &&
+ sym->st_value == 0)
+ return (1);
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/common/symbol.h b/cddl/contrib/opensolaris/tools/ctf/common/symbol.h
new file mode 100644
index 000000000000..92b5e892affb
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/common/symbol.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYMBOL_H
+#define _SYMBOL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <gelf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ignore_symbol(GElf_Sym *sym, const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYMBOL_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/common/utils.c b/cddl/contrib/opensolaris/tools/ctf/common/utils.c
new file mode 100644
index 000000000000..b9db1a870165
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/common/utils.c
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1998-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "utils.h"
+
+/*LINTLIBRARY*/
+
+static const char *pname;
+
+#pragma init(getpname)
+const char *
+getpname(void)
+{
+ const char *p, *q;
+
+ if (pname != NULL)
+ return (pname);
+
+ if ((p = getexecname()) != NULL)
+ q = strrchr(p, '/');
+ else
+ q = NULL;
+
+ if (q == NULL)
+ pname = p;
+ else
+ pname = q + 1;
+
+ return (pname);
+}
+
+void
+vwarn(const char *format, va_list alist)
+{
+ int err = errno;
+
+ if (pname != NULL)
+ (void) fprintf(stderr, "%s: ", pname);
+
+ (void) vfprintf(stderr, format, alist);
+
+ if (strchr(format, '\n') == NULL)
+ (void) fprintf(stderr, ": %s\n", strerror(err));
+}
+
+/*PRINTFLIKE1*/
+void
+warn(const char *format, ...)
+{
+ va_list alist;
+
+ va_start(alist, format);
+ vwarn(format, alist);
+ va_end(alist);
+}
+
+void
+vdie(const char *format, va_list alist)
+{
+ vwarn(format, alist);
+ exit(E_ERROR);
+}
+
+/*PRINTFLIKE1*/
+void
+die(const char *format, ...)
+{
+ va_list alist;
+
+ va_start(alist, format);
+ vdie(format, alist);
+ va_end(alist);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/common/utils.h b/cddl/contrib/opensolaris/tools/ctf/common/utils.h
new file mode 100644
index 000000000000..9b07361a53ab
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/common/utils.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1998-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _UTILS_H
+#define _UTILS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define E_SUCCESS 0 /* Exit status for success */
+#define E_ERROR 1 /* Exit status for error */
+#define E_USAGE 2 /* Exit status for usage error */
+
+extern void vwarn(const char *, va_list);
+extern void warn(const char *, ...);
+extern void vdie(const char *, va_list);
+extern void die(const char *, ...);
+
+extern const char *getpname(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTILS_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/alist.c b/cddl/contrib/opensolaris/tools/ctf/cvt/alist.c
new file mode 100644
index 000000000000..8e776dc08a7f
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/alist.c
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ *
+ * 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 2001-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Create, manage, and destroy association lists. alists are arrays with
+ * arbitrary index types, and are also commonly known as associative arrays.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "alist.h"
+#include "memory.h"
+#include "hash.h"
+
+#define ALIST_HASH_SIZE 997
+
+struct alist {
+ hash_t *al_elements;
+ void (*al_namefree)(void *);
+ void (*al_valfree)(void *);
+};
+
+typedef struct alist_el {
+ void *ale_name;
+ void *ale_value;
+} alist_el_t;
+
+static int
+alist_hash(int nbuckets, void *arg)
+{
+ alist_el_t *el = arg;
+ uintptr_t num = (uintptr_t)el->ale_name;
+
+ return (num % nbuckets);
+}
+
+static int
+alist_cmp(void *arg1, void *arg2)
+{
+ alist_el_t *el1 = arg1;
+ alist_el_t *el2 = arg2;
+ return ((uintptr_t)el1->ale_name != (uintptr_t)el2->ale_name);
+}
+
+alist_t *
+alist_xnew(int nbuckets, void (*namefree)(void *),
+ void (*valfree)(void *), int (*hashfn)(int, void *),
+ int (*cmpfn)(void *, void *))
+{
+ alist_t *alist;
+
+ alist = xcalloc(sizeof (alist_t));
+ alist->al_elements = hash_new(nbuckets, hashfn, cmpfn);
+ alist->al_namefree = namefree;
+ alist->al_valfree = valfree;
+
+ return (alist);
+}
+
+alist_t *
+alist_new(void (*namefree)(void *), void (*valfree)(void *))
+{
+ return (alist_xnew(ALIST_HASH_SIZE, namefree, valfree,
+ alist_hash, alist_cmp));
+}
+
+static void
+alist_free_cb(void *arg1, void *arg2)
+{
+ alist_el_t *el = arg1;
+ alist_t *alist = arg2;
+ if (alist->al_namefree)
+ alist->al_namefree(el->ale_name);
+ if (alist->al_valfree)
+ alist->al_valfree(el->ale_name);
+ free(el);
+}
+
+void
+alist_free(alist_t *alist)
+{
+ hash_free(alist->al_elements, alist_free_cb, alist);
+ free(alist);
+}
+
+void
+alist_add(alist_t *alist, void *name, void *value)
+{
+ alist_el_t *el;
+
+ el = xmalloc(sizeof (alist_el_t));
+ el->ale_name = name;
+ el->ale_value = value;
+ hash_add(alist->al_elements, el);
+}
+
+int
+alist_find(alist_t *alist, void *name, void **value)
+{
+ alist_el_t template, *retx;
+ void *ret;
+
+ template.ale_name = name;
+ if (!hash_find(alist->al_elements, &template, &ret))
+ return (0);
+
+ if (value) {
+ retx = ret;
+ *value = retx->ale_value;
+ }
+
+ return (1);
+}
+
+typedef struct alist_iter_data {
+ int (*aid_func)(void *, void *, void *);
+ void *aid_priv;
+} alist_iter_data_t;
+
+static int
+alist_iter_cb(void *arg1, void *arg2)
+{
+ alist_el_t *el = arg1;
+ alist_iter_data_t *aid = arg2;
+ return (aid->aid_func(el->ale_name, el->ale_value, aid->aid_priv));
+}
+
+int
+alist_iter(alist_t *alist, int (*func)(void *, void *, void *), void *private)
+{
+ alist_iter_data_t aid;
+
+ aid.aid_func = func;
+ aid.aid_priv = private;
+
+ return (hash_iter(alist->al_elements, alist_iter_cb, &aid));
+}
+
+/*
+ * Debugging support. Used to print the contents of an alist.
+ */
+
+void
+alist_stats(alist_t *alist, int verbose)
+{
+ printf("Alist statistics\n");
+ hash_stats(alist->al_elements, verbose);
+}
+
+static int alist_def_print_cb_key_int = 1;
+static int alist_def_print_cb_value_int = 1;
+
+static int
+alist_def_print_cb(void *key, void *value)
+{
+ printf("Key: ");
+ if (alist_def_print_cb_key_int == 1)
+ printf("%5lu ", (ulong_t)key);
+ else
+ printf("%s\n", (char *)key);
+
+ printf("Value: ");
+ if (alist_def_print_cb_value_int == 1)
+ printf("%5lu\n", (ulong_t)value);
+ else
+ printf("%s\n", (char *)key);
+
+ return (1);
+}
+
+static int
+alist_dump_cb(void *node, void *private)
+{
+ int (*printer)(void *, void *) = private;
+ alist_el_t *el = node;
+
+ printer(el->ale_name, el->ale_value);
+
+ return (1);
+}
+
+int
+alist_dump(alist_t *alist, int (*printer)(void *, void *))
+{
+ if (!printer)
+ printer = alist_def_print_cb;
+
+ return (hash_iter(alist->al_elements, alist_dump_cb, (void *)printer));
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/alist.h b/cddl/contrib/opensolaris/tools/ctf/cvt/alist.h
new file mode 100644
index 000000000000..629e0290e7ce
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/alist.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ * 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 2001-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ASSOC_H
+#define _ASSOC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Create, manage, and destroy association lists. alists are arrays with
+ * arbitrary index types.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct alist alist_t;
+
+alist_t *alist_new(void (*)(void *), void (*)(void *));
+alist_t *alist_xnew(int, void (*)(void *), void (*)(void *),
+ int (*)(int, void *), int (*)(void *, void *));
+void alist_free(alist_t *);
+void alist_add(alist_t *, void *, void *);
+int alist_find(alist_t *, void *, void **);
+int alist_iter(alist_t *, int (*)(void *, void *, void *), void *);
+void alist_stats(alist_t *, int);
+int alist_dump(alist_t *, int (*)(void *, void *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ASSOC_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/barrier.c b/cddl/contrib/opensolaris/tools/ctf/cvt/barrier.c
new file mode 100644
index 000000000000..c0719620dbde
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/barrier.c
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ * 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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file implements a barrier, a synchronization primitive designed to allow
+ * threads to wait for each other at given points. Barriers are initialized
+ * with a given number of threads, n, using barrier_init(). When a thread calls
+ * barrier_wait(), that thread blocks until n - 1 other threads reach the
+ * barrier_wait() call using the same barrier_t. When n threads have reached
+ * the barrier, they are all awakened and sent on their way. One of the threads
+ * returns from barrier_wait() with a return code of 1; the remaining threads
+ * get a return code of 0.
+ */
+
+#include <pthread.h>
+#ifdef illumos
+#include <synch.h>
+#endif
+#include <stdio.h>
+
+#include "barrier.h"
+
+void
+barrier_init(barrier_t *bar, int nthreads)
+{
+ pthread_mutex_init(&bar->bar_lock, NULL);
+#ifdef illumos
+ sema_init(&bar->bar_sem, 0, USYNC_THREAD, NULL);
+#else
+ sem_init(&bar->bar_sem, 0, 0);
+#endif
+
+ bar->bar_numin = 0;
+ bar->bar_nthr = nthreads;
+}
+
+int
+barrier_wait(barrier_t *bar)
+{
+ pthread_mutex_lock(&bar->bar_lock);
+
+ if (++bar->bar_numin < bar->bar_nthr) {
+ pthread_mutex_unlock(&bar->bar_lock);
+#ifdef illumos
+ sema_wait(&bar->bar_sem);
+#else
+ sem_wait(&bar->bar_sem);
+#endif
+
+ return (0);
+
+ } else {
+ int i;
+
+ /* reset for next use */
+ bar->bar_numin = 0;
+ for (i = 1; i < bar->bar_nthr; i++)
+#ifdef illumos
+ sema_post(&bar->bar_sem);
+#else
+ sem_post(&bar->bar_sem);
+#endif
+ pthread_mutex_unlock(&bar->bar_lock);
+
+ return (1);
+ }
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/barrier.h b/cddl/contrib/opensolaris/tools/ctf/cvt/barrier.h
new file mode 100644
index 000000000000..babf2e64e33f
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/barrier.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ *
+ * 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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _BARRIER_H
+#define _BARRIER_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * APIs for the barrier synchronization primitive.
+ */
+
+#ifdef illumos
+#include <synch.h>
+#else
+#include <semaphore.h>
+typedef sem_t sema_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct barrier {
+ pthread_mutex_t bar_lock; /* protects bar_numin */
+ int bar_numin; /* current number of waiters */
+
+ sema_t bar_sem; /* where everyone waits */
+ int bar_nthr; /* # of waiters to trigger release */
+} barrier_t;
+
+extern void barrier_init(barrier_t *, int);
+extern int barrier_wait(barrier_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BARRIER_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/compare.c b/cddl/contrib/opensolaris/tools/ctf/cvt/compare.c
new file mode 100644
index 000000000000..26037f8a537a
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/compare.c
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is a test program designed to catch mismerges and mistranslations from
+ * stabs to CTF.
+ *
+ * Given a file with stabs data and a file with CTF data, determine whether
+ * or not all of the data structures and objects described by the stabs data
+ * are present in the CTF data.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "ctftools.h"
+
+char *progname;
+int debug_level = DEBUG_LEVEL;
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: %s ctf_file stab_file\n", progname);
+}
+
+int
+main(int argc, char **argv)
+{
+ tdata_t *ctftd, *stabrtd, *stabtd, *difftd;
+ char *ctfname, *stabname;
+ int new;
+
+ progname = argv[0];
+
+ if (argc != 3) {
+ usage();
+ exit(2);
+ }
+
+ ctfname = argv[1];
+ stabname = argv[2];
+
+ stabrtd = tdata_new();
+ stabtd = tdata_new();
+ difftd = tdata_new();
+
+ if (read_stabs(stabrtd, stabname, 0) != 0)
+ merge_into_master(stabrtd, stabtd, NULL, 1);
+ else if (read_ctf(&stabname, 1, NULL, read_ctf_save_cb, &stabtd, 0)
+ == 0)
+ terminate("%s doesn't have stabs or CTF\n", stabname);
+
+ if (read_ctf(&ctfname, 1, NULL, read_ctf_save_cb, &ctftd, 0) == 0)
+ terminate("%s doesn't contain CTF data\n", ctfname);
+
+ merge_into_master(stabtd, ctftd, difftd, 0);
+
+ if ((new = hash_count(difftd->td_iihash)) != 0) {
+ (void) hash_iter(difftd->td_iihash, (int (*)())iidesc_dump,
+ NULL);
+ terminate("%s grew by %d\n", stabname, new);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c b/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c
new file mode 100644
index 000000000000..5cd2de9f43ea
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c
@@ -0,0 +1,1382 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Create and parse buffers containing CTF data.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <ctype.h>
+#include <zlib.h>
+#include <elf.h>
+
+#include "ctf_headers.h"
+#include "ctftools.h"
+#include "strtab.h"
+#include "memory.h"
+
+/*
+ * Name of the file currently being read, used to print error messages. We
+ * assume that only one file will be read at a time, and thus make no attempt
+ * to allow curfile to be used simultaneously by multiple threads.
+ *
+ * The value is only valid during a call to ctf_load.
+ */
+static char *curfile;
+
+#define CTF_BUF_CHUNK_SIZE (64 * 1024)
+#define RES_BUF_CHUNK_SIZE (64 * 1024)
+
+struct ctf_buf {
+ strtab_t ctb_strtab; /* string table */
+ caddr_t ctb_base; /* pointer to base of buffer */
+ caddr_t ctb_end; /* pointer to end of buffer */
+ caddr_t ctb_ptr; /* pointer to empty buffer space */
+ size_t ctb_size; /* size of buffer */
+ int nptent; /* number of processed types */
+ int ntholes; /* number of type holes */
+};
+
+/*
+ * Macros to reverse byte order
+ */
+#define BSWAP_8(x) ((x) & 0xff)
+#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
+#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
+
+#define SWAP_16(x) (x) = BSWAP_16(x)
+#define SWAP_32(x) (x) = BSWAP_32(x)
+
+static int target_requires_swap;
+
+/*PRINTFLIKE1*/
+static void
+parseterminate(const char *fmt, ...)
+{
+ static char msgbuf[1024]; /* sigh */
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof (msgbuf), fmt, ap);
+ va_end(ap);
+
+ terminate("%s: %s\n", curfile, msgbuf);
+}
+
+static void
+ctf_buf_grow(ctf_buf_t *b)
+{
+ off_t ptroff = b->ctb_ptr - b->ctb_base;
+
+ b->ctb_size += CTF_BUF_CHUNK_SIZE;
+ b->ctb_base = xrealloc(b->ctb_base, b->ctb_size);
+ b->ctb_end = b->ctb_base + b->ctb_size;
+ b->ctb_ptr = b->ctb_base + ptroff;
+}
+
+static ctf_buf_t *
+ctf_buf_new(void)
+{
+ ctf_buf_t *b = xcalloc(sizeof (ctf_buf_t));
+
+ strtab_create(&b->ctb_strtab);
+ ctf_buf_grow(b);
+
+ return (b);
+}
+
+static void
+ctf_buf_free(ctf_buf_t *b)
+{
+ strtab_destroy(&b->ctb_strtab);
+ free(b->ctb_base);
+ free(b);
+}
+
+static uint_t
+ctf_buf_cur(ctf_buf_t *b)
+{
+ return (b->ctb_ptr - b->ctb_base);
+}
+
+static void
+ctf_buf_write(ctf_buf_t *b, void const *p, size_t n)
+{
+ size_t len;
+
+ while (n != 0) {
+ if (b->ctb_ptr == b->ctb_end)
+ ctf_buf_grow(b);
+
+ len = MIN((size_t)(b->ctb_end - b->ctb_ptr), n);
+ bcopy(p, b->ctb_ptr, len);
+ b->ctb_ptr += len;
+
+ p = (char const *)p + len;
+ n -= len;
+ }
+}
+
+static int
+write_label(void *arg1, void *arg2)
+{
+ labelent_t *le = arg1;
+ ctf_buf_t *b = arg2;
+ ctf_lblent_t ctl;
+
+ ctl.ctl_label = strtab_insert(&b->ctb_strtab, le->le_name);
+ ctl.ctl_typeidx = le->le_idx;
+
+ if (target_requires_swap) {
+ SWAP_32(ctl.ctl_label);
+ SWAP_32(ctl.ctl_typeidx);
+ }
+
+ ctf_buf_write(b, &ctl, sizeof (ctl));
+
+ return (1);
+}
+
+static void
+write_objects(iidesc_t *idp, ctf_buf_t *b)
+{
+ ushort_t id = (idp ? idp->ii_dtype->t_id : 0);
+
+ if (target_requires_swap) {
+ SWAP_16(id);
+ }
+
+ ctf_buf_write(b, &id, sizeof (id));
+
+ debug(3, "Wrote object %s (%d)\n", (idp ? idp->ii_name : "(null)"), id);
+}
+
+static void
+write_functions(iidesc_t *idp, ctf_buf_t *b)
+{
+ ushort_t fdata[2];
+ ushort_t id;
+ int nargs;
+ int i;
+
+ if (!idp) {
+ fdata[0] = 0;
+ ctf_buf_write(b, &fdata[0], sizeof (fdata[0]));
+
+ debug(3, "Wrote function (null)\n");
+ return;
+ }
+
+ nargs = idp->ii_nargs + (idp->ii_vargs != 0);
+
+ if (nargs > CTF_MAX_VLEN) {
+ terminate("function %s has too many args: %d > %d\n",
+ idp->ii_name, nargs, CTF_MAX_VLEN);
+ }
+
+ fdata[0] = CTF_TYPE_INFO(CTF_K_FUNCTION, 1, nargs);
+ fdata[1] = idp->ii_dtype->t_id;
+
+ if (target_requires_swap) {
+ SWAP_16(fdata[0]);
+ SWAP_16(fdata[1]);
+ }
+
+ ctf_buf_write(b, fdata, sizeof (fdata));
+
+ for (i = 0; i < idp->ii_nargs; i++) {
+ id = idp->ii_args[i]->t_id;
+
+ if (target_requires_swap) {
+ SWAP_16(id);
+ }
+
+ ctf_buf_write(b, &id, sizeof (id));
+ }
+
+ if (idp->ii_vargs) {
+ id = 0;
+ ctf_buf_write(b, &id, sizeof (id));
+ }
+
+ debug(3, "Wrote function %s (%d args)\n", idp->ii_name, nargs);
+}
+
+/*
+ * Depending on the size of the type being described, either a ctf_stype_t (for
+ * types with size < CTF_LSTRUCT_THRESH) or a ctf_type_t (all others) will be
+ * written. We isolate the determination here so the rest of the writer code
+ * doesn't need to care.
+ */
+static void
+write_sized_type_rec(ctf_buf_t *b, ctf_type_t *ctt, size_t size)
+{
+ if (size > CTF_MAX_SIZE) {
+ ctt->ctt_size = CTF_LSIZE_SENT;
+ ctt->ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size);
+ ctt->ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size);
+ if (target_requires_swap) {
+ SWAP_32(ctt->ctt_name);
+ SWAP_16(ctt->ctt_info);
+ SWAP_16(ctt->ctt_size);
+ SWAP_32(ctt->ctt_lsizehi);
+ SWAP_32(ctt->ctt_lsizelo);
+ }
+ ctf_buf_write(b, ctt, sizeof (*ctt));
+ } else {
+ ctf_stype_t *cts = (ctf_stype_t *)ctt;
+
+ cts->ctt_size = (ushort_t)size;
+
+ if (target_requires_swap) {
+ SWAP_32(cts->ctt_name);
+ SWAP_16(cts->ctt_info);
+ SWAP_16(cts->ctt_size);
+ }
+
+ ctf_buf_write(b, cts, sizeof (*cts));
+ }
+}
+
+static void
+write_unsized_type_rec(ctf_buf_t *b, ctf_type_t *ctt)
+{
+ ctf_stype_t *cts = (ctf_stype_t *)ctt;
+
+ if (target_requires_swap) {
+ SWAP_32(cts->ctt_name);
+ SWAP_16(cts->ctt_info);
+ SWAP_16(cts->ctt_size);
+ }
+
+ ctf_buf_write(b, cts, sizeof (*cts));
+}
+
+static int
+write_type(void *arg1, void *arg2)
+{
+ tdesc_t *tp = arg1;
+ ctf_buf_t *b = arg2;
+ elist_t *ep;
+ mlist_t *mp;
+ intr_t *ip;
+
+ size_t offset;
+ uint_t encoding;
+ uint_t data;
+ int isroot = tp->t_flags & TDESC_F_ISROOT;
+ int i;
+
+ ctf_type_t ctt;
+ ctf_array_t cta;
+ ctf_member_t ctm;
+ ctf_lmember_t ctlm;
+ ctf_enum_t cte;
+ ushort_t id;
+
+ ctlm.ctlm_pad = 0;
+
+ /*
+ * There shouldn't be any holes in the type list (where a hole is
+ * defined as two consecutive tdescs without consecutive ids), but
+ * check for them just in case. If we do find holes, we need to make
+ * fake entries to fill the holes, or we won't be able to reconstruct
+ * the tree from the written data.
+ */
+ if (++b->nptent < CTF_TYPE_TO_INDEX(tp->t_id)) {
+ debug(2, "genctf: type hole from %d < x < %d\n",
+ b->nptent - 1, CTF_TYPE_TO_INDEX(tp->t_id));
+
+ ctt.ctt_name = CTF_TYPE_NAME(CTF_STRTAB_0, 0);
+ ctt.ctt_info = CTF_TYPE_INFO(0, 0, 0);
+ while (b->nptent < CTF_TYPE_TO_INDEX(tp->t_id)) {
+ write_sized_type_rec(b, &ctt, 0);
+ b->nptent++;
+ }
+ }
+
+ offset = strtab_insert(&b->ctb_strtab, tp->t_name);
+ ctt.ctt_name = CTF_TYPE_NAME(CTF_STRTAB_0, offset);
+
+ switch (tp->t_type) {
+ case INTRINSIC:
+ ip = tp->t_intr;
+ if (ip->intr_type == INTR_INT)
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_INTEGER,
+ isroot, 1);
+ else
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_FLOAT, isroot, 1);
+ write_sized_type_rec(b, &ctt, tp->t_size);
+
+ encoding = 0;
+
+ if (ip->intr_type == INTR_INT) {
+ if (ip->intr_signed)
+ encoding |= CTF_INT_SIGNED;
+ if (ip->intr_iformat == 'c')
+ encoding |= CTF_INT_CHAR;
+ else if (ip->intr_iformat == 'b')
+ encoding |= CTF_INT_BOOL;
+ else if (ip->intr_iformat == 'v')
+ encoding |= CTF_INT_VARARGS;
+ } else
+ encoding = ip->intr_fformat;
+
+ data = CTF_INT_DATA(encoding, ip->intr_offset, ip->intr_nbits);
+ if (target_requires_swap) {
+ SWAP_32(data);
+ }
+ ctf_buf_write(b, &data, sizeof (data));
+ break;
+
+ case POINTER:
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_POINTER, isroot, 0);
+ ctt.ctt_type = tp->t_tdesc->t_id;
+ write_unsized_type_rec(b, &ctt);
+ break;
+
+ case ARRAY:
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, isroot, 1);
+ write_sized_type_rec(b, &ctt, tp->t_size);
+
+ cta.cta_contents = tp->t_ardef->ad_contents->t_id;
+ cta.cta_index = tp->t_ardef->ad_idxtype->t_id;
+ cta.cta_nelems = tp->t_ardef->ad_nelems;
+ if (target_requires_swap) {
+ SWAP_16(cta.cta_contents);
+ SWAP_16(cta.cta_index);
+ SWAP_32(cta.cta_nelems);
+ }
+ ctf_buf_write(b, &cta, sizeof (cta));
+ break;
+
+ case STRUCT:
+ case UNION:
+ for (i = 0, mp = tp->t_members; mp != NULL; mp = mp->ml_next)
+ i++; /* count up struct or union members */
+
+ if (i > CTF_MAX_VLEN) {
+ terminate("sou %s has too many members: %d > %d\n",
+ tdesc_name(tp), i, CTF_MAX_VLEN);
+ }
+
+ if (tp->t_type == STRUCT)
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, isroot, i);
+ else
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, isroot, i);
+
+ write_sized_type_rec(b, &ctt, tp->t_size);
+
+ if (tp->t_size < CTF_LSTRUCT_THRESH) {
+ for (mp = tp->t_members; mp != NULL; mp = mp->ml_next) {
+ offset = strtab_insert(&b->ctb_strtab,
+ mp->ml_name);
+
+ ctm.ctm_name = CTF_TYPE_NAME(CTF_STRTAB_0,
+ offset);
+ ctm.ctm_type = mp->ml_type->t_id;
+ ctm.ctm_offset = mp->ml_offset;
+ if (target_requires_swap) {
+ SWAP_32(ctm.ctm_name);
+ SWAP_16(ctm.ctm_type);
+ SWAP_16(ctm.ctm_offset);
+ }
+ ctf_buf_write(b, &ctm, sizeof (ctm));
+ }
+ } else {
+ for (mp = tp->t_members; mp != NULL; mp = mp->ml_next) {
+ offset = strtab_insert(&b->ctb_strtab,
+ mp->ml_name);
+
+ ctlm.ctlm_name = CTF_TYPE_NAME(CTF_STRTAB_0,
+ offset);
+ ctlm.ctlm_type = mp->ml_type->t_id;
+ ctlm.ctlm_offsethi =
+ CTF_OFFSET_TO_LMEMHI(mp->ml_offset);
+ ctlm.ctlm_offsetlo =
+ CTF_OFFSET_TO_LMEMLO(mp->ml_offset);
+
+ if (target_requires_swap) {
+ SWAP_32(ctlm.ctlm_name);
+ SWAP_16(ctlm.ctlm_type);
+ SWAP_32(ctlm.ctlm_offsethi);
+ SWAP_32(ctlm.ctlm_offsetlo);
+ }
+
+ ctf_buf_write(b, &ctlm, sizeof (ctlm));
+ }
+ }
+ break;
+
+ case ENUM:
+ for (i = 0, ep = tp->t_emem; ep != NULL; ep = ep->el_next)
+ i++; /* count up enum members */
+
+ if (i > CTF_MAX_VLEN) {
+ i = CTF_MAX_VLEN;
+ }
+
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, isroot, i);
+ write_sized_type_rec(b, &ctt, tp->t_size);
+
+ for (ep = tp->t_emem; ep != NULL && i > 0; ep = ep->el_next) {
+ offset = strtab_insert(&b->ctb_strtab, ep->el_name);
+ cte.cte_name = CTF_TYPE_NAME(CTF_STRTAB_0, offset);
+ cte.cte_value = ep->el_number;
+
+ if (target_requires_swap) {
+ SWAP_32(cte.cte_name);
+ SWAP_32(cte.cte_value);
+ }
+
+ ctf_buf_write(b, &cte, sizeof (cte));
+ i--;
+ }
+ break;
+
+ case FORWARD:
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_FORWARD, isroot, 0);
+ ctt.ctt_type = 0;
+ write_unsized_type_rec(b, &ctt);
+ break;
+
+ case TYPEDEF:
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, isroot, 0);
+ ctt.ctt_type = tp->t_tdesc->t_id;
+ write_unsized_type_rec(b, &ctt);
+ break;
+
+ case VOLATILE:
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_VOLATILE, isroot, 0);
+ ctt.ctt_type = tp->t_tdesc->t_id;
+ write_unsized_type_rec(b, &ctt);
+ break;
+
+ case CONST:
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_CONST, isroot, 0);
+ ctt.ctt_type = tp->t_tdesc->t_id;
+ write_unsized_type_rec(b, &ctt);
+ break;
+
+ case FUNCTION:
+ i = tp->t_fndef->fn_nargs + tp->t_fndef->fn_vargs;
+
+ if (i > CTF_MAX_VLEN) {
+ terminate("function %s has too many args: %d > %d\n",
+ tdesc_name(tp), i, CTF_MAX_VLEN);
+ }
+
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, isroot, i);
+ ctt.ctt_type = tp->t_fndef->fn_ret->t_id;
+ write_unsized_type_rec(b, &ctt);
+
+ for (i = 0; i < (int) tp->t_fndef->fn_nargs; i++) {
+ id = tp->t_fndef->fn_args[i]->t_id;
+
+ if (target_requires_swap) {
+ SWAP_16(id);
+ }
+
+ ctf_buf_write(b, &id, sizeof (id));
+ }
+
+ if (tp->t_fndef->fn_vargs) {
+ id = 0;
+ ctf_buf_write(b, &id, sizeof (id));
+ i++;
+ }
+
+ if (i & 1) {
+ id = 0;
+ ctf_buf_write(b, &id, sizeof (id));
+ }
+ break;
+
+ case RESTRICT:
+ ctt.ctt_info = CTF_TYPE_INFO(CTF_K_RESTRICT, isroot, 0);
+ ctt.ctt_type = tp->t_tdesc->t_id;
+ write_unsized_type_rec(b, &ctt);
+ break;
+
+ default:
+ warning("Can't write unknown type %d\n", tp->t_type);
+ }
+
+ debug(3, "Wrote type %d %s\n", tp->t_id, tdesc_name(tp));
+
+ return (1);
+}
+
+typedef struct resbuf {
+ caddr_t rb_base;
+ caddr_t rb_ptr;
+ size_t rb_size;
+ z_stream rb_zstr;
+} resbuf_t;
+
+static void
+rbzs_grow(resbuf_t *rb)
+{
+ off_t ptroff = (caddr_t)rb->rb_zstr.next_out - rb->rb_base;
+
+ rb->rb_size += RES_BUF_CHUNK_SIZE;
+ rb->rb_base = xrealloc(rb->rb_base, rb->rb_size);
+ rb->rb_ptr = rb->rb_base + ptroff;
+ rb->rb_zstr.next_out = (Bytef *)(rb->rb_ptr);
+ rb->rb_zstr.avail_out += RES_BUF_CHUNK_SIZE;
+}
+
+static void
+compress_start(resbuf_t *rb)
+{
+ int rc;
+
+ rb->rb_zstr.zalloc = (alloc_func)0;
+ rb->rb_zstr.zfree = (free_func)0;
+ rb->rb_zstr.opaque = (voidpf)0;
+
+ if ((rc = deflateInit(&rb->rb_zstr, Z_BEST_COMPRESSION)) != Z_OK)
+ parseterminate("zlib start failed: %s", zError(rc));
+}
+
+static ssize_t
+compress_buffer(void *buf, size_t n, void *data)
+{
+ resbuf_t *rb = (resbuf_t *)data;
+ int rc;
+
+ rb->rb_zstr.next_out = (Bytef *)rb->rb_ptr;
+ rb->rb_zstr.avail_out = rb->rb_size - (rb->rb_ptr - rb->rb_base);
+ rb->rb_zstr.next_in = buf;
+ rb->rb_zstr.avail_in = n;
+
+ while (rb->rb_zstr.avail_in) {
+ if (rb->rb_zstr.avail_out == 0)
+ rbzs_grow(rb);
+
+ if ((rc = deflate(&rb->rb_zstr, Z_NO_FLUSH)) != Z_OK)
+ parseterminate("zlib deflate failed: %s", zError(rc));
+ }
+ rb->rb_ptr = (caddr_t)rb->rb_zstr.next_out;
+
+ return (n);
+}
+
+static void
+compress_flush(resbuf_t *rb, int type)
+{
+ int rc;
+
+ for (;;) {
+ if (rb->rb_zstr.avail_out == 0)
+ rbzs_grow(rb);
+
+ rc = deflate(&rb->rb_zstr, type);
+ if ((type == Z_FULL_FLUSH && rc == Z_BUF_ERROR) ||
+ (type == Z_FINISH && rc == Z_STREAM_END))
+ break;
+ else if (rc != Z_OK)
+ parseterminate("zlib finish failed: %s", zError(rc));
+ }
+ rb->rb_ptr = (caddr_t)rb->rb_zstr.next_out;
+}
+
+static void
+compress_end(resbuf_t *rb)
+{
+ int rc;
+
+ compress_flush(rb, Z_FINISH);
+
+ if ((rc = deflateEnd(&rb->rb_zstr)) != Z_OK)
+ parseterminate("zlib end failed: %s", zError(rc));
+}
+
+/*
+ * Pad the buffer to a power-of-2 boundary
+ */
+static void
+pad_buffer(ctf_buf_t *buf, int align)
+{
+ uint_t cur = ctf_buf_cur(buf);
+ ssize_t topad = (align - (cur % align)) % align;
+ static const char pad[8] = { 0 };
+
+ while (topad > 0) {
+ ctf_buf_write(buf, pad, (topad > 8 ? 8 : topad));
+ topad -= 8;
+ }
+}
+
+static ssize_t
+bcopy_data(void *buf, size_t n, void *data)
+{
+ caddr_t *posp = (caddr_t *)data;
+ bcopy(buf, *posp, n);
+ *posp += n;
+ return (n);
+}
+
+static caddr_t
+write_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp)
+{
+ caddr_t outbuf;
+ caddr_t bufpos;
+
+ outbuf = xmalloc(sizeof (ctf_header_t) + (buf->ctb_ptr - buf->ctb_base)
+ + buf->ctb_strtab.str_size);
+
+ bufpos = outbuf;
+ (void) bcopy_data(h, sizeof (ctf_header_t), &bufpos);
+ (void) bcopy_data(buf->ctb_base, buf->ctb_ptr - buf->ctb_base,
+ &bufpos);
+ (void) strtab_write(&buf->ctb_strtab, bcopy_data, &bufpos);
+ *resszp = bufpos - outbuf;
+ return (outbuf);
+}
+
+/*
+ * Create the compression buffer, and fill it with the CTF and string
+ * table data. We flush the compression state between the two so the
+ * dictionary used for the string tables won't be polluted with values
+ * that made sense for the CTF data.
+ */
+static caddr_t
+write_compressed_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp)
+{
+ resbuf_t resbuf;
+ resbuf.rb_size = RES_BUF_CHUNK_SIZE;
+ resbuf.rb_base = xmalloc(resbuf.rb_size);
+ bcopy(h, resbuf.rb_base, sizeof (ctf_header_t));
+ resbuf.rb_ptr = resbuf.rb_base + sizeof (ctf_header_t);
+
+ compress_start(&resbuf);
+ (void) compress_buffer(buf->ctb_base, buf->ctb_ptr - buf->ctb_base,
+ &resbuf);
+ compress_flush(&resbuf, Z_FULL_FLUSH);
+ (void) strtab_write(&buf->ctb_strtab, compress_buffer, &resbuf);
+ compress_end(&resbuf);
+
+ *resszp = (resbuf.rb_ptr - resbuf.rb_base);
+ return (resbuf.rb_base);
+}
+
+caddr_t
+ctf_gen(iiburst_t *iiburst, size_t *resszp, int do_compress)
+{
+ ctf_buf_t *buf = ctf_buf_new();
+ ctf_header_t h;
+ caddr_t outbuf;
+
+ int i;
+
+ target_requires_swap = do_compress & CTF_SWAP_BYTES;
+ do_compress &= ~CTF_SWAP_BYTES;
+
+ /*
+ * Prepare the header, and create the CTF output buffers. The data
+ * object section and function section are both lists of 2-byte
+ * integers; we pad these out to the next 4-byte boundary if needed.
+ */
+ h.cth_magic = CTF_MAGIC;
+ h.cth_version = CTF_VERSION;
+ h.cth_flags = do_compress ? CTF_F_COMPRESS : 0;
+ h.cth_parlabel = strtab_insert(&buf->ctb_strtab,
+ iiburst->iib_td->td_parlabel);
+ h.cth_parname = strtab_insert(&buf->ctb_strtab,
+ iiburst->iib_td->td_parname);
+
+ h.cth_lbloff = 0;
+ (void) list_iter(iiburst->iib_td->td_labels, write_label,
+ buf);
+
+ pad_buffer(buf, 2);
+ h.cth_objtoff = ctf_buf_cur(buf);
+ for (i = 0; i < iiburst->iib_nobjts; i++)
+ write_objects(iiburst->iib_objts[i], buf);
+
+ pad_buffer(buf, 2);
+ h.cth_funcoff = ctf_buf_cur(buf);
+ for (i = 0; i < iiburst->iib_nfuncs; i++)
+ write_functions(iiburst->iib_funcs[i], buf);
+
+ pad_buffer(buf, 4);
+ h.cth_typeoff = ctf_buf_cur(buf);
+ (void) list_iter(iiburst->iib_types, write_type, buf);
+
+ debug(2, "CTF wrote %d types\n", list_count(iiburst->iib_types));
+
+ h.cth_stroff = ctf_buf_cur(buf);
+ h.cth_strlen = strtab_size(&buf->ctb_strtab);
+
+ if (target_requires_swap) {
+ SWAP_16(h.cth_preamble.ctp_magic);
+ SWAP_32(h.cth_parlabel);
+ SWAP_32(h.cth_parname);
+ SWAP_32(h.cth_lbloff);
+ SWAP_32(h.cth_objtoff);
+ SWAP_32(h.cth_funcoff);
+ SWAP_32(h.cth_typeoff);
+ SWAP_32(h.cth_stroff);
+ SWAP_32(h.cth_strlen);
+ }
+
+ /*
+ * We only do compression for ctfmerge, as ctfconvert is only
+ * supposed to be used on intermediary build objects. This is
+ * significantly faster.
+ */
+ if (do_compress)
+ outbuf = write_compressed_buffer(&h, buf, resszp);
+ else
+ outbuf = write_buffer(&h, buf, resszp);
+
+ ctf_buf_free(buf);
+ return (outbuf);
+}
+
+static void
+get_ctt_size(ctf_type_t *ctt, size_t *sizep, size_t *incrementp)
+{
+ if (ctt->ctt_size == CTF_LSIZE_SENT) {
+ *sizep = (size_t)CTF_TYPE_LSIZE(ctt);
+ *incrementp = sizeof (ctf_type_t);
+ } else {
+ *sizep = ctt->ctt_size;
+ *incrementp = sizeof (ctf_stype_t);
+ }
+}
+
+static int
+count_types(ctf_header_t *h, caddr_t data)
+{
+ caddr_t dptr = data + h->cth_typeoff;
+ int count = 0;
+
+ dptr = data + h->cth_typeoff;
+ while (dptr < data + h->cth_stroff) {
+ void *v = (void *) dptr;
+ ctf_type_t *ctt = v;
+ size_t vlen = CTF_INFO_VLEN(ctt->ctt_info);
+ size_t size, increment;
+
+ get_ctt_size(ctt, &size, &increment);
+
+ switch (CTF_INFO_KIND(ctt->ctt_info)) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ dptr += 4;
+ break;
+ case CTF_K_POINTER:
+ case CTF_K_FORWARD:
+ case CTF_K_TYPEDEF:
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ case CTF_K_FUNCTION:
+ dptr += sizeof (ushort_t) * (vlen + (vlen & 1));
+ break;
+ case CTF_K_ARRAY:
+ dptr += sizeof (ctf_array_t);
+ break;
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ if (size < CTF_LSTRUCT_THRESH)
+ dptr += sizeof (ctf_member_t) * vlen;
+ else
+ dptr += sizeof (ctf_lmember_t) * vlen;
+ break;
+ case CTF_K_ENUM:
+ dptr += sizeof (ctf_enum_t) * vlen;
+ break;
+ case CTF_K_UNKNOWN:
+ break;
+ default:
+ parseterminate("Unknown CTF type %d (#%d) at %#x",
+ CTF_INFO_KIND(ctt->ctt_info), count, dptr - data);
+ }
+
+ dptr += increment;
+ count++;
+ }
+
+ debug(3, "CTF read %d types\n", count);
+
+ return (count);
+}
+
+/*
+ * Resurrect the labels stored in the CTF data, returning the index associated
+ * with a label provided by the caller. There are several cases, outlined
+ * below. Note that, given two labels, the one associated with the lesser type
+ * index is considered to be older than the other.
+ *
+ * 1. matchlbl == NULL - return the index of the most recent label.
+ * 2. matchlbl == "BASE" - return the index of the oldest label.
+ * 3. matchlbl != NULL, but doesn't match any labels in the section - warn
+ * the user, and proceed as if matchlbl == "BASE" (for safety).
+ * 4. matchlbl != NULL, and matches one of the labels in the section - return
+ * the type index associated with the label.
+ */
+static int
+resurrect_labels(ctf_header_t *h, tdata_t *td, caddr_t ctfdata, char *matchlbl)
+{
+ caddr_t buf = ctfdata + h->cth_lbloff;
+ caddr_t sbuf = ctfdata + h->cth_stroff;
+ size_t bufsz = h->cth_objtoff - h->cth_lbloff;
+ int lastidx = 0, baseidx = -1;
+ char *baselabel = NULL;
+ ctf_lblent_t *ctl;
+ void *v = (void *) buf;
+
+ for (ctl = v; (caddr_t)ctl < buf + bufsz; ctl++) {
+ char *label = sbuf + ctl->ctl_label;
+
+ lastidx = ctl->ctl_typeidx;
+
+ debug(3, "Resurrected label %s type idx %d\n", label, lastidx);
+
+ tdata_label_add(td, label, lastidx);
+
+ if (baseidx == -1) {
+ baseidx = lastidx;
+ baselabel = label;
+ if (matchlbl != NULL && streq(matchlbl, "BASE"))
+ return (lastidx);
+ }
+
+ if (matchlbl != NULL && streq(label, matchlbl))
+ return (lastidx);
+ }
+
+ if (matchlbl != NULL) {
+ /* User provided a label that didn't match */
+ warning("%s: Cannot find label `%s' - using base (%s)\n",
+ curfile, matchlbl, (baselabel ? baselabel : "NONE"));
+
+ tdata_label_free(td);
+ tdata_label_add(td, baselabel, baseidx);
+
+ return (baseidx);
+ }
+
+ return (lastidx);
+}
+
+static void
+resurrect_objects(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
+ caddr_t ctfdata, symit_data_t *si)
+{
+ caddr_t buf = ctfdata + h->cth_objtoff;
+ size_t bufsz = h->cth_funcoff - h->cth_objtoff;
+ caddr_t dptr;
+
+ symit_reset(si);
+ for (dptr = buf; dptr < buf + bufsz; dptr += 2) {
+ void *v = (void *) dptr;
+ ushort_t id = *((ushort_t *)v);
+ iidesc_t *ii;
+ GElf_Sym *sym;
+
+ if (!(sym = symit_next(si, STT_OBJECT)) && id != 0) {
+ parseterminate(
+ "Unexpected end of object symbols at %x of %x",
+ dptr - buf, bufsz);
+ }
+
+ if (id == 0) {
+ debug(3, "Skipping null object\n");
+ continue;
+ } else if (id >= tdsize) {
+ parseterminate("Reference to invalid type %d", id);
+ }
+
+ ii = iidesc_new(symit_name(si));
+ ii->ii_dtype = tdarr[id];
+ if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) {
+ ii->ii_type = II_SVAR;
+ ii->ii_owner = xstrdup(symit_curfile(si));
+ } else
+ ii->ii_type = II_GVAR;
+ hash_add(td->td_iihash, ii);
+
+ debug(3, "Resurrected %s object %s (%d) from %s\n",
+ (ii->ii_type == II_GVAR ? "global" : "static"),
+ ii->ii_name, id, (ii->ii_owner ? ii->ii_owner : "(none)"));
+ }
+}
+
+static void
+resurrect_functions(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
+ caddr_t ctfdata, symit_data_t *si)
+{
+ caddr_t buf = ctfdata + h->cth_funcoff;
+ size_t bufsz = h->cth_typeoff - h->cth_funcoff;
+ caddr_t dptr = buf;
+ iidesc_t *ii;
+ ushort_t info;
+ ushort_t retid;
+ GElf_Sym *sym;
+ int i;
+
+ symit_reset(si);
+ while (dptr < buf + bufsz) {
+ void *v = (void *) dptr;
+ info = *((ushort_t *)v);
+ dptr += 2;
+
+ if (!(sym = symit_next(si, STT_FUNC)) && info != 0)
+ parseterminate("Unexpected end of function symbols");
+
+ if (info == 0) {
+ debug(3, "Skipping null function (%s)\n",
+ symit_name(si));
+ continue;
+ }
+
+ v = (void *) dptr;
+ retid = *((ushort_t *)v);
+ dptr += 2;
+
+ if (retid >= tdsize)
+ parseterminate("Reference to invalid type %d", retid);
+
+ ii = iidesc_new(symit_name(si));
+ ii->ii_dtype = tdarr[retid];
+ if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) {
+ ii->ii_type = II_SFUN;
+ ii->ii_owner = xstrdup(symit_curfile(si));
+ } else
+ ii->ii_type = II_GFUN;
+ ii->ii_nargs = CTF_INFO_VLEN(info);
+ if (ii->ii_nargs)
+ ii->ii_args =
+ xmalloc(sizeof (tdesc_t *) * ii->ii_nargs);
+
+ for (i = 0; i < ii->ii_nargs; i++, dptr += 2) {
+ v = (void *) dptr;
+ ushort_t id = *((ushort_t *)v);
+ if (id >= tdsize)
+ parseterminate("Reference to invalid type %d",
+ id);
+ ii->ii_args[i] = tdarr[id];
+ }
+
+ if (ii->ii_nargs && ii->ii_args[ii->ii_nargs - 1] == NULL) {
+ ii->ii_nargs--;
+ ii->ii_vargs = 1;
+ }
+
+ hash_add(td->td_iihash, ii);
+
+ debug(3, "Resurrected %s function %s (%d, %d args)\n",
+ (ii->ii_type == II_GFUN ? "global" : "static"),
+ ii->ii_name, retid, ii->ii_nargs);
+ }
+}
+
+static void
+resurrect_types(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
+ caddr_t ctfdata, int maxid)
+{
+ caddr_t buf = ctfdata + h->cth_typeoff;
+ size_t bufsz = h->cth_stroff - h->cth_typeoff;
+ caddr_t sbuf = ctfdata + h->cth_stroff;
+ caddr_t dptr = buf;
+ tdesc_t *tdp;
+ uint_t data;
+ uint_t encoding;
+ size_t size, increment;
+ int tcnt;
+ int iicnt = 0;
+ tid_t tid, argid;
+ int kind, vlen;
+ int i;
+
+ elist_t **epp;
+ mlist_t **mpp;
+ intr_t *ip;
+
+ ctf_type_t *ctt;
+ ctf_array_t *cta;
+ ctf_enum_t *cte;
+
+ /*
+ * A maxid of zero indicates a request to resurrect all types, so reset
+ * maxid to the maximum type id.
+ */
+ if (maxid == 0)
+ maxid = CTF_MAX_TYPE;
+
+ for (dptr = buf, tcnt = 0, tid = 1; dptr < buf + bufsz; tcnt++, tid++) {
+ if (tid > maxid)
+ break;
+
+ if (tid >= tdsize)
+ parseterminate("Reference to invalid type %d", tid);
+
+ void *v = (void *) dptr;
+ ctt = v;
+
+ get_ctt_size(ctt, &size, &increment);
+ dptr += increment;
+
+ tdp = tdarr[tid];
+
+ if (CTF_NAME_STID(ctt->ctt_name) != CTF_STRTAB_0)
+ parseterminate(
+ "Unable to cope with non-zero strtab id");
+ if (CTF_NAME_OFFSET(ctt->ctt_name) != 0) {
+ tdp->t_name =
+ xstrdup(sbuf + CTF_NAME_OFFSET(ctt->ctt_name));
+ } else
+ tdp->t_name = NULL;
+
+ kind = CTF_INFO_KIND(ctt->ctt_info);
+ vlen = CTF_INFO_VLEN(ctt->ctt_info);
+
+ switch (kind) {
+ case CTF_K_INTEGER:
+ tdp->t_type = INTRINSIC;
+ tdp->t_size = size;
+
+ v = (void *) dptr;
+ data = *((uint_t *)v);
+ dptr += sizeof (uint_t);
+ encoding = CTF_INT_ENCODING(data);
+
+ ip = xmalloc(sizeof (intr_t));
+ ip->intr_type = INTR_INT;
+ ip->intr_signed = (encoding & CTF_INT_SIGNED) ? 1 : 0;
+
+ if (encoding & CTF_INT_CHAR)
+ ip->intr_iformat = 'c';
+ else if (encoding & CTF_INT_BOOL)
+ ip->intr_iformat = 'b';
+ else if (encoding & CTF_INT_VARARGS)
+ ip->intr_iformat = 'v';
+ else
+ ip->intr_iformat = '\0';
+
+ ip->intr_offset = CTF_INT_OFFSET(data);
+ ip->intr_nbits = CTF_INT_BITS(data);
+ tdp->t_intr = ip;
+ break;
+
+ case CTF_K_FLOAT:
+ tdp->t_type = INTRINSIC;
+ tdp->t_size = size;
+
+ v = (void *) dptr;
+ data = *((uint_t *)v);
+ dptr += sizeof (uint_t);
+
+ ip = xcalloc(sizeof (intr_t));
+ ip->intr_type = INTR_REAL;
+ ip->intr_fformat = CTF_FP_ENCODING(data);
+ ip->intr_offset = CTF_FP_OFFSET(data);
+ ip->intr_nbits = CTF_FP_BITS(data);
+ tdp->t_intr = ip;
+ break;
+
+ case CTF_K_POINTER:
+ tdp->t_type = POINTER;
+ tdp->t_tdesc = tdarr[ctt->ctt_type];
+ break;
+
+ case CTF_K_ARRAY:
+ tdp->t_type = ARRAY;
+ tdp->t_size = size;
+
+ v = (void *) dptr;
+ cta = v;
+ dptr += sizeof (ctf_array_t);
+
+ tdp->t_ardef = xmalloc(sizeof (ardef_t));
+ tdp->t_ardef->ad_contents = tdarr[cta->cta_contents];
+ tdp->t_ardef->ad_idxtype = tdarr[cta->cta_index];
+ tdp->t_ardef->ad_nelems = cta->cta_nelems;
+ break;
+
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ tdp->t_type = (kind == CTF_K_STRUCT ? STRUCT : UNION);
+ tdp->t_size = size;
+
+ if (size < CTF_LSTRUCT_THRESH) {
+ for (i = 0, mpp = &tdp->t_members; i < vlen;
+ i++, mpp = &((*mpp)->ml_next)) {
+ v = (void *) dptr;
+ ctf_member_t *ctm = v;
+ dptr += sizeof (ctf_member_t);
+
+ *mpp = xmalloc(sizeof (mlist_t));
+ (*mpp)->ml_name = xstrdup(sbuf +
+ ctm->ctm_name);
+ (*mpp)->ml_type = tdarr[ctm->ctm_type];
+ (*mpp)->ml_offset = ctm->ctm_offset;
+ (*mpp)->ml_size = 0;
+ }
+ } else {
+ for (i = 0, mpp = &tdp->t_members; i < vlen;
+ i++, mpp = &((*mpp)->ml_next)) {
+ v = (void *) dptr;
+ ctf_lmember_t *ctlm = v;
+ dptr += sizeof (ctf_lmember_t);
+
+ *mpp = xmalloc(sizeof (mlist_t));
+ (*mpp)->ml_name = xstrdup(sbuf +
+ ctlm->ctlm_name);
+ (*mpp)->ml_type =
+ tdarr[ctlm->ctlm_type];
+ (*mpp)->ml_offset =
+ (int)CTF_LMEM_OFFSET(ctlm);
+ (*mpp)->ml_size = 0;
+ }
+ }
+
+ *mpp = NULL;
+ break;
+
+ case CTF_K_ENUM:
+ tdp->t_type = ENUM;
+ tdp->t_size = size;
+
+ for (i = 0, epp = &tdp->t_emem; i < vlen;
+ i++, epp = &((*epp)->el_next)) {
+ v = (void *) dptr;
+ cte = v;
+ dptr += sizeof (ctf_enum_t);
+
+ *epp = xmalloc(sizeof (elist_t));
+ (*epp)->el_name = xstrdup(sbuf + cte->cte_name);
+ (*epp)->el_number = cte->cte_value;
+ }
+ *epp = NULL;
+ break;
+
+ case CTF_K_FORWARD:
+ tdp->t_type = FORWARD;
+ list_add(&td->td_fwdlist, tdp);
+ break;
+
+ case CTF_K_TYPEDEF:
+ tdp->t_type = TYPEDEF;
+ tdp->t_tdesc = tdarr[ctt->ctt_type];
+ break;
+
+ case CTF_K_VOLATILE:
+ tdp->t_type = VOLATILE;
+ tdp->t_tdesc = tdarr[ctt->ctt_type];
+ break;
+
+ case CTF_K_CONST:
+ tdp->t_type = CONST;
+ tdp->t_tdesc = tdarr[ctt->ctt_type];
+ break;
+
+ case CTF_K_FUNCTION:
+ tdp->t_type = FUNCTION;
+ tdp->t_fndef = xcalloc(sizeof (fndef_t));
+ tdp->t_fndef->fn_ret = tdarr[ctt->ctt_type];
+
+ v = (void *) (dptr + (sizeof (ushort_t) * (vlen - 1)));
+ if (vlen > 0 && *(ushort_t *)v == 0)
+ tdp->t_fndef->fn_vargs = 1;
+
+ tdp->t_fndef->fn_nargs = vlen - tdp->t_fndef->fn_vargs;
+ tdp->t_fndef->fn_args = xcalloc(sizeof (tdesc_t) *
+ vlen - tdp->t_fndef->fn_vargs);
+
+ for (i = 0; i < vlen; i++) {
+ v = (void *) dptr;
+ argid = *(ushort_t *)v;
+ dptr += sizeof (ushort_t);
+
+ if (argid != 0)
+ tdp->t_fndef->fn_args[i] = tdarr[argid];
+ }
+
+ if (vlen & 1)
+ dptr += sizeof (ushort_t);
+ break;
+
+ case CTF_K_RESTRICT:
+ tdp->t_type = RESTRICT;
+ tdp->t_tdesc = tdarr[ctt->ctt_type];
+ break;
+
+ case CTF_K_UNKNOWN:
+ break;
+
+ default:
+ warning("Can't parse unknown CTF type %d\n", kind);
+ }
+
+ if (CTF_INFO_ISROOT(ctt->ctt_info)) {
+ iidesc_t *ii = iidesc_new(tdp->t_name);
+ if (tdp->t_type == STRUCT || tdp->t_type == UNION ||
+ tdp->t_type == ENUM)
+ ii->ii_type = II_SOU;
+ else
+ ii->ii_type = II_TYPE;
+ ii->ii_dtype = tdp;
+ hash_add(td->td_iihash, ii);
+
+ iicnt++;
+ }
+
+ debug(3, "Resurrected %d %stype %s (%d)\n", tdp->t_type,
+ (CTF_INFO_ISROOT(ctt->ctt_info) ? "root " : ""),
+ tdesc_name(tdp), tdp->t_id);
+ }
+
+ debug(3, "Resurrected %d types (%d were roots)\n", tcnt, iicnt);
+}
+
+/*
+ * For lack of other inspiration, we're going to take the boring route. We
+ * count the number of types. This lets us malloc that many tdesc structs
+ * before we start filling them in. This has the advantage of allowing us to
+ * avoid a merge-esque remap step.
+ */
+static tdata_t *
+ctf_parse(ctf_header_t *h, caddr_t buf, symit_data_t *si, char *label)
+{
+ tdata_t *td = tdata_new();
+ tdesc_t **tdarr;
+ int ntypes = count_types(h, buf);
+ int idx, i;
+
+ /* shudder */
+ tdarr = xcalloc(sizeof (tdesc_t *) * (ntypes + 1));
+ tdarr[0] = NULL;
+ for (i = 1; i <= ntypes; i++) {
+ tdarr[i] = xcalloc(sizeof (tdesc_t));
+ tdarr[i]->t_id = i;
+ }
+
+ td->td_parlabel = xstrdup(buf + h->cth_stroff + h->cth_parlabel);
+
+ /* we have the technology - we can rebuild them */
+ idx = resurrect_labels(h, td, buf, label);
+
+ resurrect_objects(h, td, tdarr, ntypes + 1, buf, si);
+ resurrect_functions(h, td, tdarr, ntypes + 1, buf, si);
+ resurrect_types(h, td, tdarr, ntypes + 1, buf, idx);
+
+ free(tdarr);
+
+ td->td_nextid = ntypes + 1;
+
+ return (td);
+}
+
+static size_t
+decompress_ctf(caddr_t cbuf, size_t cbufsz, caddr_t dbuf, size_t dbufsz)
+{
+ z_stream zstr;
+ int rc;
+
+ zstr.zalloc = (alloc_func)0;
+ zstr.zfree = (free_func)0;
+ zstr.opaque = (voidpf)0;
+
+ zstr.next_in = (Bytef *)cbuf;
+ zstr.avail_in = cbufsz;
+ zstr.next_out = (Bytef *)dbuf;
+ zstr.avail_out = dbufsz;
+
+ if ((rc = inflateInit(&zstr)) != Z_OK ||
+ (rc = inflate(&zstr, Z_NO_FLUSH)) != Z_STREAM_END ||
+ (rc = inflateEnd(&zstr)) != Z_OK) {
+ warning("CTF decompress zlib error %s\n", zError(rc));
+ return (0);
+ }
+
+ debug(3, "reflated %lu bytes to %lu, pointer at %d\n",
+ zstr.total_in, zstr.total_out, (caddr_t)zstr.next_in - cbuf);
+
+ return (zstr.total_out);
+}
+
+/*
+ * Reconstruct the type tree from a given buffer of CTF data. Only the types
+ * up to the type associated with the provided label, inclusive, will be
+ * reconstructed. If a NULL label is provided, all types will be reconstructed.
+ *
+ * This function won't work on files that have been uniquified.
+ */
+tdata_t *
+ctf_load(char *file, caddr_t buf, size_t bufsz, symit_data_t *si, char *label)
+{
+ ctf_header_t *h;
+ caddr_t ctfdata;
+ size_t ctfdatasz;
+ tdata_t *td;
+
+ curfile = file;
+
+ if (bufsz < sizeof (ctf_header_t))
+ parseterminate("Corrupt CTF - short header");
+
+ void *v = (void *) buf;
+ h = v;
+ buf += sizeof (ctf_header_t);
+ bufsz -= sizeof (ctf_header_t);
+
+ if (h->cth_magic != CTF_MAGIC)
+ parseterminate("Corrupt CTF - bad magic 0x%x", h->cth_magic);
+
+ if (h->cth_version != CTF_VERSION)
+ parseterminate("Unknown CTF version %d", h->cth_version);
+
+ ctfdatasz = h->cth_stroff + h->cth_strlen;
+ if (h->cth_flags & CTF_F_COMPRESS) {
+ size_t actual;
+
+ ctfdata = xmalloc(ctfdatasz);
+ if ((actual = decompress_ctf(buf, bufsz, ctfdata, ctfdatasz)) !=
+ ctfdatasz) {
+ parseterminate("Corrupt CTF - short decompression "
+ "(was %d, expecting %d)", actual, ctfdatasz);
+ }
+ } else {
+ ctfdata = buf;
+ ctfdatasz = bufsz;
+ }
+
+ td = ctf_parse(h, ctfdata, si, label);
+
+ if (h->cth_flags & CTF_F_COMPRESS)
+ free(ctfdata);
+
+ curfile = NULL;
+
+ return (td);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctfconvert.c b/cddl/contrib/opensolaris/tools/ctf/cvt/ctfconvert.c
new file mode 100644
index 000000000000..d40be25da27f
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctfconvert.c
@@ -0,0 +1,263 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Given a file containing sections with stabs data, convert the stabs data to
+ * CTF data, and replace the stabs sections with a CTF section.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "ctftools.h"
+#include "memory.h"
+
+const char *progname;
+int debug_level = DEBUG_LEVEL;
+
+static char *infile = NULL;
+static const char *outfile = NULL;
+static int dynsym;
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr,
+ "Usage: %s [-gis] -l label | -L labelenv [-o outfile] object_file\n"
+ "\n"
+ " Note: if -L labelenv is specified and labelenv is not set in\n"
+ " the environment, a default value is used.\n",
+ progname);
+}
+
+static void
+terminate_cleanup(void)
+{
+#if !defined(__FreeBSD__)
+ if (!outfile) {
+ fprintf(stderr, "Removing %s\n", infile);
+ unlink(infile);
+ }
+#endif
+}
+
+static void
+handle_sig(int sig)
+{
+ terminate("Caught signal %d - exiting\n", sig);
+}
+
+static int
+file_read(tdata_t *td, char *filename, int ignore_non_c)
+{
+ typedef int (*reader_f)(tdata_t *, Elf *, char *);
+ static reader_f readers[] = {
+ stabs_read,
+ dw_read,
+ NULL
+ };
+
+ source_types_t source_types;
+ Elf *elf;
+ int i, rc, fd;
+
+ if ((fd = open(filename, O_RDONLY)) < 0)
+ terminate("failed to open %s", filename);
+
+ (void) elf_version(EV_CURRENT);
+
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
+ close(fd);
+ terminate("failed to read %s: %s\n", filename,
+ elf_errmsg(-1));
+ }
+
+ source_types = built_source_types(elf, filename);
+
+ if ((source_types == SOURCE_NONE || (source_types & SOURCE_UNKNOWN)) &&
+ ignore_non_c) {
+ debug(1, "Ignoring file %s from unknown sources\n", filename);
+ exit(0);
+ }
+
+ for (i = 0; readers[i] != NULL; i++) {
+ if ((rc = readers[i](td, elf, filename)) == 0)
+ break;
+
+ assert(rc < 0 && errno == ENOENT);
+ }
+
+ if (readers[i] == NULL) {
+ /*
+ * None of the readers found compatible type data.
+ */
+
+ if (findelfsecidx(elf, filename, ".debug") >= 0) {
+ terminate("%s: DWARF version 1 is not supported\n",
+ filename);
+ }
+
+ if (!(source_types & SOURCE_C) && ignore_non_c) {
+ debug(1, "Ignoring file %s not built from C sources\n",
+ filename);
+ exit(0);
+ }
+
+ rc = 0;
+ } else {
+ rc = 1;
+ }
+
+ (void) elf_end(elf);
+ (void) close(fd);
+
+ return (rc);
+}
+
+int
+main(int argc, char **argv)
+{
+ tdata_t *filetd, *mstrtd;
+ const char *label = NULL;
+ int verbose = 0;
+ int ignore_non_c = 0;
+ int keep_stabs = 0;
+ int c;
+
+#ifdef illumos
+ sighold(SIGINT);
+ sighold(SIGQUIT);
+ sighold(SIGTERM);
+#endif
+
+ progname = basename(argv[0]);
+
+ if (getenv("CTFCONVERT_DEBUG_LEVEL"))
+ debug_level = atoi(getenv("CTFCONVERT_DEBUG_LEVEL"));
+ if (getenv("CTFCONVERT_DEBUG_PARSE"))
+ debug_parse = atoi(getenv("CTFCONVERT_DEBUG_PARSE"));
+
+ while ((c = getopt(argc, argv, ":l:L:o:givs")) != EOF) {
+ switch (c) {
+ case 'l':
+ label = optarg;
+ break;
+ case 'L':
+ if ((label = getenv(optarg)) == NULL)
+ label = CTF_DEFAULT_LABEL;
+ break;
+ case 'o':
+ outfile = optarg;
+ break;
+ case 's':
+ dynsym = CTF_USE_DYNSYM;
+ break;
+ case 'i':
+ ignore_non_c = 1;
+ break;
+ case 'g':
+ keep_stabs = CTF_KEEP_STABS;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage();
+ exit(2);
+ }
+ }
+
+ if (getenv("STRIPSTABS_KEEP_STABS") != NULL)
+ keep_stabs = CTF_KEEP_STABS;
+
+ if (argc - optind != 1 || label == NULL) {
+ usage();
+ exit(2);
+ }
+
+ infile = argv[optind];
+ if (access(infile, R_OK) != 0)
+ terminate("Can't access %s", infile);
+
+ /*
+ * Upon receipt of a signal, we want to clean up and exit. Our
+ * primary goal during cleanup is to restore the system to a state
+ * such that a subsequent make will eventually cause this command to
+ * be re-run. If we remove the input file (which we do if we get a
+ * signal and the user didn't specify a separate output file), make
+ * will need to rebuild the input file, and will then need to re-run
+ * ctfconvert, which is what we want.
+ */
+ set_terminate_cleanup(terminate_cleanup);
+
+#ifdef illumos
+ sigset(SIGINT, handle_sig);
+ sigset(SIGQUIT, handle_sig);
+ sigset(SIGTERM, handle_sig);
+#else
+ signal(SIGINT, handle_sig);
+ signal(SIGQUIT, handle_sig);
+ signal(SIGTERM, handle_sig);
+#endif
+
+ filetd = tdata_new();
+
+ if (!file_read(filetd, infile, ignore_non_c))
+ terminate("%s doesn't have type data to convert\n", infile);
+
+ if (verbose)
+ iidesc_stats(filetd->td_iihash);
+
+ mstrtd = tdata_new();
+ merge_into_master(filetd, mstrtd, NULL, 1);
+
+ tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);
+
+ /*
+ * If the user supplied an output file that is different from the
+ * input file, write directly to the output file. Otherwise, write
+ * to a temporary file, and replace the input file when we're done.
+ */
+ if (outfile && strcmp(infile, outfile) != 0) {
+ write_ctf(mstrtd, infile, outfile, dynsym | keep_stabs);
+ } else {
+ char *tmpname = mktmpname(infile, ".ctf");
+ write_ctf(mstrtd, infile, tmpname, dynsym | keep_stabs);
+ if (rename(tmpname, infile) != 0)
+ terminate("Couldn't rename temp file %s", tmpname);
+ free(tmpname);
+ }
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.c b/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.c
new file mode 100644
index 000000000000..a3d05ad20b28
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.c
@@ -0,0 +1,1024 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Given several files containing CTF data, merge and uniquify that data into
+ * a single CTF section in an output file.
+ *
+ * Merges can proceed independently. As such, we perform the merges in parallel
+ * using a worker thread model. A given glob of CTF data (either all of the CTF
+ * data from a single input file, or the result of one or more merges) can only
+ * be involved in a single merge at any given time, so the process decreases in
+ * parallelism, especially towards the end, as more and more files are
+ * consolidated, finally resulting in a single merge of two large CTF graphs.
+ * Unfortunately, the last merge is also the slowest, as the two graphs being
+ * merged are each the product of merges of half of the input files.
+ *
+ * The algorithm consists of two phases, described in detail below. The first
+ * phase entails the merging of CTF data in groups of eight. The second phase
+ * takes the results of Phase I, and merges them two at a time. This disparity
+ * is due to an observation that the merge time increases at least quadratically
+ * with the size of the CTF data being merged. As such, merges of CTF graphs
+ * newly read from input files are much faster than merges of CTF graphs that
+ * are themselves the results of prior merges.
+ *
+ * A further complication is the need to ensure the repeatability of CTF merges.
+ * That is, a merge should produce the same output every time, given the same
+ * input. In both phases, this consistency requirement is met by imposing an
+ * ordering on the merge process, thus ensuring that a given set of input files
+ * are merged in the same order every time.
+ *
+ * Phase I
+ *
+ * The main thread reads the input files one by one, transforming the CTF
+ * data they contain into tdata structures. When a given file has been read
+ * and parsed, it is placed on the work queue for retrieval by worker threads.
+ *
+ * Central to Phase I is the Work In Progress (wip) array, which is used to
+ * merge batches of files in a predictable order. Files are read by the main
+ * thread, and are merged into wip array elements in round-robin order. When
+ * the number of files merged into a given array slot equals the batch size,
+ * the merged CTF graph in that array is added to the done slot in order by
+ * array slot.
+ *
+ * For example, consider a case where we have five input files, a batch size
+ * of two, a wip array size of two, and two worker threads (T1 and T2).
+ *
+ * 1. The wip array elements are assigned initial batch numbers 0 and 1.
+ * 2. T1 reads an input file from the input queue (wq_queue). This is the
+ * first input file, so it is placed into wip[0]. The second file is
+ * similarly read and placed into wip[1]. The wip array slots now contain
+ * one file each (wip_nmerged == 1).
+ * 3. T1 reads the third input file, which it merges into wip[0]. The
+ * number of files in wip[0] is equal to the batch size.
+ * 4. T2 reads the fourth input file, which it merges into wip[1]. wip[1]
+ * is now full too.
+ * 5. T2 attempts to place the contents of wip[1] on the done queue
+ * (wq_done_queue), but it can't, since the batch ID for wip[1] is 1.
+ * Batch 0 needs to be on the done queue before batch 1 can be added, so
+ * T2 blocks on wip[1]'s cv.
+ * 6. T1 attempts to place the contents of wip[0] on the done queue, and
+ * succeeds, updating wq_lastdonebatch to 0. It clears wip[0], and sets
+ * its batch ID to 2. T1 then signals wip[1]'s cv to awaken T2.
+ * 7. T2 wakes up, notices that wq_lastdonebatch is 0, which means that
+ * batch 1 can now be added. It adds wip[1] to the done queue, clears
+ * wip[1], and sets its batch ID to 3. It signals wip[0]'s cv, and
+ * restarts.
+ *
+ * The above process continues until all input files have been consumed. At
+ * this point, a pair of barriers are used to allow a single thread to move
+ * any partial batches from the wip array to the done array in batch ID order.
+ * When this is complete, wq_done_queue is moved to wq_queue, and Phase II
+ * begins.
+ *
+ * Locking Semantics (Phase I)
+ *
+ * The input queue (wq_queue) and the done queue (wq_done_queue) are
+ * protected by separate mutexes - wq_queue_lock and wq_done_queue. wip
+ * array slots are protected by their own mutexes, which must be grabbed
+ * before releasing the input queue lock. The wip array lock is dropped
+ * when the thread restarts the loop. If the array slot was full, the
+ * array lock will be held while the slot contents are added to the done
+ * queue. The done queue lock is used to protect the wip slot cv's.
+ *
+ * The pow number is protected by the queue lock. The master batch ID
+ * and last completed batch (wq_lastdonebatch) counters are protected *in
+ * Phase I* by the done queue lock.
+ *
+ * Phase II
+ *
+ * When Phase II begins, the queue consists of the merged batches from the
+ * first phase. Assume we have five batches:
+ *
+ * Q: a b c d e
+ *
+ * Using the same batch ID mechanism we used in Phase I, but without the wip
+ * array, worker threads remove two entries at a time from the beginning of
+ * the queue. These two entries are merged, and are added back to the tail
+ * of the queue, as follows:
+ *
+ * Q: a b c d e # start
+ * Q: c d e ab # a, b removed, merged, added to end
+ * Q: e ab cd # c, d removed, merged, added to end
+ * Q: cd eab # e, ab removed, merged, added to end
+ * Q: cdeab # cd, eab removed, merged, added to end
+ *
+ * When one entry remains on the queue, with no merges outstanding, Phase II
+ * finishes. We pre-determine the stopping point by pre-calculating the
+ * number of nodes that will appear on the list. In the example above, the
+ * number (wq_ninqueue) is 9. When ninqueue is 1, we conclude Phase II by
+ * signaling the main thread via wq_done_cv.
+ *
+ * Locking Semantics (Phase II)
+ *
+ * The queue (wq_queue), ninqueue, and the master batch ID and last
+ * completed batch counters are protected by wq_queue_lock. The done
+ * queue and corresponding lock are unused in Phase II as is the wip array.
+ *
+ * Uniquification
+ *
+ * We want the CTF data that goes into a given module to be as small as
+ * possible. For example, we don't want it to contain any type data that may
+ * be present in another common module. As such, after creating the master
+ * tdata_t for a given module, we can, if requested by the user, uniquify it
+ * against the tdata_t from another module (genunix in the case of the SunOS
+ * kernel). We perform a merge between the tdata_t for this module and the
+ * tdata_t from genunix. Nodes found in this module that are not present in
+ * genunix are added to a third tdata_t - the uniquified tdata_t.
+ *
+ * Additive Merges
+ *
+ * In some cases, for example if we are issuing a new version of a common
+ * module in a patch, we need to make sure that the CTF data already present
+ * in that module does not change. Changes to this data would void the CTF
+ * data in any module that uniquified against the common module. To preserve
+ * the existing data, we can perform what is known as an additive merge. In
+ * this case, a final uniquification is performed against the CTF data in the
+ * previous version of the module. The result will be the placement of new
+ * and changed data after the existing data, thus preserving the existing type
+ * ID space.
+ *
+ * Saving the result
+ *
+ * When the merges are complete, the resulting tdata_t is placed into the
+ * output file, replacing the .SUNW_ctf section (if any) already in that file.
+ *
+ * The person who changes the merging thread code in this file without updating
+ * this comment will not live to see the stock hit five.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <assert.h>
+#ifdef illumos
+#include <synch.h>
+#endif
+#include <signal.h>
+#include <libgen.h>
+#include <string.h>
+#include <errno.h>
+#ifdef illumos
+#include <alloca.h>
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#ifdef illumos
+#include <sys/sysconf.h>
+#endif
+
+#include "ctf_headers.h"
+#include "ctftools.h"
+#include "ctfmerge.h"
+#include "traverse.h"
+#include "memory.h"
+#include "fifo.h"
+#include "barrier.h"
+
+#pragma init(bigheap)
+
+#define MERGE_PHASE1_BATCH_SIZE 8
+#define MERGE_PHASE1_MAX_SLOTS 5
+#define MERGE_INPUT_THROTTLE_LEN 10
+
+const char *progname;
+static char *outfile = NULL;
+static char *tmpname = NULL;
+static int dynsym;
+int debug_level = DEBUG_LEVEL;
+static size_t maxpgsize = 0x400000;
+
+
+void
+usage(void)
+{
+ (void) fprintf(stderr,
+ "Usage: %s [-fgstv] -l label | -L labelenv -o outfile file ...\n"
+ " %s [-fgstv] -l label | -L labelenv -o outfile -d uniqfile\n"
+ " %*s [-g] [-D uniqlabel] file ...\n"
+ " %s [-fgstv] -l label | -L labelenv -o outfile -w withfile "
+ "file ...\n"
+ " %s [-g] -c srcfile destfile\n"
+ "\n"
+ " Note: if -L labelenv is specified and labelenv is not set in\n"
+ " the environment, a default value is used.\n",
+ progname, progname, (int)strlen(progname), " ",
+ progname, progname);
+}
+
+#ifdef illumos
+static void
+bigheap(void)
+{
+ size_t big, *size;
+ int sizes;
+ struct memcntl_mha mha;
+
+ /*
+ * First, get the available pagesizes.
+ */
+ if ((sizes = getpagesizes(NULL, 0)) == -1)
+ return;
+
+ if (sizes == 1 || (size = alloca(sizeof (size_t) * sizes)) == NULL)
+ return;
+
+ if (getpagesizes(size, sizes) == -1)
+ return;
+
+ while (size[sizes - 1] > maxpgsize)
+ sizes--;
+
+ /* set big to the largest allowed page size */
+ big = size[sizes - 1];
+ if (big & (big - 1)) {
+ /*
+ * The largest page size is not a power of two for some
+ * inexplicable reason; return.
+ */
+ return;
+ }
+
+ /*
+ * Now, align our break to the largest page size.
+ */
+ if (brk((void *)((((uintptr_t)sbrk(0) - 1) & ~(big - 1)) + big)) != 0)
+ return;
+
+ /*
+ * set the preferred page size for the heap
+ */
+ mha.mha_cmd = MHA_MAPSIZE_BSSBRK;
+ mha.mha_flags = 0;
+ mha.mha_pagesize = big;
+
+ (void) memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t)&mha, 0, 0);
+}
+#endif /* illumos */
+
+static void
+finalize_phase_one(workqueue_t *wq)
+{
+ int startslot, i;
+
+ /*
+ * wip slots are cleared out only when maxbatchsz td's have been merged
+ * into them. We're not guaranteed that the number of files we're
+ * merging is a multiple of maxbatchsz, so there will be some partial
+ * groups in the wip array. Move them to the done queue in batch ID
+ * order, starting with the slot containing the next batch that would
+ * have been placed on the done queue, followed by the others.
+ * One thread will be doing this while the others wait at the barrier
+ * back in worker_thread(), so we don't need to worry about pesky things
+ * like locks.
+ */
+
+ for (startslot = -1, i = 0; i < wq->wq_nwipslots; i++) {
+ if (wq->wq_wip[i].wip_batchid == wq->wq_lastdonebatch + 1) {
+ startslot = i;
+ break;
+ }
+ }
+
+ assert(startslot != -1);
+
+ for (i = startslot; i < startslot + wq->wq_nwipslots; i++) {
+ int slotnum = i % wq->wq_nwipslots;
+ wip_t *wipslot = &wq->wq_wip[slotnum];
+
+ if (wipslot->wip_td != NULL) {
+ debug(2, "clearing slot %d (%d) (saving %d)\n",
+ slotnum, i, wipslot->wip_nmerged);
+ } else
+ debug(2, "clearing slot %d (%d)\n", slotnum, i);
+
+ if (wipslot->wip_td != NULL) {
+ fifo_add(wq->wq_donequeue, wipslot->wip_td);
+ wq->wq_wip[slotnum].wip_td = NULL;
+ }
+ }
+
+ wq->wq_lastdonebatch = wq->wq_next_batchid++;
+
+ debug(2, "phase one done: donequeue has %d items\n",
+ fifo_len(wq->wq_donequeue));
+}
+
+static void
+init_phase_two(workqueue_t *wq)
+{
+ int num;
+
+ /*
+ * We're going to continually merge the first two entries on the queue,
+ * placing the result on the end, until there's nothing left to merge.
+ * At that point, everything will have been merged into one. The
+ * initial value of ninqueue needs to be equal to the total number of
+ * entries that will show up on the queue, both at the start of the
+ * phase and as generated by merges during the phase.
+ */
+ wq->wq_ninqueue = num = fifo_len(wq->wq_donequeue);
+ while (num != 1) {
+ wq->wq_ninqueue += num / 2;
+ num = num / 2 + num % 2;
+ }
+
+ /*
+ * Move the done queue to the work queue. We won't be using the done
+ * queue in phase 2.
+ */
+ assert(fifo_len(wq->wq_queue) == 0);
+ fifo_free(wq->wq_queue, NULL);
+ wq->wq_queue = wq->wq_donequeue;
+}
+
+static void
+wip_save_work(workqueue_t *wq, wip_t *slot, int slotnum)
+{
+ pthread_mutex_lock(&wq->wq_donequeue_lock);
+
+ while (wq->wq_lastdonebatch + 1 < slot->wip_batchid)
+ pthread_cond_wait(&slot->wip_cv, &wq->wq_donequeue_lock);
+ assert(wq->wq_lastdonebatch + 1 == slot->wip_batchid);
+
+ fifo_add(wq->wq_donequeue, slot->wip_td);
+ wq->wq_lastdonebatch++;
+ pthread_cond_signal(&wq->wq_wip[(slotnum + 1) %
+ wq->wq_nwipslots].wip_cv);
+
+ /* reset the slot for next use */
+ slot->wip_td = NULL;
+ slot->wip_batchid = wq->wq_next_batchid++;
+
+ pthread_mutex_unlock(&wq->wq_donequeue_lock);
+}
+
+static void
+wip_add_work(wip_t *slot, tdata_t *pow)
+{
+ if (slot->wip_td == NULL) {
+ slot->wip_td = pow;
+ slot->wip_nmerged = 1;
+ } else {
+ debug(2, "%d: merging %p into %p\n", pthread_self(),
+ (void *)pow, (void *)slot->wip_td);
+
+ merge_into_master(pow, slot->wip_td, NULL, 0);
+ tdata_free(pow);
+
+ slot->wip_nmerged++;
+ }
+}
+
+static void
+worker_runphase1(workqueue_t *wq)
+{
+ wip_t *wipslot;
+ tdata_t *pow;
+ int wipslotnum, pownum;
+
+ for (;;) {
+ pthread_mutex_lock(&wq->wq_queue_lock);
+
+ while (fifo_empty(wq->wq_queue)) {
+ if (wq->wq_nomorefiles == 1) {
+ pthread_cond_broadcast(&wq->wq_work_avail);
+ pthread_mutex_unlock(&wq->wq_queue_lock);
+
+ /* on to phase 2 ... */
+ return;
+ }
+
+ pthread_cond_wait(&wq->wq_work_avail,
+ &wq->wq_queue_lock);
+ }
+
+ /* there's work to be done! */
+ pow = fifo_remove(wq->wq_queue);
+ pownum = wq->wq_nextpownum++;
+ pthread_cond_broadcast(&wq->wq_work_removed);
+
+ assert(pow != NULL);
+
+ /* merge it into the right slot */
+ wipslotnum = pownum % wq->wq_nwipslots;
+ wipslot = &wq->wq_wip[wipslotnum];
+
+ pthread_mutex_lock(&wipslot->wip_lock);
+
+ pthread_mutex_unlock(&wq->wq_queue_lock);
+
+ wip_add_work(wipslot, pow);
+
+ if (wipslot->wip_nmerged == wq->wq_maxbatchsz)
+ wip_save_work(wq, wipslot, wipslotnum);
+
+ pthread_mutex_unlock(&wipslot->wip_lock);
+ }
+}
+
+static void
+worker_runphase2(workqueue_t *wq)
+{
+ tdata_t *pow1, *pow2;
+ int batchid;
+
+ for (;;) {
+ pthread_mutex_lock(&wq->wq_queue_lock);
+
+ if (wq->wq_ninqueue == 1) {
+ pthread_cond_broadcast(&wq->wq_work_avail);
+ pthread_mutex_unlock(&wq->wq_queue_lock);
+
+ debug(2, "%d: entering p2 completion barrier\n",
+ pthread_self());
+ if (barrier_wait(&wq->wq_bar1)) {
+ pthread_mutex_lock(&wq->wq_queue_lock);
+ wq->wq_alldone = 1;
+ pthread_cond_signal(&wq->wq_alldone_cv);
+ pthread_mutex_unlock(&wq->wq_queue_lock);
+ }
+
+ return;
+ }
+
+ if (fifo_len(wq->wq_queue) < 2) {
+ pthread_cond_wait(&wq->wq_work_avail,
+ &wq->wq_queue_lock);
+ pthread_mutex_unlock(&wq->wq_queue_lock);
+ continue;
+ }
+
+ /* there's work to be done! */
+ pow1 = fifo_remove(wq->wq_queue);
+ pow2 = fifo_remove(wq->wq_queue);
+ wq->wq_ninqueue -= 2;
+
+ batchid = wq->wq_next_batchid++;
+
+ pthread_mutex_unlock(&wq->wq_queue_lock);
+
+ debug(2, "%d: merging %p into %p\n", pthread_self(),
+ (void *)pow1, (void *)pow2);
+ merge_into_master(pow1, pow2, NULL, 0);
+ tdata_free(pow1);
+
+ /*
+ * merging is complete. place at the tail of the queue in
+ * proper order.
+ */
+ pthread_mutex_lock(&wq->wq_queue_lock);
+ while (wq->wq_lastdonebatch + 1 != batchid) {
+ pthread_cond_wait(&wq->wq_done_cv,
+ &wq->wq_queue_lock);
+ }
+
+ wq->wq_lastdonebatch = batchid;
+
+ fifo_add(wq->wq_queue, pow2);
+ debug(2, "%d: added %p to queue, len now %d, ninqueue %d\n",
+ pthread_self(), (void *)pow2, fifo_len(wq->wq_queue),
+ wq->wq_ninqueue);
+ pthread_cond_broadcast(&wq->wq_done_cv);
+ pthread_cond_signal(&wq->wq_work_avail);
+ pthread_mutex_unlock(&wq->wq_queue_lock);
+ }
+}
+
+/*
+ * Main loop for worker threads.
+ */
+static void
+worker_thread(workqueue_t *wq)
+{
+ worker_runphase1(wq);
+
+ debug(2, "%d: entering first barrier\n", pthread_self());
+
+ if (barrier_wait(&wq->wq_bar1)) {
+
+ debug(2, "%d: doing work in first barrier\n", pthread_self());
+
+ finalize_phase_one(wq);
+
+ init_phase_two(wq);
+
+ debug(2, "%d: ninqueue is %d, %d on queue\n", pthread_self(),
+ wq->wq_ninqueue, fifo_len(wq->wq_queue));
+ }
+
+ debug(2, "%d: entering second barrier\n", pthread_self());
+
+ (void) barrier_wait(&wq->wq_bar2);
+
+ debug(2, "%d: phase 1 complete\n", pthread_self());
+
+ worker_runphase2(wq);
+}
+
+/*
+ * Pass a tdata_t tree, built from an input file, off to the work queue for
+ * consumption by worker threads.
+ */
+static int
+merge_ctf_cb(tdata_t *td, char *name, void *arg)
+{
+ workqueue_t *wq = arg;
+
+ debug(3, "Adding tdata %p for processing\n", (void *)td);
+
+ pthread_mutex_lock(&wq->wq_queue_lock);
+ while (fifo_len(wq->wq_queue) > wq->wq_ithrottle) {
+ debug(2, "Throttling input (len = %d, throttle = %d)\n",
+ fifo_len(wq->wq_queue), wq->wq_ithrottle);
+ pthread_cond_wait(&wq->wq_work_removed, &wq->wq_queue_lock);
+ }
+
+ fifo_add(wq->wq_queue, td);
+ debug(1, "Thread %d announcing %s\n", pthread_self(), name);
+ pthread_cond_broadcast(&wq->wq_work_avail);
+ pthread_mutex_unlock(&wq->wq_queue_lock);
+
+ return (1);
+}
+
+/*
+ * This program is intended to be invoked from a Makefile, as part of the build.
+ * As such, in the event of a failure or user-initiated interrupt (^C), we need
+ * to ensure that a subsequent re-make will cause ctfmerge to be executed again.
+ * Unfortunately, ctfmerge will usually be invoked directly after (and as part
+ * of the same Makefile rule as) a link, and will operate on the linked file
+ * in place. If we merely exit upon receipt of a SIGINT, a subsequent make
+ * will notice that the *linked* file is newer than the object files, and thus
+ * will not reinvoke ctfmerge. The only way to ensure that a subsequent make
+ * reinvokes ctfmerge, is to remove the file to which we are adding CTF
+ * data (confusingly named the output file). This means that the link will need
+ * to happen again, but links are generally fast, and we can't allow the merge
+ * to be skipped.
+ *
+ * Another possibility would be to block SIGINT entirely - to always run to
+ * completion. The run time of ctfmerge can, however, be measured in minutes
+ * in some cases, so this is not a valid option.
+ */
+static void
+handle_sig(int sig)
+{
+ terminate("Caught signal %d - exiting\n", sig);
+}
+
+static void
+terminate_cleanup(void)
+{
+ int dounlink = getenv("CTFMERGE_TERMINATE_NO_UNLINK") ? 0 : 1;
+
+ if (tmpname != NULL && dounlink)
+ unlink(tmpname);
+
+ if (outfile == NULL)
+ return;
+
+#if !defined(__FreeBSD__)
+ if (dounlink) {
+ fprintf(stderr, "Removing %s\n", outfile);
+ unlink(outfile);
+ }
+#endif
+}
+
+static void
+copy_ctf_data(char *srcfile, char *destfile, int keep_stabs)
+{
+ tdata_t *srctd;
+
+ if (read_ctf(&srcfile, 1, NULL, read_ctf_save_cb, &srctd, 1) == 0)
+ terminate("No CTF data found in source file %s\n", srcfile);
+
+ tmpname = mktmpname(destfile, ".ctf");
+ write_ctf(srctd, destfile, tmpname, CTF_COMPRESS | CTF_SWAP_BYTES | keep_stabs);
+ if (rename(tmpname, destfile) != 0) {
+ terminate("Couldn't rename temp file %s to %s", tmpname,
+ destfile);
+ }
+ free(tmpname);
+ tdata_free(srctd);
+}
+
+static void
+wq_init(workqueue_t *wq, int nfiles)
+{
+ int throttle, nslots, i;
+
+ if (getenv("CTFMERGE_MAX_SLOTS"))
+ nslots = atoi(getenv("CTFMERGE_MAX_SLOTS"));
+ else
+ nslots = MERGE_PHASE1_MAX_SLOTS;
+
+ if (getenv("CTFMERGE_PHASE1_BATCH_SIZE"))
+ wq->wq_maxbatchsz = atoi(getenv("CTFMERGE_PHASE1_BATCH_SIZE"));
+ else
+ wq->wq_maxbatchsz = MERGE_PHASE1_BATCH_SIZE;
+
+ nslots = MIN(nslots, (nfiles + wq->wq_maxbatchsz - 1) /
+ wq->wq_maxbatchsz);
+
+ wq->wq_wip = xcalloc(sizeof (wip_t) * nslots);
+ wq->wq_nwipslots = nslots;
+ wq->wq_nthreads = MIN(sysconf(_SC_NPROCESSORS_ONLN) * 3 / 2, nslots);
+ wq->wq_thread = xmalloc(sizeof (pthread_t) * wq->wq_nthreads);
+
+ if (getenv("CTFMERGE_INPUT_THROTTLE"))
+ throttle = atoi(getenv("CTFMERGE_INPUT_THROTTLE"));
+ else
+ throttle = MERGE_INPUT_THROTTLE_LEN;
+ wq->wq_ithrottle = throttle * wq->wq_nthreads;
+
+ debug(1, "Using %d slots, %d threads\n", wq->wq_nwipslots,
+ wq->wq_nthreads);
+
+ wq->wq_next_batchid = 0;
+
+ for (i = 0; i < nslots; i++) {
+ pthread_mutex_init(&wq->wq_wip[i].wip_lock, NULL);
+ wq->wq_wip[i].wip_batchid = wq->wq_next_batchid++;
+ }
+
+ pthread_mutex_init(&wq->wq_queue_lock, NULL);
+ wq->wq_queue = fifo_new();
+ pthread_cond_init(&wq->wq_work_avail, NULL);
+ pthread_cond_init(&wq->wq_work_removed, NULL);
+ wq->wq_ninqueue = nfiles;
+ wq->wq_nextpownum = 0;
+
+ pthread_mutex_init(&wq->wq_donequeue_lock, NULL);
+ wq->wq_donequeue = fifo_new();
+ wq->wq_lastdonebatch = -1;
+
+ pthread_cond_init(&wq->wq_done_cv, NULL);
+
+ pthread_cond_init(&wq->wq_alldone_cv, NULL);
+ wq->wq_alldone = 0;
+
+ barrier_init(&wq->wq_bar1, wq->wq_nthreads);
+ barrier_init(&wq->wq_bar2, wq->wq_nthreads);
+
+ wq->wq_nomorefiles = 0;
+}
+
+static void
+start_threads(workqueue_t *wq)
+{
+ sigset_t sets;
+ int i;
+
+ sigemptyset(&sets);
+ sigaddset(&sets, SIGINT);
+ sigaddset(&sets, SIGQUIT);
+ sigaddset(&sets, SIGTERM);
+ pthread_sigmask(SIG_BLOCK, &sets, NULL);
+
+ for (i = 0; i < wq->wq_nthreads; i++) {
+ pthread_create(&wq->wq_thread[i], NULL,
+ (void *(*)(void *))worker_thread, wq);
+ }
+
+#ifdef illumos
+ sigset(SIGINT, handle_sig);
+ sigset(SIGQUIT, handle_sig);
+ sigset(SIGTERM, handle_sig);
+#else
+ signal(SIGINT, handle_sig);
+ signal(SIGQUIT, handle_sig);
+ signal(SIGTERM, handle_sig);
+#endif
+ pthread_sigmask(SIG_UNBLOCK, &sets, NULL);
+}
+
+static void
+join_threads(workqueue_t *wq)
+{
+ int i;
+
+ for (i = 0; i < wq->wq_nthreads; i++) {
+ pthread_join(wq->wq_thread[i], NULL);
+ }
+}
+
+static int
+strcompare(const void *p1, const void *p2)
+{
+ char *s1 = *((char **)p1);
+ char *s2 = *((char **)p2);
+
+ return (strcmp(s1, s2));
+}
+
+/*
+ * Core work queue structure; passed to worker threads on thread creation
+ * as the main point of coordination. Allocate as a static structure; we
+ * could have put this into a local variable in main, but passing a pointer
+ * into your stack to another thread is fragile at best and leads to some
+ * hard-to-debug failure modes.
+ */
+static workqueue_t wq;
+
+int
+main(int argc, char **argv)
+{
+ tdata_t *mstrtd, *savetd;
+ char *uniqfile = NULL, *uniqlabel = NULL;
+ char *withfile = NULL;
+ char *label = NULL;
+ char **ifiles, **tifiles;
+ int verbose = 0, docopy = 0;
+ int write_fuzzy_match = 0;
+ int keep_stabs = 0;
+ int require_ctf = 0;
+ int nifiles, nielems;
+ int c, i, idx, tidx, err;
+
+ progname = basename(argv[0]);
+
+ if (getenv("CTFMERGE_DEBUG_LEVEL"))
+ debug_level = atoi(getenv("CTFMERGE_DEBUG_LEVEL"));
+
+ err = 0;
+ while ((c = getopt(argc, argv, ":cd:D:fgl:L:o:tvw:s")) != EOF) {
+ switch (c) {
+ case 'c':
+ docopy = 1;
+ break;
+ case 'd':
+ /* Uniquify against `uniqfile' */
+ uniqfile = optarg;
+ break;
+ case 'D':
+ /* Uniquify against label `uniqlabel' in `uniqfile' */
+ uniqlabel = optarg;
+ break;
+ case 'f':
+ write_fuzzy_match = CTF_FUZZY_MATCH;
+ break;
+ case 'g':
+ keep_stabs = CTF_KEEP_STABS;
+ break;
+ case 'l':
+ /* Label merged types with `label' */
+ label = optarg;
+ break;
+ case 'L':
+ /* Label merged types with getenv(`label`) */
+ if ((label = getenv(optarg)) == NULL)
+ label = CTF_DEFAULT_LABEL;
+ break;
+ case 'o':
+ /* Place merged types in CTF section in `outfile' */
+ outfile = optarg;
+ break;
+ case 't':
+ /* Insist *all* object files built from C have CTF */
+ require_ctf = 1;
+ break;
+ case 'v':
+ /* More debugging information */
+ verbose = 1;
+ break;
+ case 'w':
+ /* Additive merge with data from `withfile' */
+ withfile = optarg;
+ break;
+ case 's':
+ /* use the dynsym rather than the symtab */
+ dynsym = CTF_USE_DYNSYM;
+ break;
+ default:
+ usage();
+ exit(2);
+ }
+ }
+
+ /* Validate arguments */
+ if (docopy) {
+ if (uniqfile != NULL || uniqlabel != NULL || label != NULL ||
+ outfile != NULL || withfile != NULL || dynsym != 0)
+ err++;
+
+ if (argc - optind != 2)
+ err++;
+ } else {
+ if (uniqfile != NULL && withfile != NULL)
+ err++;
+
+ if (uniqlabel != NULL && uniqfile == NULL)
+ err++;
+
+ if (outfile == NULL || label == NULL)
+ err++;
+
+ if (argc - optind == 0)
+ err++;
+ }
+
+ if (err) {
+ usage();
+ exit(2);
+ }
+
+ if (getenv("STRIPSTABS_KEEP_STABS") != NULL)
+ keep_stabs = CTF_KEEP_STABS;
+
+ if (uniqfile && access(uniqfile, R_OK) != 0) {
+ warning("Uniquification file %s couldn't be opened and "
+ "will be ignored.\n", uniqfile);
+ uniqfile = NULL;
+ }
+ if (withfile && access(withfile, R_OK) != 0) {
+ warning("With file %s couldn't be opened and will be "
+ "ignored.\n", withfile);
+ withfile = NULL;
+ }
+ if (outfile && access(outfile, R_OK|W_OK) != 0)
+ terminate("Cannot open output file %s for r/w", outfile);
+
+ /*
+ * This is ugly, but we don't want to have to have a separate tool
+ * (yet) just for copying an ELF section with our specific requirements,
+ * so we shoe-horn a copier into ctfmerge.
+ */
+ if (docopy) {
+ copy_ctf_data(argv[optind], argv[optind + 1], keep_stabs);
+
+ exit(0);
+ }
+
+ set_terminate_cleanup(terminate_cleanup);
+
+ /* Sort the input files and strip out duplicates */
+ nifiles = argc - optind;
+ ifiles = xmalloc(sizeof (char *) * nifiles);
+ tifiles = xmalloc(sizeof (char *) * nifiles);
+
+ for (i = 0; i < nifiles; i++)
+ tifiles[i] = argv[optind + i];
+ qsort(tifiles, nifiles, sizeof (char *), (int (*)())strcompare);
+
+ ifiles[0] = tifiles[0];
+ for (idx = 0, tidx = 1; tidx < nifiles; tidx++) {
+ if (strcmp(ifiles[idx], tifiles[tidx]) != 0)
+ ifiles[++idx] = tifiles[tidx];
+ }
+ nifiles = idx + 1;
+
+ /* Make sure they all exist */
+ if ((nielems = count_files(ifiles, nifiles)) < 0)
+ terminate("Some input files were inaccessible\n");
+
+ /* Prepare for the merge */
+ wq_init(&wq, nielems);
+
+ start_threads(&wq);
+
+ /*
+ * Start the merge
+ *
+ * We're reading everything from each of the object files, so we
+ * don't need to specify labels.
+ */
+ if (read_ctf(ifiles, nifiles, NULL, merge_ctf_cb,
+ &wq, require_ctf) == 0) {
+ /*
+ * If we're verifying that C files have CTF, it's safe to
+ * assume that in this case, we're building only from assembly
+ * inputs.
+ */
+ if (require_ctf)
+ exit(0);
+ terminate("No ctf sections found to merge\n");
+ }
+
+ pthread_mutex_lock(&wq.wq_queue_lock);
+ wq.wq_nomorefiles = 1;
+ pthread_cond_broadcast(&wq.wq_work_avail);
+ pthread_mutex_unlock(&wq.wq_queue_lock);
+
+ pthread_mutex_lock(&wq.wq_queue_lock);
+ while (wq.wq_alldone == 0)
+ pthread_cond_wait(&wq.wq_alldone_cv, &wq.wq_queue_lock);
+ pthread_mutex_unlock(&wq.wq_queue_lock);
+
+ join_threads(&wq);
+
+ /*
+ * All requested files have been merged, with the resulting tree in
+ * mstrtd. savetd is the tree that will be placed into the output file.
+ *
+ * Regardless of whether we're doing a normal uniquification or an
+ * additive merge, we need a type tree that has been uniquified
+ * against uniqfile or withfile, as appropriate.
+ *
+ * If we're doing a uniquification, we stuff the resulting tree into
+ * outfile. Otherwise, we add the tree to the tree already in withfile.
+ */
+ assert(fifo_len(wq.wq_queue) == 1);
+ mstrtd = fifo_remove(wq.wq_queue);
+
+ if (verbose || debug_level) {
+ debug(2, "Statistics for td %p\n", (void *)mstrtd);
+
+ iidesc_stats(mstrtd->td_iihash);
+ }
+
+ if (uniqfile != NULL || withfile != NULL) {
+ char *reffile, *reflabel = NULL;
+ tdata_t *reftd;
+
+ if (uniqfile != NULL) {
+ reffile = uniqfile;
+ reflabel = uniqlabel;
+ } else
+ reffile = withfile;
+
+ if (read_ctf(&reffile, 1, reflabel, read_ctf_save_cb,
+ &reftd, require_ctf) == 0) {
+ terminate("No CTF data found in reference file %s\n",
+ reffile);
+ }
+
+ savetd = tdata_new();
+
+ if (CTF_TYPE_ISCHILD(reftd->td_nextid))
+ terminate("No room for additional types in master\n");
+
+ savetd->td_nextid = withfile ? reftd->td_nextid :
+ CTF_INDEX_TO_TYPE(1, TRUE);
+ merge_into_master(mstrtd, reftd, savetd, 0);
+
+ tdata_label_add(savetd, label, CTF_LABEL_LASTIDX);
+
+ if (withfile) {
+ /*
+ * savetd holds the new data to be added to the withfile
+ */
+ tdata_t *withtd = reftd;
+
+ tdata_merge(withtd, savetd);
+
+ savetd = withtd;
+ } else {
+ char uniqname[MAXPATHLEN];
+ labelent_t *parle;
+
+ parle = tdata_label_top(reftd);
+
+ savetd->td_parlabel = xstrdup(parle->le_name);
+
+ strncpy(uniqname, reffile, sizeof (uniqname));
+ uniqname[MAXPATHLEN - 1] = '\0';
+ savetd->td_parname = xstrdup(basename(uniqname));
+ }
+
+ } else {
+ /*
+ * No post processing. Write the merged tree as-is into the
+ * output file.
+ */
+ tdata_label_free(mstrtd);
+ tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);
+
+ savetd = mstrtd;
+ }
+
+ tmpname = mktmpname(outfile, ".ctf");
+ write_ctf(savetd, outfile, tmpname,
+ CTF_COMPRESS | CTF_SWAP_BYTES | write_fuzzy_match | dynsym | keep_stabs);
+ if (rename(tmpname, outfile) != 0)
+ terminate("Couldn't rename output temp file %s", tmpname);
+ free(tmpname);
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.h b/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.h
new file mode 100644
index 000000000000..ce40803d52a8
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.h
@@ -0,0 +1,90 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _CTFMERGE_H
+#define _CTFMERGE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Merging structures used in ctfmerge. See ctfmerge.c for locking semantics.
+ */
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ctftools.h"
+#include "barrier.h"
+#include "fifo.h"
+
+typedef struct wip {
+ pthread_mutex_t wip_lock;
+ pthread_cond_t wip_cv;
+ tdata_t *wip_td;
+ int wip_nmerged;
+ int wip_batchid;
+} wip_t;
+
+typedef struct workqueue {
+ int wq_next_batchid;
+
+ int wq_maxbatchsz;
+
+ wip_t *wq_wip;
+ int wq_nwipslots;
+ int wq_nthreads;
+ int wq_ithrottle;
+
+ pthread_mutex_t wq_queue_lock;
+ fifo_t *wq_queue;
+ pthread_cond_t wq_work_avail;
+ pthread_cond_t wq_work_removed;
+ int wq_ninqueue;
+ int wq_nextpownum;
+
+ pthread_mutex_t wq_donequeue_lock;
+ fifo_t *wq_donequeue;
+ int wq_lastdonebatch;
+ pthread_cond_t wq_done_cv;
+
+ pthread_cond_t wq_alldone_cv; /* protected by queue_lock */
+ int wq_alldone;
+
+ int wq_nomorefiles;
+
+ pthread_t *wq_thread;
+
+ barrier_t wq_bar1;
+ barrier_t wq_bar2;
+} workqueue_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CTFMERGE_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h b/cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h
new file mode 100644
index 000000000000..c8d272faa419
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h
@@ -0,0 +1,454 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _CTFTOOLS_H
+#define _CTFTOOLS_H
+
+/*
+ * Functions and data structures used in the manipulation of stabs and CTF data
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <pthread.h>
+
+#include <sys/ccompile.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "list.h"
+#include "hash.h"
+
+#ifndef DEBUG_LEVEL
+#define DEBUG_LEVEL 0
+#endif
+#ifndef DEBUG_PARSE
+#define DEBUG_PARSE 0
+#endif
+
+#ifndef DEBUG_STREAM
+#define DEBUG_STREAM stderr
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+#ifndef MIN
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#define CTF_ELF_SCN_NAME ".SUNW_ctf"
+
+#define CTF_LABEL_LASTIDX -1
+
+#define CTF_DEFAULT_LABEL "*** No Label Provided ***"
+
+/*
+ * Default hash sizes
+ */
+#define TDATA_LAYOUT_HASH_SIZE 8191 /* A tdesc hash based on layout */
+#define TDATA_ID_HASH_SIZE 997 /* A tdesc hash based on type id */
+#define IIDESC_HASH_SIZE 8191 /* Hash of iidesc's */
+
+/*
+ * The default function argument array size. We'll realloc the array larger
+ * if we need to, but we want a default value that will allow us to avoid
+ * reallocation in the common case.
+ */
+#define FUNCARG_DEF 5
+
+extern const char *progname;
+extern int debug_level;
+extern int debug_parse;
+extern char *curhdr;
+
+/*
+ * This is a partial copy of the stab.h that DevPro includes with their
+ * compiler.
+ */
+typedef struct stab {
+ uint32_t n_strx;
+ uint8_t n_type;
+ int8_t n_other;
+ int16_t n_desc;
+ uint32_t n_value;
+} stab_t;
+
+#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */
+#define N_FUN 0x24 /* procedure: name,,0,linenumber,0 */
+#define N_STSYM 0x26 /* static symbol: name,,0,type,0 or section relative */
+#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,0 or section relative */
+#define N_ROSYM 0x2c /* ro_data: name,,0,type,0 or section relative */
+#define N_OPT 0x3c /* compiler options */
+#define N_RSYM 0x40 /* register sym: name,,0,type,register */
+#define N_SO 0x64 /* source file name: name,,0,0,0 */
+#define N_LSYM 0x80 /* local sym: name,,0,type,offset */
+#define N_SOL 0x84 /* #included file name: name,,0,0,0 */
+#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */
+#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,function relative */
+#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,func relative */
+#define N_BINCL 0x82 /* header file: name,,0,0,0 */
+#define N_EINCL 0xa2 /* end of include file */
+
+/*
+ * Nodes in the type tree
+ *
+ * Each node consists of a single tdesc_t, with one of several auxiliary
+ * structures linked in via the `data' union.
+ */
+
+/* The type of tdesc_t node */
+typedef enum stabtype {
+ STABTYPE_FIRST, /* do not use */
+ INTRINSIC,
+ POINTER,
+ ARRAY,
+ FUNCTION,
+ STRUCT,
+ UNION,
+ ENUM,
+ FORWARD,
+ TYPEDEF,
+ TYPEDEF_UNRES,
+ VOLATILE,
+ CONST,
+ RESTRICT,
+ STABTYPE_LAST /* do not use */
+} stabtype_t;
+
+typedef struct tdesc tdesc_t;
+
+/* Auxiliary structure for array tdesc_t */
+typedef struct ardef {
+ tdesc_t *ad_contents;
+ tdesc_t *ad_idxtype;
+ uint_t ad_nelems;
+} ardef_t;
+
+/* Auxiliary structure for structure/union tdesc_t */
+typedef struct mlist {
+ int ml_offset; /* Offset from start of structure (in bits) */
+ int ml_size; /* Member size (in bits) */
+ char *ml_name; /* Member name */
+ struct tdesc *ml_type; /* Member type */
+ struct mlist *ml_next; /* Next member */
+} mlist_t;
+
+/* Auxiliary structure for enum tdesc_t */
+typedef struct elist {
+ char *el_name;
+ int el_number;
+ struct elist *el_next;
+} elist_t;
+
+/* Auxiliary structure for intrinsics (integers and reals) */
+typedef enum {
+ INTR_INT,
+ INTR_REAL
+} intrtype_t;
+
+typedef struct intr {
+ intrtype_t intr_type;
+ int intr_signed;
+ union {
+ char _iformat;
+ int _fformat;
+ } _u;
+ int intr_offset;
+ int intr_nbits;
+} intr_t;
+
+#define intr_iformat _u._iformat
+#define intr_fformat _u._fformat
+
+typedef struct fnarg {
+ char *fna_name;
+ struct tdesc *fna_type;
+} fnarg_t;
+
+#define FN_F_GLOBAL 0x1
+#define FN_F_VARARGS 0x2
+
+typedef struct fndef {
+ struct tdesc *fn_ret;
+ uint_t fn_nargs;
+ tdesc_t **fn_args;
+ uint_t fn_vargs;
+} fndef_t;
+
+typedef int32_t tid_t;
+
+/*
+ * The tdesc_t (Type DESCription) is the basic node type used in the stabs data
+ * structure. Each data node gets a tdesc structure. Each node is linked into
+ * a directed graph (think of it as a tree with multiple roots and multiple
+ * leaves), with the root nodes at the top, and intrinsics at the bottom. The
+ * root nodes, which are pointed to by iidesc nodes, correspond to the types,
+ * globals, and statics defined by the stabs.
+ */
+struct tdesc {
+ char *t_name;
+ tdesc_t *t_next; /* Name hash next pointer */
+
+ tid_t t_id;
+ tdesc_t *t_hash; /* ID hash next pointer */
+
+ stabtype_t t_type;
+ int t_size; /* Size in bytes of object represented by this node */
+
+ union {
+ intr_t *intr; /* int, real */
+ tdesc_t *tdesc; /* ptr, typedef, vol, const, restr */
+ ardef_t *ardef; /* array */
+ mlist_t *members; /* struct, union */
+ elist_t *emem; /* enum */
+ fndef_t *fndef; /* function - first is return type */
+ } t_data;
+
+ int t_flags;
+ int t_vgen; /* Visitation generation (see traverse.c) */
+ int t_emark; /* Equality mark (see equiv_cb() in merge.c) */
+};
+
+#define t_intr t_data.intr
+#define t_tdesc t_data.tdesc
+#define t_ardef t_data.ardef
+#define t_members t_data.members
+#define t_emem t_data.emem
+#define t_fndef t_data.fndef
+
+#define TDESC_F_ISROOT 0x1 /* Has an iidesc_t (see below) */
+#define TDESC_F_GLOBAL 0x2
+#define TDESC_F_RESOLVED 0x4
+
+/*
+ * iidesc_t (Interesting Item DESCription) nodes point to tdesc_t nodes that
+ * correspond to "interesting" stabs. A stab is interesting if it defines a
+ * global or static variable, a global or static function, or a data type.
+ */
+typedef enum iitype {
+ II_NOT = 0,
+ II_GFUN, /* Global function */
+ II_SFUN, /* Static function */
+ II_GVAR, /* Global variable */
+ II_SVAR, /* Static variable */
+ II_PSYM, /* Function argument */
+ II_SOU, /* Struct or union */
+ II_TYPE /* Type (typedef) */
+} iitype_t;
+
+typedef struct iidesc {
+ iitype_t ii_type;
+ char *ii_name;
+ tdesc_t *ii_dtype;
+ char *ii_owner; /* File that defined this node */
+ int ii_flags;
+
+ /* Function arguments (if any) */
+ int ii_nargs;
+ tdesc_t **ii_args;
+ int ii_vargs; /* Function uses varargs */
+} iidesc_t;
+
+#define IIDESC_F_USED 0x1 /* Write this iidesc out */
+
+/*
+ * labelent_t nodes identify labels and corresponding type ranges associated
+ * with them. The label in a given labelent_t is associated with types with
+ * ids <= le_idx.
+ */
+typedef struct labelent {
+ char *le_name;
+ int le_idx;
+} labelent_t;
+
+/*
+ * The tdata_t (Type DATA) structure contains or references all type data for
+ * a given file or, during merging, several files.
+ */
+typedef struct tdata {
+ int td_curemark; /* Equality mark (see merge.c) */
+ int td_curvgen; /* Visitation generation (see traverse.c) */
+ int td_nextid; /* The ID for the next tdesc_t created */
+ hash_t *td_iihash; /* The iidesc_t nodes for this file */
+
+ hash_t *td_layouthash; /* The tdesc nodes, hashed by structure */
+ hash_t *td_idhash; /* The tdesc nodes, hashed by type id */
+ list_t *td_fwdlist; /* All forward declaration tdesc nodes */
+
+ char *td_parlabel; /* Top label uniq'd against in parent */
+ char *td_parname; /* Basename of parent */
+ list_t *td_labels; /* Labels and their type ranges */
+
+ pthread_mutex_t td_mergelock;
+
+ int td_ref;
+} tdata_t;
+
+/*
+ * By design, the iidesc hash is heterogeneous. The CTF emitter, on the
+ * other hand, needs to be able to access the elements of the list by type,
+ * and in a specific sorted order. An iiburst holds these elements in that
+ * order. (A burster is a machine that separates carbon-copy forms)
+ */
+typedef struct iiburst {
+ int iib_nfuncs;
+ int iib_curfunc;
+ iidesc_t **iib_funcs;
+
+ int iib_nobjts;
+ int iib_curobjt;
+ iidesc_t **iib_objts;
+
+ list_t *iib_types;
+ int iib_maxtypeid;
+
+ tdata_t *iib_td;
+ struct tdtrav_data *iib_tdtd; /* tdtrav_data_t */
+} iiburst_t;
+
+typedef struct ctf_buf ctf_buf_t;
+
+typedef struct symit_data symit_data_t;
+
+/* fixup_tdescs.c */
+void cvt_fixstabs(tdata_t *);
+void cvt_fixups(tdata_t *, size_t);
+
+/* ctf.c */
+caddr_t ctf_gen(iiburst_t *, size_t *, int);
+tdata_t *ctf_load(char *, caddr_t, size_t, symit_data_t *, char *);
+
+/* iidesc.c */
+iidesc_t *iidesc_new(char *);
+int iidesc_hash(int, void *);
+void iter_iidescs_by_name(tdata_t *, const char *,
+ int (*)(void *, void *), void *);
+iidesc_t *iidesc_dup(iidesc_t *);
+iidesc_t *iidesc_dup_rename(iidesc_t *, char const *, char const *);
+void iidesc_add(hash_t *, iidesc_t *);
+void iidesc_free(void *, void *);
+int iidesc_count_type(void *, void *);
+void iidesc_stats(hash_t *);
+int iidesc_dump(iidesc_t *);
+
+/* input.c */
+typedef enum source_types {
+ SOURCE_NONE = 0,
+ SOURCE_UNKNOWN = 1,
+ SOURCE_C = 2,
+ SOURCE_S = 4
+} source_types_t;
+
+source_types_t built_source_types(Elf *, const char *);
+int count_files(char **, int);
+int read_ctf(char **, int, char *, int (*)(tdata_t *, char *, void *),
+ void *, int);
+int read_ctf_save_cb(tdata_t *, char *, void *);
+symit_data_t *symit_new(Elf *, const char *);
+void symit_reset(symit_data_t *);
+char *symit_curfile(symit_data_t *);
+GElf_Sym *symit_next(symit_data_t *, int);
+char *symit_name(symit_data_t *);
+void symit_free(symit_data_t *);
+
+/* merge.c */
+void merge_into_master(tdata_t *, tdata_t *, tdata_t *, int);
+
+/* output.c */
+#define CTF_FUZZY_MATCH 0x1 /* match local symbols to global CTF */
+#define CTF_USE_DYNSYM 0x2 /* use .dynsym not .symtab */
+#define CTF_COMPRESS 0x4 /* compress CTF output */
+#define CTF_KEEP_STABS 0x8 /* keep .stabs sections */
+#define CTF_SWAP_BYTES 0x10 /* target byte order is different from host */
+
+void write_ctf(tdata_t *, const char *, const char *, int);
+
+/* parse.c */
+void parse_init(tdata_t *);
+void parse_finish(tdata_t *);
+int parse_stab(stab_t *, char *, iidesc_t **);
+tdesc_t *lookup(int);
+tdesc_t *lookupname(const char *);
+void check_hash(void);
+void resolve_typed_bitfields(void);
+
+/* stabs.c */
+int stabs_read(tdata_t *, Elf *, char *);
+
+/* dwarf.c */
+int dw_read(tdata_t *, Elf *, char *);
+const char *dw_tag2str(uint_t);
+
+/* tdata.c */
+tdata_t *tdata_new(void);
+void tdata_free(tdata_t *);
+void tdata_build_hashes(tdata_t *td);
+const char *tdesc_name(tdesc_t *);
+int tdesc_idhash(int, void *);
+int tdesc_idcmp(void *, void *);
+int tdesc_namehash(int, void *);
+int tdesc_namecmp(void *, void *);
+int tdesc_layouthash(int, void *);
+int tdesc_layoutcmp(void *, void *);
+void tdesc_free(tdesc_t *);
+void tdata_label_add(tdata_t *, const char *, int);
+labelent_t *tdata_label_top(tdata_t *);
+int tdata_label_find(tdata_t *, char *);
+void tdata_label_free(tdata_t *);
+void tdata_merge(tdata_t *, tdata_t *);
+void tdata_label_newmax(tdata_t *, int);
+
+/* util.c */
+int streq(const char *, const char *);
+int findelfsecidx(Elf *, const char *, const char *);
+size_t elf_ptrsz(Elf *);
+char *mktmpname(const char *, const char *);
+void terminate(const char *, ...) __NORETURN;
+void aborterr(const char *, ...) __NORETURN;
+void set_terminate_cleanup(void (*)(void));
+void elfterminate(const char *, const char *, ...);
+void warning(const char *, ...);
+void vadebug(int, const char *, va_list);
+void debug(int, const char *, ...);
+
+
+void watch_dump(int);
+void watch_set(void *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CTFTOOLS_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
new file mode 100644
index 000000000000..32c993e1e524
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
@@ -0,0 +1,2019 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * DWARF to tdata conversion
+ *
+ * For the most part, conversion is straightforward, proceeding in two passes.
+ * On the first pass, we iterate through every die, creating new type nodes as
+ * necessary. Referenced tdesc_t's are created in an uninitialized state, thus
+ * allowing type reference pointers to be filled in. If the tdesc_t
+ * corresponding to a given die can be completely filled out (sizes and offsets
+ * calculated, and so forth) without using any referenced types, the tdesc_t is
+ * marked as resolved. Consider an array type. If the type corresponding to
+ * the array contents has not yet been processed, we will create a blank tdesc
+ * for the contents type (only the type ID will be filled in, relying upon the
+ * later portion of the first pass to encounter and complete the referenced
+ * type). We will then attempt to determine the size of the array. If the
+ * array has a byte size attribute, we will have completely characterized the
+ * array type, and will be able to mark it as resolved. The lack of a byte
+ * size attribute, on the other hand, will prevent us from fully resolving the
+ * type, as the size will only be calculable with reference to the contents
+ * type, which has not, as yet, been encountered. The array type will thus be
+ * left without the resolved flag, and the first pass will continue.
+ *
+ * When we begin the second pass, we will have created tdesc_t nodes for every
+ * type in the section. We will traverse the tree, from the iidescs down,
+ * processing each unresolved node. As the referenced nodes will have been
+ * populated, the array type used in our example above will be able to use the
+ * size of the referenced types (if available) to determine its own type. The
+ * traversal will be repeated until all types have been resolved or we have
+ * failed to make progress. When all tdescs have been resolved, the conversion
+ * is complete.
+ *
+ * There are, as always, a few special cases that are handled during the first
+ * and second passes:
+ *
+ * 1. Empty enums - GCC will occasionally emit an enum without any members.
+ * Later on in the file, it will emit the same enum type, though this time
+ * with the full complement of members. All references to the memberless
+ * enum need to be redirected to the full definition. During the first
+ * pass, each enum is entered in dm_enumhash, along with a pointer to its
+ * corresponding tdesc_t. If, during the second pass, we encounter a
+ * memberless enum, we use the hash to locate the full definition. All
+ * tdescs referencing the empty enum are then redirected.
+ *
+ * 2. Forward declarations - If the compiler sees a forward declaration for
+ * a structure, followed by the definition of that structure, it will emit
+ * DWARF data for both the forward declaration and the definition. We need
+ * to resolve the forward declarations when possible, by redirecting
+ * forward-referencing tdescs to the actual struct/union definitions. This
+ * redirection is done completely within the first pass. We begin by
+ * recording all forward declarations in dw_fwdhash. When we define a
+ * structure, we check to see if there have been any corresponding forward
+ * declarations. If so, we redirect the tdescs which referenced the forward
+ * declarations to the structure or union definition.
+ *
+ * XXX see if a post traverser will allow the elimination of repeated pass 2
+ * traversals.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <libelf.h>
+#include <libdwarf.h>
+#include <libgen.h>
+#include <dwarf.h>
+
+#include "ctf_headers.h"
+#include "ctftools.h"
+#include "memory.h"
+#include "list.h"
+#include "traverse.h"
+
+/*
+ * We need to define a couple of our own intrinsics, to smooth out some of the
+ * differences between the GCC and DevPro DWARF emitters. See the referenced
+ * routines and the special cases in the file comment for more details.
+ *
+ * Type IDs are 32 bits wide. We're going to use the top of that field to
+ * indicate types that we've created ourselves.
+ */
+#define TID_FILEMAX 0x3fffffff /* highest tid from file */
+#define TID_VOID 0x40000001 /* see die_void() */
+#define TID_LONG 0x40000002 /* see die_array() */
+
+#define TID_MFGTID_BASE 0x40000003 /* first mfg'd tid */
+
+/*
+ * To reduce the staggering amount of error-handling code that would otherwise
+ * be required, the attribute-retrieval routines handle most of their own
+ * errors. If the following flag is supplied as the value of the `req'
+ * argument, they will also handle the absence of a requested attribute by
+ * terminating the program.
+ */
+#define DW_ATTR_REQ 1
+
+#define TDESC_HASH_BUCKETS 511
+
+typedef struct dwarf {
+ Dwarf_Debug dw_dw; /* for libdwarf */
+ Dwarf_Error dw_err; /* for libdwarf */
+ Dwarf_Off dw_maxoff; /* highest legal offset in this cu */
+ tdata_t *dw_td; /* root of the tdesc/iidesc tree */
+ hash_t *dw_tidhash; /* hash of tdescs by t_id */
+ hash_t *dw_fwdhash; /* hash of fwd decls by name */
+ hash_t *dw_enumhash; /* hash of memberless enums by name */
+ tdesc_t *dw_void; /* manufactured void type */
+ tdesc_t *dw_long; /* manufactured long type for arrays */
+ size_t dw_ptrsz; /* size of a pointer in this file */
+ tid_t dw_mfgtid_last; /* last mfg'd type ID used */
+ uint_t dw_nunres; /* count of unresolved types */
+ char *dw_cuname; /* name of compilation unit */
+} dwarf_t;
+
+static void die_create_one(dwarf_t *, Dwarf_Die);
+static void die_create(dwarf_t *, Dwarf_Die);
+
+static tid_t
+mfgtid_next(dwarf_t *dw)
+{
+ return (++dw->dw_mfgtid_last);
+}
+
+static void
+tdesc_add(dwarf_t *dw, tdesc_t *tdp)
+{
+ hash_add(dw->dw_tidhash, tdp);
+}
+
+static tdesc_t *
+tdesc_lookup(dwarf_t *dw, int tid)
+{
+ tdesc_t tmpl;
+ void *tdp;
+
+ tmpl.t_id = tid;
+
+ if (hash_find(dw->dw_tidhash, &tmpl, &tdp))
+ return (tdp);
+ else
+ return (NULL);
+}
+
+/*
+ * Resolve a tdesc down to a node which should have a size. Returns the size,
+ * zero if the size hasn't yet been determined.
+ */
+static size_t
+tdesc_size(tdesc_t *tdp)
+{
+ for (;;) {
+ switch (tdp->t_type) {
+ case INTRINSIC:
+ case POINTER:
+ case ARRAY:
+ case FUNCTION:
+ case STRUCT:
+ case UNION:
+ case ENUM:
+ return (tdp->t_size);
+
+ case FORWARD:
+ return (0);
+
+ case TYPEDEF:
+ case VOLATILE:
+ case CONST:
+ case RESTRICT:
+ tdp = tdp->t_tdesc;
+ continue;
+
+ case 0: /* not yet defined */
+ return (0);
+
+ default:
+ terminate("tdp %u: tdesc_size on unknown type %d\n",
+ tdp->t_id, tdp->t_type);
+ }
+ }
+}
+
+static size_t
+tdesc_bitsize(tdesc_t *tdp)
+{
+ for (;;) {
+ switch (tdp->t_type) {
+ case INTRINSIC:
+ return (tdp->t_intr->intr_nbits);
+
+ case ARRAY:
+ case FUNCTION:
+ case STRUCT:
+ case UNION:
+ case ENUM:
+ case POINTER:
+ return (tdp->t_size * NBBY);
+
+ case FORWARD:
+ return (0);
+
+ case TYPEDEF:
+ case VOLATILE:
+ case RESTRICT:
+ case CONST:
+ tdp = tdp->t_tdesc;
+ continue;
+
+ case 0: /* not yet defined */
+ return (0);
+
+ default:
+ terminate("tdp %u: tdesc_bitsize on unknown type %d\n",
+ tdp->t_id, tdp->t_type);
+ }
+ }
+}
+
+static tdesc_t *
+tdesc_basetype(tdesc_t *tdp)
+{
+ for (;;) {
+ switch (tdp->t_type) {
+ case TYPEDEF:
+ case VOLATILE:
+ case RESTRICT:
+ case CONST:
+ tdp = tdp->t_tdesc;
+ break;
+ case 0: /* not yet defined */
+ return (NULL);
+ default:
+ return (tdp);
+ }
+ }
+}
+
+static Dwarf_Off
+die_off(dwarf_t *dw, Dwarf_Die die)
+{
+ Dwarf_Off off;
+
+ if (dwarf_dieoffset(die, &off, &dw->dw_err) == DW_DLV_OK)
+ return (off);
+
+ terminate("failed to get offset for die: %s\n",
+ dwarf_errmsg(dw->dw_err));
+ /*NOTREACHED*/
+ return (0);
+}
+
+static Dwarf_Die
+die_sibling(dwarf_t *dw, Dwarf_Die die)
+{
+ Dwarf_Die sib;
+ int rc;
+
+ if ((rc = dwarf_siblingof(dw->dw_dw, die, &sib, &dw->dw_err)) ==
+ DW_DLV_OK)
+ return (sib);
+ else if (rc == DW_DLV_NO_ENTRY)
+ return (NULL);
+
+ terminate("die %llu: failed to find type sibling: %s\n",
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
+ /*NOTREACHED*/
+ return (NULL);
+}
+
+static Dwarf_Die
+die_child(dwarf_t *dw, Dwarf_Die die)
+{
+ Dwarf_Die child;
+ int rc;
+
+ if ((rc = dwarf_child(die, &child, &dw->dw_err)) == DW_DLV_OK)
+ return (child);
+ else if (rc == DW_DLV_NO_ENTRY)
+ return (NULL);
+
+ terminate("die %llu: failed to find type child: %s\n",
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
+ /*NOTREACHED*/
+ return (NULL);
+}
+
+static Dwarf_Half
+die_tag(dwarf_t *dw, Dwarf_Die die)
+{
+ Dwarf_Half tag;
+
+ if (dwarf_tag(die, &tag, &dw->dw_err) == DW_DLV_OK)
+ return (tag);
+
+ terminate("die %llu: failed to get tag for type: %s\n",
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
+ /*NOTREACHED*/
+ return (0);
+}
+
+static Dwarf_Attribute
+die_attr(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, int req)
+{
+ Dwarf_Attribute attr;
+ int rc;
+
+ if ((rc = dwarf_attr(die, name, &attr, &dw->dw_err)) == DW_DLV_OK) {
+ return (attr);
+ } else if (rc == DW_DLV_NO_ENTRY) {
+ if (req) {
+ terminate("die %llu: no attr 0x%x\n", die_off(dw, die),
+ name);
+ } else {
+ return (NULL);
+ }
+ }
+
+ terminate("die %llu: failed to get attribute for type: %s\n",
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
+ /*NOTREACHED*/
+ return (NULL);
+}
+
+static int
+die_signed(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Signed *valp,
+ int req)
+{
+ *valp = 0;
+ if (dwarf_attrval_signed(die, name, valp, &dw->dw_err) != DW_DLV_OK) {
+ if (req)
+ terminate("die %llu: failed to get signed: %s\n",
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
+ return (0);
+ }
+
+ return (1);
+}
+
+static int
+die_unsigned(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Unsigned *valp,
+ int req)
+{
+ *valp = 0;
+ if (dwarf_attrval_unsigned(die, name, valp, &dw->dw_err) != DW_DLV_OK) {
+ if (req)
+ terminate("die %llu: failed to get unsigned: %s\n",
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
+ return (0);
+ }
+
+ return (1);
+}
+
+static int
+die_bool(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Bool *valp, int req)
+{
+ *valp = 0;
+
+ if (dwarf_attrval_flag(die, name, valp, &dw->dw_err) != DW_DLV_OK) {
+ if (req)
+ terminate("die %llu: failed to get flag: %s\n",
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
+ return (0);
+ }
+
+ return (1);
+}
+
+static int
+die_string(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, char **strp, int req)
+{
+ const char *str = NULL;
+
+ if (dwarf_attrval_string(die, name, &str, &dw->dw_err) != DW_DLV_OK ||
+ str == NULL) {
+ if (req)
+ terminate("die %llu: failed to get string: %s\n",
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
+ else
+ *strp = NULL;
+ return (0);
+ } else
+ *strp = xstrdup(str);
+
+ return (1);
+}
+
+static Dwarf_Off
+die_attr_ref(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name)
+{
+ Dwarf_Off off;
+
+ if (dwarf_attrval_unsigned(die, name, &off, &dw->dw_err) != DW_DLV_OK) {
+ terminate("die %llu: failed to get ref: %s\n",
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
+ }
+
+ return (off);
+}
+
+static char *
+die_name(dwarf_t *dw, Dwarf_Die die)
+{
+ char *str = NULL;
+
+ (void) die_string(dw, die, DW_AT_name, &str, 0);
+ if (str == NULL)
+ str = xstrdup("");
+
+ return (str);
+}
+
+static int
+die_isdecl(dwarf_t *dw, Dwarf_Die die)
+{
+ Dwarf_Bool val;
+
+ return (die_bool(dw, die, DW_AT_declaration, &val, 0) && val);
+}
+
+static int
+die_isglobal(dwarf_t *dw, Dwarf_Die die)
+{
+ Dwarf_Signed vis;
+ Dwarf_Bool ext;
+
+ /*
+ * Some compilers (gcc) use DW_AT_external to indicate function
+ * visibility. Others (Sun) use DW_AT_visibility.
+ */
+ if (die_signed(dw, die, DW_AT_visibility, &vis, 0))
+ return (vis == DW_VIS_exported);
+ else
+ return (die_bool(dw, die, DW_AT_external, &ext, 0) && ext);
+}
+
+static tdesc_t *
+die_add(dwarf_t *dw, Dwarf_Off off)
+{
+ tdesc_t *tdp = xcalloc(sizeof (tdesc_t));
+
+ tdp->t_id = off;
+
+ tdesc_add(dw, tdp);
+
+ return (tdp);
+}
+
+static tdesc_t *
+die_lookup_pass1(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name)
+{
+ Dwarf_Off ref = die_attr_ref(dw, die, name);
+ tdesc_t *tdp;
+
+ if ((tdp = tdesc_lookup(dw, ref)) != NULL)
+ return (tdp);
+
+ return (die_add(dw, ref));
+}
+
+static int
+die_mem_offset(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Unsigned *valp, int req __unused)
+{
+ Dwarf_Locdesc *loc = NULL;
+ Dwarf_Signed locnum = 0;
+ Dwarf_Attribute at;
+ Dwarf_Half form;
+
+ if (name != DW_AT_data_member_location)
+ terminate("die %llu: can only process attribute "
+ "DW_AT_data_member_location\n", die_off(dw, die));
+
+ if ((at = die_attr(dw, die, name, 0)) == NULL)
+ return (0);
+
+ if (dwarf_whatform(at, &form, &dw->dw_err) != DW_DLV_OK)
+ return (0);
+
+ switch (form) {
+ case DW_FORM_sec_offset:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ /*
+ * GCC in base and Clang (3.3 or below) generates
+ * DW_AT_data_member_location attribute with DW_FORM_block*
+ * form. The attribute contains one DW_OP_plus_uconst
+ * operator. The member offset stores in the operand.
+ */
+ if (dwarf_loclist(at, &loc, &locnum, &dw->dw_err) != DW_DLV_OK)
+ return (0);
+ if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) {
+ terminate("die %llu: cannot parse member offset with "
+ "operator other than DW_OP_plus_uconst\n",
+ die_off(dw, die));
+ }
+ *valp = loc->ld_s->lr_number;
+ if (loc != NULL) {
+ dwarf_dealloc(dw->dw_dw, loc->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(dw->dw_dw, loc, DW_DLA_LOCDESC);
+ }
+ break;
+
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_udata:
+ /*
+ * Clang 3.4 generates DW_AT_data_member_location attribute
+ * with DW_FORM_data* form (constant class). The attribute
+ * stores a contant value which is the member offset.
+ *
+ * However, note that DW_FORM_data[48] in DWARF version 2 or 3
+ * could be used as a section offset (offset into .debug_loc in
+ * this case). Here we assume the attribute always stores a
+ * constant because we know Clang 3.4 does this and GCC in
+ * base won't emit DW_FORM_data[48] for this attribute. This
+ * code will remain correct if future vesrions of Clang and
+ * GCC conform to DWARF4 standard and only use the form
+ * DW_FORM_sec_offset for section offset.
+ */
+ if (dwarf_attrval_unsigned(die, name, valp, &dw->dw_err) !=
+ DW_DLV_OK)
+ return (0);
+ break;
+
+ default:
+ terminate("die %llu: cannot parse member offset with form "
+ "%u\n", die_off(dw, die), form);
+ }
+
+ return (1);
+}
+
+static tdesc_t *
+tdesc_intr_common(dwarf_t *dw, int tid, const char *name, size_t sz)
+{
+ tdesc_t *tdp;
+ intr_t *intr;
+
+ intr = xcalloc(sizeof (intr_t));
+ intr->intr_type = INTR_INT;
+ intr->intr_signed = 1;
+ intr->intr_nbits = sz * NBBY;
+
+ tdp = xcalloc(sizeof (tdesc_t));
+ tdp->t_name = xstrdup(name);
+ tdp->t_size = sz;
+ tdp->t_id = tid;
+ tdp->t_type = INTRINSIC;
+ tdp->t_intr = intr;
+ tdp->t_flags = TDESC_F_RESOLVED;
+
+ tdesc_add(dw, tdp);
+
+ return (tdp);
+}
+
+/*
+ * Manufacture a void type. Used for gcc-emitted stabs, where the lack of a
+ * type reference implies a reference to a void type. A void *, for example
+ * will be represented by a pointer die without a DW_AT_type. CTF requires
+ * that pointer nodes point to something, so we'll create a void for use as
+ * the target. Note that the DWARF data may already create a void type. Ours
+ * would then be a duplicate, but it'll be removed in the self-uniquification
+ * merge performed at the completion of DWARF->tdesc conversion.
+ */
+static tdesc_t *
+tdesc_intr_void(dwarf_t *dw)
+{
+ if (dw->dw_void == NULL)
+ dw->dw_void = tdesc_intr_common(dw, TID_VOID, "void", 0);
+
+ return (dw->dw_void);
+}
+
+static tdesc_t *
+tdesc_intr_long(dwarf_t *dw)
+{
+ if (dw->dw_long == NULL) {
+ dw->dw_long = tdesc_intr_common(dw, TID_LONG, "long",
+ dw->dw_ptrsz);
+ }
+
+ return (dw->dw_long);
+}
+
+/*
+ * Used for creating bitfield types. We create a copy of an existing intrinsic,
+ * adjusting the size of the copy to match what the caller requested. The
+ * caller can then use the copy as the type for a bitfield structure member.
+ */
+static tdesc_t *
+tdesc_intr_clone(dwarf_t *dw, tdesc_t *old, size_t bitsz)
+{
+ tdesc_t *new = xcalloc(sizeof (tdesc_t));
+
+ if (!(old->t_flags & TDESC_F_RESOLVED)) {
+ terminate("tdp %u: attempt to make a bit field from an "
+ "unresolved type\n", old->t_id);
+ }
+
+ new->t_name = xstrdup(old->t_name);
+ new->t_size = old->t_size;
+ new->t_id = mfgtid_next(dw);
+ new->t_type = INTRINSIC;
+ new->t_flags = TDESC_F_RESOLVED;
+
+ new->t_intr = xcalloc(sizeof (intr_t));
+ bcopy(old->t_intr, new->t_intr, sizeof (intr_t));
+ new->t_intr->intr_nbits = bitsz;
+
+ tdesc_add(dw, new);
+
+ return (new);
+}
+
+static void
+tdesc_array_create(dwarf_t *dw, Dwarf_Die dim, tdesc_t *arrtdp,
+ tdesc_t *dimtdp)
+{
+ Dwarf_Unsigned uval;
+ Dwarf_Signed sval;
+ tdesc_t *ctdp = NULL;
+ Dwarf_Die dim2;
+ ardef_t *ar;
+
+ if ((dim2 = die_sibling(dw, dim)) == NULL) {
+ ctdp = arrtdp;
+ } else if (die_tag(dw, dim2) == DW_TAG_subrange_type) {
+ ctdp = xcalloc(sizeof (tdesc_t));
+ ctdp->t_id = mfgtid_next(dw);
+ debug(3, "die %llu: creating new type %u for sub-dimension\n",
+ die_off(dw, dim2), ctdp->t_id);
+ tdesc_array_create(dw, dim2, arrtdp, ctdp);
+ } else {
+ terminate("die %llu: unexpected non-subrange node in array\n",
+ die_off(dw, dim2));
+ }
+
+ dimtdp->t_type = ARRAY;
+ dimtdp->t_ardef = ar = xcalloc(sizeof (ardef_t));
+
+ /*
+ * Array bounds can be signed or unsigned, but there are several kinds
+ * of signless forms (data1, data2, etc) that take their sign from the
+ * routine that is trying to interpret them. That is, data1 can be
+ * either signed or unsigned, depending on whether you use the signed or
+ * unsigned accessor function. GCC will use the signless forms to store
+ * unsigned values which have their high bit set, so we need to try to
+ * read them first as unsigned to get positive values. We could also
+ * try signed first, falling back to unsigned if we got a negative
+ * value.
+ */
+ if (die_unsigned(dw, dim, DW_AT_upper_bound, &uval, 0))
+ ar->ad_nelems = uval + 1;
+ else if (die_signed(dw, dim, DW_AT_upper_bound, &sval, 0))
+ ar->ad_nelems = sval + 1;
+ else if (die_unsigned(dw, dim, DW_AT_count, &uval, 0))
+ ar->ad_nelems = uval;
+ else if (die_signed(dw, dim, DW_AT_count, &sval, 0))
+ ar->ad_nelems = sval;
+ else
+ ar->ad_nelems = 0;
+
+ /*
+ * Different compilers use different index types. Force the type to be
+ * a common, known value (long).
+ */
+ ar->ad_idxtype = tdesc_intr_long(dw);
+ ar->ad_contents = ctdp;
+
+ if (ar->ad_contents->t_size != 0) {
+ dimtdp->t_size = ar->ad_contents->t_size * ar->ad_nelems;
+ dimtdp->t_flags |= TDESC_F_RESOLVED;
+ }
+}
+
+/*
+ * Create a tdesc from an array node. Some arrays will come with byte size
+ * attributes, and thus can be resolved immediately. Others don't, and will
+ * need to wait until the second pass for resolution.
+ */
+static void
+die_array_create(dwarf_t *dw, Dwarf_Die arr, Dwarf_Off off, tdesc_t *tdp)
+{
+ tdesc_t *arrtdp = die_lookup_pass1(dw, arr, DW_AT_type);
+ Dwarf_Unsigned uval;
+ Dwarf_Die dim;
+
+ debug(3, "die %llu <%llx>: creating array\n", off, off);
+
+ if ((dim = die_child(dw, arr)) == NULL ||
+ die_tag(dw, dim) != DW_TAG_subrange_type)
+ terminate("die %llu: failed to retrieve array bounds\n", off);
+
+ tdesc_array_create(dw, dim, arrtdp, tdp);
+
+ if (die_unsigned(dw, arr, DW_AT_byte_size, &uval, 0)) {
+ tdesc_t *dimtdp;
+ int flags;
+
+ tdp->t_size = uval;
+
+ /*
+ * Ensure that sub-dimensions have sizes too before marking
+ * as resolved.
+ */
+ flags = TDESC_F_RESOLVED;
+ for (dimtdp = tdp->t_ardef->ad_contents;
+ dimtdp->t_type == ARRAY;
+ dimtdp = dimtdp->t_ardef->ad_contents) {
+ if (!(dimtdp->t_flags & TDESC_F_RESOLVED)) {
+ flags = 0;
+ break;
+ }
+ }
+
+ tdp->t_flags |= flags;
+ }
+
+ debug(3, "die %llu <%llx>: array nelems %u size %u\n", off, off,
+ tdp->t_ardef->ad_nelems, tdp->t_size);
+}
+
+/*ARGSUSED1*/
+static int
+die_array_resolve(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private)
+{
+ dwarf_t *dw = private;
+ size_t sz;
+
+ if (tdp->t_flags & TDESC_F_RESOLVED)
+ return (1);
+
+ debug(3, "trying to resolve array %d (cont %d)\n", tdp->t_id,
+ tdp->t_ardef->ad_contents->t_id);
+
+ if ((sz = tdesc_size(tdp->t_ardef->ad_contents)) == 0 &&
+ (tdp->t_ardef->ad_contents->t_flags & TDESC_F_RESOLVED) == 0) {
+ debug(3, "unable to resolve array %s (%d) contents %d\n",
+ tdesc_name(tdp), tdp->t_id,
+ tdp->t_ardef->ad_contents->t_id);
+
+ dw->dw_nunres++;
+ return (1);
+ }
+
+ tdp->t_size = sz * tdp->t_ardef->ad_nelems;
+ tdp->t_flags |= TDESC_F_RESOLVED;
+
+ debug(3, "resolved array %d: %u bytes\n", tdp->t_id, tdp->t_size);
+
+ return (1);
+}
+
+/*ARGSUSED1*/
+static int
+die_array_failed(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private __unused)
+{
+ tdesc_t *cont = tdp->t_ardef->ad_contents;
+
+ if (tdp->t_flags & TDESC_F_RESOLVED)
+ return (1);
+
+ fprintf(stderr, "Array %d: failed to size contents type %s (%d)\n",
+ tdp->t_id, tdesc_name(cont), cont->t_id);
+
+ return (1);
+}
+
+/*
+ * Most enums (those with members) will be resolved during this first pass.
+ * Others - those without members (see the file comment) - won't be, and will
+ * need to wait until the second pass when they can be matched with their full
+ * definitions.
+ */
+static void
+die_enum_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp)
+{
+ Dwarf_Die mem;
+ Dwarf_Unsigned uval;
+ Dwarf_Signed sval;
+
+ if (die_isdecl(dw, die)) {
+ tdp->t_type = FORWARD;
+ return;
+ }
+
+ debug(3, "die %llu: creating enum\n", off);
+
+ tdp->t_type = ENUM;
+
+ (void) die_unsigned(dw, die, DW_AT_byte_size, &uval, DW_ATTR_REQ);
+ tdp->t_size = uval;
+
+ if ((mem = die_child(dw, die)) != NULL) {
+ elist_t **elastp = &tdp->t_emem;
+
+ do {
+ elist_t *el;
+
+ if (die_tag(dw, mem) != DW_TAG_enumerator) {
+ /* Nested type declaration */
+ die_create_one(dw, mem);
+ continue;
+ }
+
+ el = xcalloc(sizeof (elist_t));
+ el->el_name = die_name(dw, mem);
+
+ if (die_signed(dw, mem, DW_AT_const_value, &sval, 0)) {
+ el->el_number = sval;
+ } else if (die_unsigned(dw, mem, DW_AT_const_value,
+ &uval, 0)) {
+ el->el_number = uval;
+ } else {
+ terminate("die %llu: enum %llu: member without "
+ "value\n", off, die_off(dw, mem));
+ }
+
+ debug(3, "die %llu: enum %llu: created %s = %d\n", off,
+ die_off(dw, mem), el->el_name, el->el_number);
+
+ *elastp = el;
+ elastp = &el->el_next;
+
+ } while ((mem = die_sibling(dw, mem)) != NULL);
+
+ hash_add(dw->dw_enumhash, tdp);
+
+ tdp->t_flags |= TDESC_F_RESOLVED;
+
+ if (tdp->t_name != NULL) {
+ iidesc_t *ii = xcalloc(sizeof (iidesc_t));
+ ii->ii_type = II_SOU;
+ ii->ii_name = xstrdup(tdp->t_name);
+ ii->ii_dtype = tdp;
+
+ iidesc_add(dw->dw_td->td_iihash, ii);
+ }
+ }
+}
+
+static int
+die_enum_match(void *arg1, void *arg2)
+{
+ tdesc_t *tdp = arg1, **fullp = arg2;
+
+ if (tdp->t_emem != NULL) {
+ *fullp = tdp;
+ return (-1); /* stop the iteration */
+ }
+
+ return (0);
+}
+
+/*ARGSUSED1*/
+static int
+die_enum_resolve(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private)
+{
+ dwarf_t *dw = private;
+ tdesc_t *full = NULL;
+
+ if (tdp->t_flags & TDESC_F_RESOLVED)
+ return (1);
+
+ (void) hash_find_iter(dw->dw_enumhash, tdp, die_enum_match, &full);
+
+ /*
+ * The answer to this one won't change from iteration to iteration,
+ * so don't even try.
+ */
+ if (full == NULL) {
+ terminate("tdp %u: enum %s has no members\n", tdp->t_id,
+ tdesc_name(tdp));
+ }
+
+ debug(3, "tdp %u: enum %s redirected to %u\n", tdp->t_id,
+ tdesc_name(tdp), full->t_id);
+
+ tdp->t_flags |= TDESC_F_RESOLVED;
+
+ return (1);
+}
+
+static int
+die_fwd_map(void *arg1, void *arg2)
+{
+ tdesc_t *fwd = arg1, *sou = arg2;
+
+ debug(3, "tdp %u: mapped forward %s to sou %u\n", fwd->t_id,
+ tdesc_name(fwd), sou->t_id);
+ fwd->t_tdesc = sou;
+
+ return (0);
+}
+
+/*
+ * Structures and unions will never be resolved during the first pass, as we
+ * won't be able to fully determine the member sizes. The second pass, which
+ * have access to sizing information, will be able to complete the resolution.
+ */
+static void
+die_sou_create(dwarf_t *dw, Dwarf_Die str, Dwarf_Off off, tdesc_t *tdp,
+ int type, const char *typename)
+{
+ Dwarf_Unsigned sz, bitsz, bitoff;
+#if BYTE_ORDER == _LITTLE_ENDIAN
+ Dwarf_Unsigned bysz;
+#endif
+ Dwarf_Die mem;
+ mlist_t *ml, **mlastp;
+ iidesc_t *ii;
+
+ tdp->t_type = (die_isdecl(dw, str) ? FORWARD : type);
+
+ debug(3, "die %llu: creating %s %s\n", off,
+ (tdp->t_type == FORWARD ? "forward decl" : typename),
+ tdesc_name(tdp));
+
+ if (tdp->t_type == FORWARD) {
+ hash_add(dw->dw_fwdhash, tdp);
+ return;
+ }
+
+ (void) hash_find_iter(dw->dw_fwdhash, tdp, die_fwd_map, tdp);
+
+ (void) die_unsigned(dw, str, DW_AT_byte_size, &sz, DW_ATTR_REQ);
+ tdp->t_size = sz;
+
+ /*
+ * GCC allows empty SOUs as an extension.
+ */
+ if ((mem = die_child(dw, str)) == NULL) {
+ goto out;
+ }
+
+ mlastp = &tdp->t_members;
+
+ do {
+ Dwarf_Off memoff = die_off(dw, mem);
+ Dwarf_Half tag = die_tag(dw, mem);
+ Dwarf_Unsigned mloff;
+
+ if (tag != DW_TAG_member) {
+ /* Nested type declaration */
+ die_create_one(dw, mem);
+ continue;
+ }
+
+ debug(3, "die %llu: mem %llu: creating member\n", off, memoff);
+
+ ml = xcalloc(sizeof (mlist_t));
+
+ /*
+ * This could be a GCC anon struct/union member, so we'll allow
+ * an empty name, even though nothing can really handle them
+ * properly. Note that some versions of GCC miss out debug
+ * info for anon structs, though recent versions are fixed (gcc
+ * bug 11816).
+ */
+ if ((ml->ml_name = die_name(dw, mem)) == NULL)
+ ml->ml_name = NULL;
+
+ ml->ml_type = die_lookup_pass1(dw, mem, DW_AT_type);
+
+ if (die_mem_offset(dw, mem, DW_AT_data_member_location,
+ &mloff, 0)) {
+ debug(3, "die %llu: got mloff %llx\n", off,
+ (u_longlong_t)mloff);
+ ml->ml_offset = mloff * 8;
+ }
+
+ if (die_unsigned(dw, mem, DW_AT_bit_size, &bitsz, 0))
+ ml->ml_size = bitsz;
+ else
+ ml->ml_size = tdesc_bitsize(ml->ml_type);
+
+ if (die_unsigned(dw, mem, DW_AT_bit_offset, &bitoff, 0)) {
+#if BYTE_ORDER == _BIG_ENDIAN
+ ml->ml_offset += bitoff;
+#else
+ /*
+ * Note that Clang 3.4 will sometimes generate
+ * member DIE before generating the DIE for the
+ * member's type. The code can not handle this
+ * properly so that tdesc_bitsize(ml->ml_type) will
+ * return 0 because ml->ml_type is unknown. As a
+ * result, a wrong member offset will be calculated.
+ * To workaround this, we can instead try to
+ * retrieve the value of DW_AT_byte_size attribute
+ * which stores the byte size of the space occupied
+ * by the type. If this attribute exists, its value
+ * should equal to tdesc_bitsize(ml->ml_type)/NBBY.
+ */
+ if (die_unsigned(dw, mem, DW_AT_byte_size, &bysz, 0) &&
+ bysz > 0)
+ ml->ml_offset += bysz * NBBY - bitoff -
+ ml->ml_size;
+ else
+ ml->ml_offset += tdesc_bitsize(ml->ml_type) -
+ bitoff - ml->ml_size;
+#endif
+ }
+
+ debug(3, "die %llu: mem %llu: created \"%s\" (off %u sz %u)\n",
+ off, memoff, ml->ml_name, ml->ml_offset, ml->ml_size);
+
+ *mlastp = ml;
+ mlastp = &ml->ml_next;
+ } while ((mem = die_sibling(dw, mem)) != NULL);
+
+ /*
+ * GCC will attempt to eliminate unused types, thus decreasing the
+ * size of the emitted dwarf. That is, if you declare a foo_t in your
+ * header, include said header in your source file, and neglect to
+ * actually use (directly or indirectly) the foo_t in the source file,
+ * the foo_t won't make it into the emitted DWARF. So, at least, goes
+ * the theory.
+ *
+ * Occasionally, it'll emit the DW_TAG_structure_type for the foo_t,
+ * and then neglect to emit the members. Strangely, the loner struct
+ * tag will always be followed by a proper nested declaration of
+ * something else. This is clearly a bug, but we're not going to have
+ * time to get it fixed before this goo goes back, so we'll have to work
+ * around it. If we see a no-membered struct with a nested declaration
+ * (i.e. die_child of the struct tag won't be null), we'll ignore it.
+ * Being paranoid, we won't simply remove it from the hash. Instead,
+ * we'll decline to create an iidesc for it, thus ensuring that this
+ * type won't make it into the output file. To be safe, we'll also
+ * change the name.
+ */
+ if (tdp->t_members == NULL) {
+ const char *old = tdesc_name(tdp);
+ size_t newsz = 7 + strlen(old) + 1;
+ char *new = xmalloc(newsz);
+ (void) snprintf(new, newsz, "orphan %s", old);
+
+ debug(3, "die %llu: worked around %s %s\n", off, typename, old);
+
+ if (tdp->t_name != NULL)
+ free(tdp->t_name);
+ tdp->t_name = new;
+ return;
+ }
+
+out:
+ if (tdp->t_name != NULL) {
+ ii = xcalloc(sizeof (iidesc_t));
+ ii->ii_type = II_SOU;
+ ii->ii_name = xstrdup(tdp->t_name);
+ ii->ii_dtype = tdp;
+
+ iidesc_add(dw->dw_td->td_iihash, ii);
+ }
+}
+
+static void
+die_struct_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp)
+{
+ die_sou_create(dw, die, off, tdp, STRUCT, "struct");
+}
+
+static void
+die_union_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp)
+{
+ die_sou_create(dw, die, off, tdp, UNION, "union");
+}
+
+/*ARGSUSED1*/
+static int
+die_sou_resolve(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private)
+{
+ dwarf_t *dw = private;
+ mlist_t *ml;
+ tdesc_t *mt;
+
+ if (tdp->t_flags & TDESC_F_RESOLVED)
+ return (1);
+
+ debug(3, "resolving sou %s\n", tdesc_name(tdp));
+
+ for (ml = tdp->t_members; ml != NULL; ml = ml->ml_next) {
+ if (ml->ml_size == 0) {
+ mt = tdesc_basetype(ml->ml_type);
+
+ if ((ml->ml_size = tdesc_bitsize(mt)) != 0)
+ continue;
+
+ /*
+ * For empty members, or GCC/C99 flexible array
+ * members, a size of 0 is correct. Structs and unions
+ * consisting of flexible array members will also have
+ * size 0.
+ */
+ if (mt->t_members == NULL)
+ continue;
+ if (mt->t_type == ARRAY && mt->t_ardef->ad_nelems == 0)
+ continue;
+ if ((mt->t_flags & TDESC_F_RESOLVED) != 0 &&
+ (mt->t_type == STRUCT || mt->t_type == UNION))
+ continue;
+
+ dw->dw_nunres++;
+ return (1);
+ }
+
+ if ((mt = tdesc_basetype(ml->ml_type)) == NULL) {
+ dw->dw_nunres++;
+ return (1);
+ }
+
+ if (ml->ml_size != 0 && mt->t_type == INTRINSIC &&
+ mt->t_intr->intr_nbits != ml->ml_size) {
+ /*
+ * This member is a bitfield, and needs to reference
+ * an intrinsic type with the same width. If the
+ * currently-referenced type isn't of the same width,
+ * we'll copy it, adjusting the width of the copy to
+ * the size we'd like.
+ */
+ debug(3, "tdp %u: creating bitfield for %d bits\n",
+ tdp->t_id, ml->ml_size);
+
+ ml->ml_type = tdesc_intr_clone(dw, mt, ml->ml_size);
+ }
+ }
+
+ tdp->t_flags |= TDESC_F_RESOLVED;
+
+ return (1);
+}
+
+/*ARGSUSED1*/
+static int
+die_sou_failed(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private __unused)
+{
+ const char *typename = (tdp->t_type == STRUCT ? "struct" : "union");
+ mlist_t *ml;
+
+ if (tdp->t_flags & TDESC_F_RESOLVED)
+ return (1);
+
+ for (ml = tdp->t_members; ml != NULL; ml = ml->ml_next) {
+ if (ml->ml_size == 0) {
+ fprintf(stderr, "%s %d <%x>: failed to size member \"%s\" "
+ "of type %s (%d <%x>)\n", typename, tdp->t_id,
+ tdp->t_id,
+ ml->ml_name, tdesc_name(ml->ml_type),
+ ml->ml_type->t_id, ml->ml_type->t_id);
+ }
+ }
+
+ return (1);
+}
+
+static void
+die_funcptr_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp)
+{
+ Dwarf_Attribute attr;
+ Dwarf_Half tag;
+ Dwarf_Die arg;
+ fndef_t *fn;
+ int i;
+
+ debug(3, "die %llu <%llx>: creating function pointer\n", off, off);
+
+ /*
+ * We'll begin by processing any type definition nodes that may be
+ * lurking underneath this one.
+ */
+ for (arg = die_child(dw, die); arg != NULL;
+ arg = die_sibling(dw, arg)) {
+ if ((tag = die_tag(dw, arg)) != DW_TAG_formal_parameter &&
+ tag != DW_TAG_unspecified_parameters) {
+ /* Nested type declaration */
+ die_create_one(dw, arg);
+ }
+ }
+
+ if (die_isdecl(dw, die)) {
+ /*
+ * This is a prototype. We don't add prototypes to the
+ * tree, so we're going to drop the tdesc. Unfortunately,
+ * it has already been added to the tree. Nobody will reference
+ * it, though, and it will be leaked.
+ */
+ return;
+ }
+
+ fn = xcalloc(sizeof (fndef_t));
+
+ tdp->t_type = FUNCTION;
+
+ if ((attr = die_attr(dw, die, DW_AT_type, 0)) != NULL) {
+ fn->fn_ret = die_lookup_pass1(dw, die, DW_AT_type);
+ } else {
+ fn->fn_ret = tdesc_intr_void(dw);
+ }
+
+ /*
+ * Count the arguments to the function, then read them in.
+ */
+ for (fn->fn_nargs = 0, arg = die_child(dw, die); arg != NULL;
+ arg = die_sibling(dw, arg)) {
+ if ((tag = die_tag(dw, arg)) == DW_TAG_formal_parameter)
+ fn->fn_nargs++;
+ else if (tag == DW_TAG_unspecified_parameters &&
+ fn->fn_nargs > 0)
+ fn->fn_vargs = 1;
+ }
+
+ if (fn->fn_nargs != 0) {
+ debug(3, "die %llu: adding %d argument%s\n", off, fn->fn_nargs,
+ (fn->fn_nargs > 1 ? "s" : ""));
+
+ fn->fn_args = xcalloc(sizeof (tdesc_t *) * fn->fn_nargs);
+ for (i = 0, arg = die_child(dw, die);
+ arg != NULL && i < (int) fn->fn_nargs;
+ arg = die_sibling(dw, arg)) {
+ if (die_tag(dw, arg) != DW_TAG_formal_parameter)
+ continue;
+
+ fn->fn_args[i++] = die_lookup_pass1(dw, arg,
+ DW_AT_type);
+ }
+ }
+
+ tdp->t_fndef = fn;
+ tdp->t_flags |= TDESC_F_RESOLVED;
+}
+
+/*
+ * GCC and DevPro use different names for the base types. While the terms are
+ * the same, they are arranged in a different order. Some terms, such as int,
+ * are implied in one, and explicitly named in the other. Given a base type
+ * as input, this routine will return a common name, along with an intr_t
+ * that reflects said name.
+ */
+static intr_t *
+die_base_name_parse(const char *name, char **newp)
+{
+ char buf[256];
+ char const *base;
+ char *c;
+ int nlong = 0, nshort = 0, nchar = 0, nint = 0;
+ int sign = 1;
+ char fmt = '\0';
+ intr_t *intr;
+
+ if (strlen(name) > sizeof (buf) - 1)
+ terminate("base type name \"%s\" is too long\n", name);
+
+ strncpy(buf, name, sizeof (buf));
+
+ for (c = strtok(buf, " "); c != NULL; c = strtok(NULL, " ")) {
+ if (strcmp(c, "signed") == 0)
+ sign = 1;
+ else if (strcmp(c, "unsigned") == 0)
+ sign = 0;
+ else if (strcmp(c, "long") == 0)
+ nlong++;
+ else if (strcmp(c, "char") == 0) {
+ nchar++;
+ fmt = 'c';
+ } else if (strcmp(c, "short") == 0)
+ nshort++;
+ else if (strcmp(c, "int") == 0)
+ nint++;
+ else {
+ /*
+ * If we don't recognize any of the tokens, we'll tell
+ * the caller to fall back to the dwarf-provided
+ * encoding information.
+ */
+ return (NULL);
+ }
+ }
+
+ if (nchar > 1 || nshort > 1 || nint > 1 || nlong > 2)
+ return (NULL);
+
+ if (nchar > 0) {
+ if (nlong > 0 || nshort > 0 || nint > 0)
+ return (NULL);
+
+ base = "char";
+
+ } else if (nshort > 0) {
+ if (nlong > 0)
+ return (NULL);
+
+ base = "short";
+
+ } else if (nlong > 0) {
+ base = "long";
+
+ } else {
+ base = "int";
+ }
+
+ intr = xcalloc(sizeof (intr_t));
+ intr->intr_type = INTR_INT;
+ intr->intr_signed = sign;
+ intr->intr_iformat = fmt;
+
+ snprintf(buf, sizeof (buf), "%s%s%s",
+ (sign ? "" : "unsigned "),
+ (nlong > 1 ? "long " : ""),
+ base);
+
+ *newp = xstrdup(buf);
+ return (intr);
+}
+
+typedef struct fp_size_map {
+ size_t fsm_typesz[2]; /* size of {32,64} type */
+ uint_t fsm_enc[3]; /* CTF_FP_* for {bare,cplx,imagry} type */
+} fp_size_map_t;
+
+static const fp_size_map_t fp_encodings[] = {
+ { { 4, 4 }, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { { 8, 8 }, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+#ifdef __sparc
+ { { 16, 16 }, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+#else
+ { { 12, 16 }, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+#endif
+ { { 0, 0 }, { 0, 0, 0 } }
+};
+
+static uint_t
+die_base_type2enc(dwarf_t *dw, Dwarf_Off off, Dwarf_Signed enc, size_t sz)
+{
+ const fp_size_map_t *map = fp_encodings;
+ uint_t szidx = dw->dw_ptrsz == sizeof (uint64_t);
+ uint_t mult = 1, col = 0;
+
+ if (enc == DW_ATE_complex_float) {
+ mult = 2;
+ col = 1;
+ } else if (enc == DW_ATE_imaginary_float
+#ifdef illumos
+ || enc == DW_ATE_SUN_imaginary_float
+#endif
+ )
+ col = 2;
+
+ while (map->fsm_typesz[szidx] != 0) {
+ if (map->fsm_typesz[szidx] * mult == sz)
+ return (map->fsm_enc[col]);
+ map++;
+ }
+
+ terminate("die %llu: unrecognized real type size %u\n", off, sz);
+ /*NOTREACHED*/
+ return (0);
+}
+
+static intr_t *
+die_base_from_dwarf(dwarf_t *dw, Dwarf_Die base, Dwarf_Off off, size_t sz)
+{
+ intr_t *intr = xcalloc(sizeof (intr_t));
+ Dwarf_Signed enc;
+
+ (void) die_signed(dw, base, DW_AT_encoding, &enc, DW_ATTR_REQ);
+
+ switch (enc) {
+ case DW_ATE_unsigned:
+ case DW_ATE_address:
+ intr->intr_type = INTR_INT;
+ break;
+ case DW_ATE_unsigned_char:
+ intr->intr_type = INTR_INT;
+ intr->intr_iformat = 'c';
+ break;
+ case DW_ATE_signed:
+ intr->intr_type = INTR_INT;
+ intr->intr_signed = 1;
+ break;
+ case DW_ATE_signed_char:
+ intr->intr_type = INTR_INT;
+ intr->intr_signed = 1;
+ intr->intr_iformat = 'c';
+ break;
+ case DW_ATE_boolean:
+ intr->intr_type = INTR_INT;
+ intr->intr_signed = 1;
+ intr->intr_iformat = 'b';
+ break;
+ case DW_ATE_float:
+ case DW_ATE_complex_float:
+ case DW_ATE_imaginary_float:
+#ifdef illumos
+ case DW_ATE_SUN_imaginary_float:
+ case DW_ATE_SUN_interval_float:
+#endif
+ intr->intr_type = INTR_REAL;
+ intr->intr_signed = 1;
+ intr->intr_fformat = die_base_type2enc(dw, off, enc, sz);
+ break;
+ default:
+ terminate("die %llu: unknown base type encoding 0x%llx\n",
+ off, enc);
+ }
+
+ return (intr);
+}
+
+static void
+die_base_create(dwarf_t *dw, Dwarf_Die base, Dwarf_Off off, tdesc_t *tdp)
+{
+ Dwarf_Unsigned sz;
+ intr_t *intr;
+ char *new;
+
+ debug(3, "die %llu: creating base type\n", off);
+
+ /*
+ * The compilers have their own clever (internally inconsistent) ideas
+ * as to what base types should look like. Some times gcc will, for
+ * example, use DW_ATE_signed_char for char. Other times, however, it
+ * will use DW_ATE_signed. Needless to say, this causes some problems
+ * down the road, particularly with merging. We do, however, use the
+ * DWARF idea of type sizes, as this allows us to avoid caring about
+ * the data model.
+ */
+ (void) die_unsigned(dw, base, DW_AT_byte_size, &sz, DW_ATTR_REQ);
+
+ if (tdp->t_name == NULL)
+ terminate("die %llu: base type without name\n", off);
+
+ /* XXX make a name parser for float too */
+ if ((intr = die_base_name_parse(tdp->t_name, &new)) != NULL) {
+ /* Found it. We'll use the parsed version */
+ debug(3, "die %llu: name \"%s\" remapped to \"%s\"\n", off,
+ tdesc_name(tdp), new);
+
+ free(tdp->t_name);
+ tdp->t_name = new;
+ } else {
+ /*
+ * We didn't recognize the type, so we'll create an intr_t
+ * based on the DWARF data.
+ */
+ debug(3, "die %llu: using dwarf data for base \"%s\"\n", off,
+ tdesc_name(tdp));
+
+ intr = die_base_from_dwarf(dw, base, off, sz);
+ }
+
+ intr->intr_nbits = sz * 8;
+
+ tdp->t_type = INTRINSIC;
+ tdp->t_intr = intr;
+ tdp->t_size = sz;
+
+ tdp->t_flags |= TDESC_F_RESOLVED;
+}
+
+static void
+die_through_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp,
+ int type, const char *typename)
+{
+ Dwarf_Attribute attr;
+
+ debug(3, "die %llu <%llx>: creating %s type %d\n", off, off, typename, type);
+
+ tdp->t_type = type;
+
+ if ((attr = die_attr(dw, die, DW_AT_type, 0)) != NULL) {
+ tdp->t_tdesc = die_lookup_pass1(dw, die, DW_AT_type);
+ } else {
+ tdp->t_tdesc = tdesc_intr_void(dw);
+ }
+
+ if (type == POINTER)
+ tdp->t_size = dw->dw_ptrsz;
+
+ tdp->t_flags |= TDESC_F_RESOLVED;
+
+ if (type == TYPEDEF) {
+ iidesc_t *ii = xcalloc(sizeof (iidesc_t));
+ ii->ii_type = II_TYPE;
+ ii->ii_name = xstrdup(tdp->t_name);
+ ii->ii_dtype = tdp;
+
+ iidesc_add(dw->dw_td->td_iihash, ii);
+ }
+}
+
+static void
+die_typedef_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp)
+{
+ die_through_create(dw, die, off, tdp, TYPEDEF, "typedef");
+}
+
+static void
+die_const_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp)
+{
+ die_through_create(dw, die, off, tdp, CONST, "const");
+}
+
+static void
+die_pointer_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp)
+{
+ die_through_create(dw, die, off, tdp, POINTER, "pointer");
+}
+
+static void
+die_restrict_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp)
+{
+ die_through_create(dw, die, off, tdp, RESTRICT, "restrict");
+}
+
+static void
+die_volatile_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp)
+{
+ die_through_create(dw, die, off, tdp, VOLATILE, "volatile");
+}
+
+/*ARGSUSED3*/
+static void
+die_function_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp __unused)
+{
+ Dwarf_Die arg;
+ Dwarf_Half tag;
+ iidesc_t *ii;
+ char *name;
+
+ debug(3, "die %llu <%llx>: creating function definition\n", off, off);
+
+ /*
+ * We'll begin by processing any type definition nodes that may be
+ * lurking underneath this one.
+ */
+ for (arg = die_child(dw, die); arg != NULL;
+ arg = die_sibling(dw, arg)) {
+ if ((tag = die_tag(dw, arg)) != DW_TAG_formal_parameter &&
+ tag != DW_TAG_variable) {
+ /* Nested type declaration */
+ die_create_one(dw, arg);
+ }
+ }
+
+ if (die_isdecl(dw, die) || (name = die_name(dw, die)) == NULL) {
+ /*
+ * We process neither prototypes nor subprograms without
+ * names.
+ */
+ return;
+ }
+
+ ii = xcalloc(sizeof (iidesc_t));
+ ii->ii_type = die_isglobal(dw, die) ? II_GFUN : II_SFUN;
+ ii->ii_name = name;
+ if (ii->ii_type == II_SFUN)
+ ii->ii_owner = xstrdup(dw->dw_cuname);
+
+ debug(3, "die %llu: function %s is %s\n", off, ii->ii_name,
+ (ii->ii_type == II_GFUN ? "global" : "static"));
+
+ if (die_attr(dw, die, DW_AT_type, 0) != NULL)
+ ii->ii_dtype = die_lookup_pass1(dw, die, DW_AT_type);
+ else
+ ii->ii_dtype = tdesc_intr_void(dw);
+
+ for (arg = die_child(dw, die); arg != NULL;
+ arg = die_sibling(dw, arg)) {
+ char *name1;
+
+ debug(3, "die %llu: looking at sub member at %llu\n",
+ off, die_off(dw, die));
+
+ if (die_tag(dw, arg) != DW_TAG_formal_parameter)
+ continue;
+
+ if ((name1 = die_name(dw, arg)) == NULL) {
+ terminate("die %llu: func arg %d has no name\n",
+ off, ii->ii_nargs + 1);
+ }
+
+ if (strcmp(name1, "...") == 0) {
+ free(name1);
+ ii->ii_vargs = 1;
+ continue;
+ }
+ free(name1);
+
+ ii->ii_nargs++;
+ }
+
+ if (ii->ii_nargs > 0) {
+ int i;
+
+ debug(3, "die %llu: function has %d argument%s\n", off,
+ ii->ii_nargs, (ii->ii_nargs == 1 ? "" : "s"));
+
+ ii->ii_args = xcalloc(sizeof (tdesc_t) * ii->ii_nargs);
+
+ for (arg = die_child(dw, die), i = 0;
+ arg != NULL && i < ii->ii_nargs;
+ arg = die_sibling(dw, arg)) {
+ if (die_tag(dw, arg) != DW_TAG_formal_parameter)
+ continue;
+
+ ii->ii_args[i++] = die_lookup_pass1(dw, arg,
+ DW_AT_type);
+ }
+ }
+
+ iidesc_add(dw->dw_td->td_iihash, ii);
+}
+
+/*ARGSUSED3*/
+static void
+die_variable_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp __unused)
+{
+ iidesc_t *ii;
+ char *name;
+
+ debug(3, "die %llu: creating object definition\n", off);
+
+ if (die_isdecl(dw, die) || (name = die_name(dw, die)) == NULL)
+ return; /* skip prototypes and nameless objects */
+
+ ii = xcalloc(sizeof (iidesc_t));
+ ii->ii_type = die_isglobal(dw, die) ? II_GVAR : II_SVAR;
+ ii->ii_name = name;
+ ii->ii_dtype = die_lookup_pass1(dw, die, DW_AT_type);
+ if (ii->ii_type == II_SVAR)
+ ii->ii_owner = xstrdup(dw->dw_cuname);
+
+ iidesc_add(dw->dw_td->td_iihash, ii);
+}
+
+/*ARGSUSED2*/
+static int
+die_fwd_resolve(tdesc_t *fwd, tdesc_t **fwdp, void *private __unused)
+{
+ if (fwd->t_flags & TDESC_F_RESOLVED)
+ return (1);
+
+ if (fwd->t_tdesc != NULL) {
+ debug(3, "tdp %u: unforwarded %s\n", fwd->t_id,
+ tdesc_name(fwd));
+ *fwdp = fwd->t_tdesc;
+ }
+
+ fwd->t_flags |= TDESC_F_RESOLVED;
+
+ return (1);
+}
+
+/*ARGSUSED*/
+static void
+die_lexblk_descend(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off __unused, tdesc_t *tdp __unused)
+{
+ Dwarf_Die child = die_child(dw, die);
+
+ if (child != NULL)
+ die_create(dw, child);
+}
+
+/*
+ * Used to map the die to a routine which can parse it, using the tag to do the
+ * mapping. While the processing of most tags entails the creation of a tdesc,
+ * there are a few which don't - primarily those which result in the creation of
+ * iidescs which refer to existing tdescs.
+ */
+
+#define DW_F_NOTDP 0x1 /* Don't create a tdesc for the creator */
+
+typedef struct die_creator {
+ Dwarf_Half dc_tag;
+ uint16_t dc_flags;
+ void (*dc_create)(dwarf_t *, Dwarf_Die, Dwarf_Off, tdesc_t *);
+} die_creator_t;
+
+static const die_creator_t die_creators[] = {
+ { DW_TAG_array_type, 0, die_array_create },
+ { DW_TAG_enumeration_type, 0, die_enum_create },
+ { DW_TAG_lexical_block, DW_F_NOTDP, die_lexblk_descend },
+ { DW_TAG_pointer_type, 0, die_pointer_create },
+ { DW_TAG_structure_type, 0, die_struct_create },
+ { DW_TAG_subroutine_type, 0, die_funcptr_create },
+ { DW_TAG_typedef, 0, die_typedef_create },
+ { DW_TAG_union_type, 0, die_union_create },
+ { DW_TAG_base_type, 0, die_base_create },
+ { DW_TAG_const_type, 0, die_const_create },
+ { DW_TAG_subprogram, DW_F_NOTDP, die_function_create },
+ { DW_TAG_variable, DW_F_NOTDP, die_variable_create },
+ { DW_TAG_volatile_type, 0, die_volatile_create },
+ { DW_TAG_restrict_type, 0, die_restrict_create },
+ { 0, 0, NULL }
+};
+
+static const die_creator_t *
+die_tag2ctor(Dwarf_Half tag)
+{
+ const die_creator_t *dc;
+
+ for (dc = die_creators; dc->dc_create != NULL; dc++) {
+ if (dc->dc_tag == tag)
+ return (dc);
+ }
+
+ return (NULL);
+}
+
+static void
+die_create_one(dwarf_t *dw, Dwarf_Die die)
+{
+ Dwarf_Off off = die_off(dw, die);
+ const die_creator_t *dc;
+ Dwarf_Half tag;
+ tdesc_t *tdp;
+
+ debug(3, "die %llu <%llx>: create_one\n", off, off);
+
+ if (off > dw->dw_maxoff) {
+ terminate("illegal die offset %llu (max %llu)\n", off,
+ dw->dw_maxoff);
+ }
+
+ tag = die_tag(dw, die);
+
+ if ((dc = die_tag2ctor(tag)) == NULL) {
+ debug(2, "die %llu: ignoring tag type %x\n", off, tag);
+ return;
+ }
+
+ if ((tdp = tdesc_lookup(dw, off)) == NULL &&
+ !(dc->dc_flags & DW_F_NOTDP)) {
+ tdp = xcalloc(sizeof (tdesc_t));
+ tdp->t_id = off;
+ tdesc_add(dw, tdp);
+ }
+
+ if (tdp != NULL)
+ tdp->t_name = die_name(dw, die);
+
+ dc->dc_create(dw, die, off, tdp);
+}
+
+static void
+die_create(dwarf_t *dw, Dwarf_Die die)
+{
+ do {
+ die_create_one(dw, die);
+ } while ((die = die_sibling(dw, die)) != NULL);
+}
+
+static tdtrav_cb_f die_resolvers[] = {
+ NULL,
+ NULL, /* intrinsic */
+ NULL, /* pointer */
+ die_array_resolve, /* array */
+ NULL, /* function */
+ die_sou_resolve, /* struct */
+ die_sou_resolve, /* union */
+ die_enum_resolve, /* enum */
+ die_fwd_resolve, /* forward */
+ NULL, /* typedef */
+ NULL, /* typedef unres */
+ NULL, /* volatile */
+ NULL, /* const */
+ NULL, /* restrict */
+};
+
+static tdtrav_cb_f die_fail_reporters[] = {
+ NULL,
+ NULL, /* intrinsic */
+ NULL, /* pointer */
+ die_array_failed, /* array */
+ NULL, /* function */
+ die_sou_failed, /* struct */
+ die_sou_failed, /* union */
+ NULL, /* enum */
+ NULL, /* forward */
+ NULL, /* typedef */
+ NULL, /* typedef unres */
+ NULL, /* volatile */
+ NULL, /* const */
+ NULL, /* restrict */
+};
+
+static void
+die_resolve(dwarf_t *dw)
+{
+ int last = -1;
+ int pass = 0;
+
+ do {
+ pass++;
+ dw->dw_nunres = 0;
+
+ (void) iitraverse_hash(dw->dw_td->td_iihash,
+ &dw->dw_td->td_curvgen, NULL, NULL, die_resolvers, dw);
+
+ debug(3, "resolve: pass %d, %u left\n", pass, dw->dw_nunres);
+
+ if ((int) dw->dw_nunres == last) {
+ fprintf(stderr, "%s: failed to resolve the following "
+ "types:\n", progname);
+
+ (void) iitraverse_hash(dw->dw_td->td_iihash,
+ &dw->dw_td->td_curvgen, NULL, NULL,
+ die_fail_reporters, dw);
+
+ terminate("failed to resolve types\n");
+ }
+
+ last = dw->dw_nunres;
+
+ } while (dw->dw_nunres != 0);
+}
+
+/*
+ * Any object containing a function or object symbol at any scope should also
+ * contain DWARF data.
+ */
+static boolean_t
+should_have_dwarf(Elf *elf)
+{
+ Elf_Scn *scn = NULL;
+ Elf_Data *data = NULL;
+ GElf_Shdr shdr;
+ GElf_Sym sym;
+ uint32_t symdx = 0;
+ size_t nsyms = 0;
+ boolean_t found = B_FALSE;
+
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ gelf_getshdr(scn, &shdr);
+
+ if (shdr.sh_type == SHT_SYMTAB) {
+ found = B_TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ terminate("cannot convert stripped objects\n");
+
+ data = elf_getdata(scn, NULL);
+ nsyms = shdr.sh_size / shdr.sh_entsize;
+
+ for (symdx = 0; symdx < nsyms; symdx++) {
+ gelf_getsym(data, symdx, &sym);
+
+ if ((GELF_ST_TYPE(sym.st_info) == STT_FUNC) ||
+ (GELF_ST_TYPE(sym.st_info) == STT_TLS) ||
+ (GELF_ST_TYPE(sym.st_info) == STT_OBJECT)) {
+ char *name;
+
+ name = elf_strptr(elf, shdr.sh_link, sym.st_name);
+
+ /* Studio emits these local symbols regardless */
+ if ((strcmp(name, "Bbss.bss") != 0) &&
+ (strcmp(name, "Ttbss.bss") != 0) &&
+ (strcmp(name, "Ddata.data") != 0) &&
+ (strcmp(name, "Ttdata.data") != 0) &&
+ (strcmp(name, "Drodata.rodata") != 0))
+ return (B_TRUE);
+ }
+ }
+
+ return (B_FALSE);
+}
+
+/*ARGSUSED*/
+int
+dw_read(tdata_t *td, Elf *elf, char *filename __unused)
+{
+ Dwarf_Unsigned abboff, hdrlen, lang, nxthdr;
+ Dwarf_Half vers, addrsz, offsz;
+ Dwarf_Die cu = 0;
+ Dwarf_Die child = 0;
+ dwarf_t dw;
+ char *prod = NULL;
+ int rc;
+
+ bzero(&dw, sizeof (dwarf_t));
+ dw.dw_td = td;
+ dw.dw_ptrsz = elf_ptrsz(elf);
+ dw.dw_mfgtid_last = TID_MFGTID_BASE;
+ dw.dw_tidhash = hash_new(TDESC_HASH_BUCKETS, tdesc_idhash, tdesc_idcmp);
+ dw.dw_fwdhash = hash_new(TDESC_HASH_BUCKETS, tdesc_namehash,
+ tdesc_namecmp);
+ dw.dw_enumhash = hash_new(TDESC_HASH_BUCKETS, tdesc_namehash,
+ tdesc_namecmp);
+
+ if ((rc = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dw.dw_dw,
+ &dw.dw_err)) == DW_DLV_NO_ENTRY) {
+ if (should_have_dwarf(elf)) {
+ errno = ENOENT;
+ return (-1);
+ } else {
+ return (0);
+ }
+ } else if (rc != DW_DLV_OK) {
+ if (dwarf_errno(dw.dw_err) == DW_DLE_DEBUG_INFO_NULL) {
+ /*
+ * There's no type data in the DWARF section, but
+ * libdwarf is too clever to handle that properly.
+ */
+ return (0);
+ }
+
+ terminate("failed to initialize DWARF: %s\n",
+ dwarf_errmsg(dw.dw_err));
+ }
+
+ if ((rc = dwarf_next_cu_header_b(dw.dw_dw, &hdrlen, &vers, &abboff,
+ &addrsz, &offsz, NULL, &nxthdr, &dw.dw_err)) != DW_DLV_OK) {
+ if (dw.dw_err.err_error == DW_DLE_NO_ENTRY)
+ exit(0);
+ else
+ terminate("rc = %d %s\n", rc, dwarf_errmsg(dw.dw_err));
+ }
+ if ((cu = die_sibling(&dw, NULL)) == NULL ||
+ (((child = die_child(&dw, cu)) == NULL) &&
+ should_have_dwarf(elf))) {
+ terminate("file does not contain dwarf type data "
+ "(try compiling with -g)\n");
+ } else if (child == NULL) {
+ return (0);
+ }
+
+ dw.dw_maxoff = nxthdr - 1;
+
+ if (dw.dw_maxoff > TID_FILEMAX)
+ terminate("file contains too many types\n");
+
+ debug(1, "DWARF version: %d\n", vers);
+ if (vers < 2 || vers > 4) {
+ terminate("file contains incompatible version %d DWARF code "
+ "(version 2, 3 or 4 required)\n", vers);
+ }
+
+ if (die_string(&dw, cu, DW_AT_producer, &prod, 0)) {
+ debug(1, "DWARF emitter: %s\n", prod);
+ free(prod);
+ }
+
+ if (dwarf_attrval_unsigned(cu, DW_AT_language, &lang, &dw.dw_err) == 0)
+ switch (lang) {
+ case DW_LANG_C:
+ case DW_LANG_C89:
+ case DW_LANG_C99:
+ case DW_LANG_C11:
+ case DW_LANG_C_plus_plus:
+ case DW_LANG_C_plus_plus_03:
+ case DW_LANG_C_plus_plus_11:
+ case DW_LANG_C_plus_plus_14:
+ case DW_LANG_Mips_Assembler:
+ break;
+ default:
+ terminate("file contains DWARF for unsupported "
+ "language %#x", lang);
+ }
+ else
+ warning("die %llu: failed to get language attribute: %s\n",
+ die_off(&dw, cu), dwarf_errmsg(dw.dw_err));
+
+ if ((dw.dw_cuname = die_name(&dw, cu)) != NULL) {
+ char *base = xstrdup(basename(dw.dw_cuname));
+ free(dw.dw_cuname);
+ dw.dw_cuname = base;
+
+ debug(1, "CU name: %s\n", dw.dw_cuname);
+ }
+
+ if ((child = die_child(&dw, cu)) != NULL)
+ die_create(&dw, child);
+
+ if ((rc = dwarf_next_cu_header_b(dw.dw_dw, &hdrlen, &vers, &abboff,
+ &addrsz, &offsz, NULL, &nxthdr, &dw.dw_err)) != DW_DLV_NO_ENTRY)
+ terminate("multiple compilation units not supported\n");
+
+ (void) dwarf_finish(dw.dw_dw, &dw.dw_err);
+
+ die_resolve(&dw);
+
+ cvt_fixups(td, dw.dw_ptrsz);
+
+ /* leak the dwarf_t */
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/fifo.c b/cddl/contrib/opensolaris/tools/ctf/cvt/fifo.c
new file mode 100644
index 000000000000..fb9a11fccf56
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/fifo.c
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ *
+ * 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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for manipulating a FIFO queue
+ */
+
+#include <stdlib.h>
+
+#include "fifo.h"
+#include "memory.h"
+
+typedef struct fifonode {
+ void *fn_data;
+ struct fifonode *fn_next;
+} fifonode_t;
+
+struct fifo {
+ fifonode_t *f_head;
+ fifonode_t *f_tail;
+};
+
+fifo_t *
+fifo_new(void)
+{
+ fifo_t *f;
+
+ f = xcalloc(sizeof (fifo_t));
+
+ return (f);
+}
+
+/* Add to the end of the fifo */
+void
+fifo_add(fifo_t *f, void *data)
+{
+ fifonode_t *fn = xmalloc(sizeof (fifonode_t));
+
+ fn->fn_data = data;
+ fn->fn_next = NULL;
+
+ if (f->f_tail == NULL)
+ f->f_head = f->f_tail = fn;
+ else {
+ f->f_tail->fn_next = fn;
+ f->f_tail = fn;
+ }
+}
+
+/* Remove from the front of the fifo */
+void *
+fifo_remove(fifo_t *f)
+{
+ fifonode_t *fn;
+ void *data;
+
+ if ((fn = f->f_head) == NULL)
+ return (NULL);
+
+ data = fn->fn_data;
+ if ((f->f_head = fn->fn_next) == NULL)
+ f->f_tail = NULL;
+
+ free(fn);
+
+ return (data);
+}
+
+/*ARGSUSED*/
+static void
+fifo_nullfree(void *arg)
+{
+ /* this function intentionally left blank */
+}
+
+/* Free an entire fifo */
+void
+fifo_free(fifo_t *f, void (*freefn)(void *))
+{
+ fifonode_t *fn = f->f_head;
+ fifonode_t *tmp;
+
+ if (freefn == NULL)
+ freefn = fifo_nullfree;
+
+ while (fn) {
+ (*freefn)(fn->fn_data);
+
+ tmp = fn;
+ fn = fn->fn_next;
+ free(tmp);
+ }
+
+ free(f);
+}
+
+int
+fifo_len(fifo_t *f)
+{
+ fifonode_t *fn;
+ int i;
+
+ for (i = 0, fn = f->f_head; fn; fn = fn->fn_next, i++);
+
+ return (i);
+}
+
+int
+fifo_empty(fifo_t *f)
+{
+ return (f->f_head == NULL);
+}
+
+int
+fifo_iter(fifo_t *f, int (*iter)(void *data, void *arg), void *arg)
+{
+ fifonode_t *fn;
+ int rc;
+ int ret = 0;
+
+ for (fn = f->f_head; fn; fn = fn->fn_next) {
+ if ((rc = iter(fn->fn_data, arg)) < 0)
+ return (-1);
+ ret += rc;
+ }
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/fifo.h b/cddl/contrib/opensolaris/tools/ctf/cvt/fifo.h
new file mode 100644
index 000000000000..e4b948abc418
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/fifo.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ *
+ * 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 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FIFO_H
+#define _FIFO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for manipulating a FIFO queue
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct fifo fifo_t;
+
+extern fifo_t *fifo_new(void);
+extern void fifo_add(fifo_t *, void *);
+extern void *fifo_remove(fifo_t *);
+extern void fifo_free(fifo_t *, void (*)(void *));
+extern int fifo_len(fifo_t *);
+extern int fifo_empty(fifo_t *);
+extern int fifo_iter(fifo_t *, int (*)(void *, void *), void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FIFO_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/fixup_tdescs.c b/cddl/contrib/opensolaris/tools/ctf/cvt/fixup_tdescs.c
new file mode 100644
index 000000000000..b239a62dc53b
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/fixup_tdescs.c
@@ -0,0 +1,279 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Workarounds for stabs generation bugs in the compiler and general needed
+ * fixups.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+
+#include "ctf_headers.h"
+#include "ctftools.h"
+#include "hash.h"
+#include "memory.h"
+
+/*
+ * Due to 4432619, the 6.1 compiler will sometimes incorrectly generate pointer
+ * stabs. Given a struct foo, and a corresponding typedef struct foo foo_t.
+ * In some cases, when faced with a pointer to a foo_t, the compiler will
+ * sometimes generate a stab that describes a pointer to a struct foo.
+ * Regardless of correctness, this breaks merges, as it occurs inconsistently
+ * by file. The following two routines know how to recognize and repair foo_t *
+ * and foo_t ** bugs in a specific set of cases. There is no general way to
+ * solve this problem without a fix to the compiler. In general, cases should
+ * only be added to these routines to fix merging problems in genunix.
+ */
+static void
+fix_ptrptr_to_struct(tdata_t *td)
+{
+ const char *strs[2] = { "as", "fdbuffer" };
+ const char *mems[2] = { "a_objectdir", "fd_shadow" };
+ const char *acts[2] = { "vnode", "page" };
+ const char *tgts[2] = { "vnode_t", "page_t" };
+ tdesc_t *str;
+ tdesc_t *act, *tgt;
+ tdesc_t *p1, *p2;
+ mlist_t *ml;
+ int i;
+
+ for (i = 0; i < (int) (sizeof (strs) / sizeof (strs[0])); i++) {
+ if (!(str = lookupname(strs[i])) || str->t_type != STRUCT)
+ continue;
+
+ for (ml = str->t_members; ml; ml = ml->ml_next) {
+ if (streq(ml->ml_name, mems[i]))
+ break;
+ }
+ if (!ml)
+ continue;
+
+ if (ml->ml_type->t_type != POINTER || ml->ml_type->t_name ||
+ ml->ml_type->t_tdesc->t_type != POINTER ||
+ ml->ml_type->t_tdesc->t_name)
+ continue;
+
+ act = ml->ml_type->t_tdesc->t_tdesc;
+ if (act->t_type != STRUCT || !streq(act->t_name, acts[i]))
+ continue;
+
+ if (!(tgt = lookupname(tgts[i])) || tgt->t_type != TYPEDEF)
+ continue;
+
+ /* We have an instance of the bug */
+ p2 = xcalloc(sizeof (*p2));
+ p2->t_type = POINTER;
+ p2->t_id = td->td_nextid++;
+ p2->t_tdesc = tgt;
+
+ p1 = xcalloc(sizeof (*p1));
+ p1->t_type = POINTER;
+ p1->t_id = td->td_nextid++;
+ p1->t_tdesc = p2;
+
+ ml->ml_type = p1;
+
+ debug(3, "Fixed %s->%s => ptrptr struct %s bug\n",
+ strs[i], mems[i], acts[i]);
+ }
+}
+
+static void
+fix_ptr_to_struct(tdata_t *td)
+{
+ const char *strs[2] = { "vmem", "id_space" };
+ const char *mems[2] = { NULL, "is_vmem" };
+ tdesc_t *ptr = NULL;
+ tdesc_t *str, *vmt;
+ mlist_t *ml;
+ int i;
+
+ if ((vmt = lookupname("vmem_t")) == NULL || vmt->t_type != TYPEDEF)
+ return;
+
+ for (i = 0; i < (int) (sizeof (strs) / sizeof (strs[0])); i++) {
+ if (!(str = lookupname(strs[i])) || str->t_type != STRUCT)
+ continue;
+
+ for (ml = str->t_members; ml; ml = ml->ml_next) {
+ if (mems[i] && !streq(ml->ml_name, mems[i]))
+ continue;
+
+ if (ml->ml_type->t_type != POINTER ||
+ ml->ml_type->t_name ||
+ (ml->ml_type->t_tdesc->t_type != STRUCT &&
+ ml->ml_type->t_tdesc->t_type != FORWARD) ||
+ !streq(ml->ml_type->t_tdesc->t_name, "vmem"))
+ continue;
+
+ debug(3, "Fixed %s->%s => ptr struct vmem bug\n",
+ strs[i], ml->ml_name);
+
+ if (!ptr) {
+ ptr = xcalloc(sizeof (*ptr));
+ ptr->t_type = POINTER;
+ ptr->t_id = td->td_nextid++;
+ ptr->t_tdesc = vmt;
+ }
+
+ ml->ml_type = ptr;
+ }
+ }
+}
+
+/*
+ * Fix stabs generation bugs. These routines must be run before the
+ * post-conversion merge
+ */
+void
+cvt_fixstabs(tdata_t *td)
+{
+ fix_ptrptr_to_struct(td);
+ fix_ptr_to_struct(td);
+}
+
+struct match {
+ tdesc_t *m_ret;
+ const char *m_name;
+};
+
+static int
+matching_iidesc(void *arg1, void *arg2)
+{
+ iidesc_t *iidesc = arg1;
+ struct match *match = arg2;
+ if (!streq(iidesc->ii_name, match->m_name))
+ return (0);
+
+ if (iidesc->ii_type != II_TYPE && iidesc->ii_type != II_SOU)
+ return (0);
+
+ match->m_ret = iidesc->ii_dtype;
+ return (-1);
+}
+
+static tdesc_t *
+lookup_tdesc(tdata_t *td, char const *name)
+{
+ struct match match = { NULL, name };
+ iter_iidescs_by_name(td, name, matching_iidesc, &match);
+ return (match.m_ret);
+}
+
+/*
+ * The cpu structure grows, with the addition of a machcpu member, if
+ * _MACHDEP is defined. This means that, for example, the cpu structure
+ * in unix is different from the cpu structure in genunix. As one might
+ * expect, this causes merges to fail. Since everyone indirectly contains
+ * a pointer to a CPU structure, the failed merges can cause massive amounts
+ * of duplication. In the case of unix uniquifying against genunix, upwards
+ * of 50% of the structures were unmerged due to this problem. We fix this
+ * by adding a cpu_m member. If machcpu hasn't been defined in our module,
+ * we make a forward node for it.
+ */
+static void
+fix_small_cpu_struct(tdata_t *td, size_t ptrsize)
+{
+ tdesc_t *cput, *cpu;
+ tdesc_t *machcpu;
+ mlist_t *ml, *lml;
+ mlist_t *cpum;
+ int foundcpucyc = 0;
+
+ /*
+ * We're going to take the circuitous route finding the cpu structure,
+ * because we want to make sure that we find the right one. It would
+ * be nice if we could verify the header name too. DWARF might not
+ * have the cpu_t, so we let this pass.
+ */
+ if ((cput = lookup_tdesc(td, "cpu_t")) != NULL) {
+ if (cput->t_type != TYPEDEF)
+ return;
+ cpu = cput->t_tdesc;
+ } else {
+ cpu = lookup_tdesc(td, "cpu");
+ }
+
+ if (cpu == NULL)
+ return;
+
+ if (!streq(cpu->t_name, "cpu") || cpu->t_type != STRUCT)
+ return;
+
+ for (ml = cpu->t_members, lml = NULL; ml;
+ lml = ml, ml = ml->ml_next) {
+ if (strcmp(ml->ml_name, "cpu_cyclic") == 0)
+ foundcpucyc = 1;
+ }
+
+ if (foundcpucyc == 0 || lml == NULL ||
+ strcmp(lml->ml_name, "cpu_m") == 0)
+ return;
+
+ /*
+ * We need to derive the right offset for the fake cpu_m member. To do
+ * that, we require a special unused member to be the last member
+ * before the 'cpu_m', that we encode knowledge of here. ABI alignment
+ * on all platforms is such that we only need to add a pointer-size
+ * number of bits to get the right offset for cpu_m. This would most
+ * likely break if gcc's -malign-double were ever used, but that option
+ * breaks the ABI anyway.
+ */
+ if (!streq(lml->ml_name, "cpu_m_pad") &&
+ getenv("CTFCONVERT_PERMISSIVE") == NULL) {
+ terminate("last cpu_t member before cpu_m is %s; "
+ "it must be cpu_m_pad.\n", lml->ml_name);
+ }
+
+ if ((machcpu = lookup_tdesc(td, "machcpu")) == NULL) {
+ machcpu = xcalloc(sizeof (*machcpu));
+ machcpu->t_name = xstrdup("machcpu");
+ machcpu->t_id = td->td_nextid++;
+ machcpu->t_type = FORWARD;
+ } else if (machcpu->t_type != STRUCT) {
+ return;
+ }
+
+ debug(3, "Adding cpu_m machcpu %s to cpu struct\n",
+ (machcpu->t_type == FORWARD ? "forward" : "struct"));
+
+ cpum = xmalloc(sizeof (*cpum));
+ cpum->ml_offset = lml->ml_offset + (ptrsize * NBBY);
+ cpum->ml_size = 0;
+ cpum->ml_name = xstrdup("cpu_m");
+ cpum->ml_type = machcpu;
+ cpum->ml_next = NULL;
+
+ lml->ml_next = cpum;
+}
+
+void
+cvt_fixups(tdata_t *td, size_t ptrsize)
+{
+ fix_small_cpu_struct(td, ptrsize);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/hash.c b/cddl/contrib/opensolaris/tools/ctf/cvt/hash.c
new file mode 100644
index 000000000000..36ed45a30f0a
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/hash.c
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for manipulating hash tables
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+
+#include "hash.h"
+#include "memory.h"
+#include "list.h"
+
+struct hash {
+ int h_nbuckets;
+ list_t **h_buckets;
+
+ int (*h_hashfn)(int, void *);
+ int (*h_cmp)(void *, void *);
+};
+
+struct hash_data {
+ hash_t *hd_hash;
+ int (*hd_fun)(void *, void *);
+ void *hd_key;
+ void *hd_private;
+
+ void *hd_ret;
+};
+
+static int
+hash_def_hash(int nbuckets, void *arg)
+{
+ uintptr_t data = (uintptr_t) arg;
+ return (data % nbuckets);
+}
+
+static int
+hash_def_cmp(void *d1, void *d2)
+{
+ return (d1 != d2);
+}
+
+
+int
+hash_name(int nbuckets, const char *name)
+{
+ const char *c;
+ ulong_t g;
+ int h = 0;
+
+ for (c = name; *c; c++) {
+ h = (h << 4) + *c;
+ if ((g = (h & 0xf0000000)) != 0) {
+ h ^= (g >> 24);
+ h ^= g;
+ }
+ }
+
+ return (h % nbuckets);
+}
+
+hash_t *
+hash_new(int nbuckets, int (*hashfn)(int, void *), int (*cmp)(void *, void *))
+{
+ hash_t *hash;
+
+ hash = xmalloc(sizeof (hash_t));
+ hash->h_buckets = xcalloc(sizeof (list_t *) * nbuckets);
+ hash->h_nbuckets = nbuckets;
+ hash->h_hashfn = hashfn ? hashfn : hash_def_hash;
+ hash->h_cmp = cmp ? cmp : hash_def_cmp;
+
+ return (hash);
+}
+
+void
+hash_add(hash_t *hash, void *key)
+{
+ int bucket = hash->h_hashfn(hash->h_nbuckets, key);
+
+ list_add(&hash->h_buckets[bucket], key);
+}
+
+static int
+hash_add_cb(void *node, void *private)
+{
+ hash_add((hash_t *)private, node);
+ return (0);
+}
+
+void
+hash_merge(hash_t *to, hash_t *from)
+{
+ (void) hash_iter(from, hash_add_cb, to);
+}
+
+static int
+hash_remove_cb(void *key1, void *key2, void *arg)
+{
+ hash_t *hash = arg;
+ return (hash->h_cmp(key1, key2));
+}
+
+void
+hash_remove(hash_t *hash, void *key)
+{
+ int bucket = hash->h_hashfn(hash->h_nbuckets, key);
+
+ (void) list_remove(&hash->h_buckets[bucket], key,
+ hash_remove_cb, hash);
+}
+
+int
+hash_match(hash_t *hash, void *key, int (*fun)(void *, void *),
+ void *private)
+{
+ int bucket = hash->h_hashfn(hash->h_nbuckets, key);
+
+ return (list_iter(hash->h_buckets[bucket], fun, private) < 0);
+}
+
+static int
+hash_find_list_cb(void *node, void *arg)
+{
+ struct hash_data *hd = arg;
+ int cbrc;
+ int rc = 0;
+
+ if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) {
+ if ((cbrc = hd->hd_fun(node, hd->hd_private)) < 0)
+ return (cbrc);
+ rc += cbrc;
+ }
+
+ return (rc);
+}
+
+int
+hash_find_iter(hash_t *hash, void *key, int (*fun)(void *, void *),
+ void *private)
+{
+ int bucket = hash->h_hashfn(hash->h_nbuckets, key);
+ struct hash_data hd;
+
+ hd.hd_hash = hash;
+ hd.hd_fun = fun;
+ hd.hd_key = key;
+ hd.hd_private = private;
+
+ return (list_iter(hash->h_buckets[bucket], hash_find_list_cb,
+ &hd));
+}
+
+/* stop on first match */
+static int
+hash_find_first_cb(void *node, void *arg)
+{
+ struct hash_data *hd = arg;
+ if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) {
+ hd->hd_ret = node;
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+hash_find(hash_t *hash, void *key, void **value)
+{
+ int ret;
+ struct hash_data hd;
+
+ hd.hd_hash = hash;
+ hd.hd_fun = hash_find_first_cb;
+ hd.hd_key = key;
+
+ ret = hash_match(hash, key, hash_find_first_cb, &hd);
+ if (ret && value)
+ *value = hd.hd_ret;
+
+ return (ret);
+}
+
+int
+hash_iter(hash_t *hash, int (*fun)(void *, void *), void *private)
+{
+ int cumrc = 0;
+ int cbrc;
+ int i;
+
+ for (i = 0; i < hash->h_nbuckets; i++) {
+ if (hash->h_buckets[i] != NULL) {
+ if ((cbrc = list_iter(hash->h_buckets[i], fun,
+ private)) < 0)
+ return (cbrc);
+ cumrc += cbrc;
+ }
+ }
+
+ return (cumrc);
+}
+
+int
+hash_count(hash_t *hash)
+{
+ int num, i;
+
+ for (num = 0, i = 0; i < hash->h_nbuckets; i++)
+ num += list_count(hash->h_buckets[i]);
+
+ return (num);
+}
+
+void
+hash_free(hash_t *hash, void (*datafree)(void *, void *), void *private)
+{
+ int i;
+
+ if (hash == NULL)
+ return;
+
+ for (i = 0; i < hash->h_nbuckets; i++)
+ list_free(hash->h_buckets[i], datafree, private);
+ free(hash->h_buckets);
+ free(hash);
+}
+
+void
+hash_stats(hash_t *hash, int verbose)
+{
+ int min = list_count(hash->h_buckets[0]);
+ int minidx = 0;
+ int max = min;
+ int maxidx = 0;
+ int tot = min;
+ int count;
+ int i;
+
+ if (min && verbose)
+ printf("%3d: %d\n", 0, min);
+ for (i = 1; i < hash->h_nbuckets; i++) {
+ count = list_count(hash->h_buckets[i]);
+ if (min > count) {
+ min = count;
+ minidx = i;
+ }
+ if (max < count) {
+ max = count;
+ maxidx = i;
+ }
+ if (count && verbose)
+ printf("%3d: %d\n", i, count);
+ tot += count;
+ }
+
+ printf("Hash statistics:\n");
+ printf(" Buckets: %d\n", hash->h_nbuckets);
+ printf(" Items : %d\n", tot);
+ printf(" Min/Max: %d in #%d, %d in #%d\n", min, minidx, max, maxidx);
+ printf(" Average: %5.2f\n", (float)tot / (float)hash->h_nbuckets);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/hash.h b/cddl/contrib/opensolaris/tools/ctf/cvt/hash.h
new file mode 100644
index 000000000000..94d93d4e5e8a
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/hash.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _HASH_H
+#define _HASH_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for manipulating hash tables
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct hash hash_t;
+
+hash_t *hash_new(int, int (*)(int, void *), int (*)(void *, void *));
+void hash_add(hash_t *, void *);
+void hash_merge(hash_t *, hash_t *);
+void hash_remove(hash_t *, void *);
+int hash_find(hash_t *, void *, void **);
+int hash_find_iter(hash_t *, void *, int (*)(void *, void *), void *);
+int hash_iter(hash_t *, int (*)(void *, void *), void *);
+int hash_match(hash_t *, void *, int (*)(void *, void *), void *);
+int hash_count(hash_t *);
+int hash_name(int, const char *);
+void hash_stats(hash_t *, int);
+void hash_free(hash_t *, void (*)(void *, void *), void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HASH_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/iidesc.c b/cddl/contrib/opensolaris/tools/ctf/cvt/iidesc.c
new file mode 100644
index 000000000000..fc1cefc9321b
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/iidesc.c
@@ -0,0 +1,197 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for manipulating iidesc_t structures
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "ctftools.h"
+#include "memory.h"
+#include "list.h"
+#include "hash.h"
+
+typedef struct iidesc_find {
+ iidesc_t *iif_tgt;
+ iidesc_t *iif_ret;
+} iidesc_find_t;
+
+iidesc_t *
+iidesc_new(char *name)
+{
+ iidesc_t *ii;
+
+ ii = xcalloc(sizeof (iidesc_t));
+ if (name)
+ ii->ii_name = xstrdup(name);
+
+ return (ii);
+}
+
+int
+iidesc_hash(int nbuckets, void *arg)
+{
+ iidesc_t *ii = arg;
+ int h = 0;
+
+ if (ii->ii_name)
+ return (hash_name(nbuckets, ii->ii_name));
+
+ return (h);
+}
+
+static int
+iidesc_cmp(void *arg1, void *arg2)
+{
+ iidesc_t *src = arg1;
+ iidesc_find_t *find = arg2;
+ iidesc_t *tgt = find->iif_tgt;
+
+ if (src->ii_type != tgt->ii_type ||
+ !streq(src->ii_name, tgt->ii_name))
+ return (0);
+
+ find->iif_ret = src;
+
+ return (-1);
+}
+
+void
+iidesc_add(hash_t *hash, iidesc_t *new)
+{
+ iidesc_find_t find;
+
+ find.iif_tgt = new;
+ find.iif_ret = NULL;
+
+ (void) hash_match(hash, new, iidesc_cmp, &find);
+
+ if (find.iif_ret != NULL) {
+ iidesc_t *old = find.iif_ret;
+ iidesc_t tmp;
+ /* replacing existing one */
+ bcopy(old, &tmp, sizeof (tmp));
+ bcopy(new, old, sizeof (*old));
+ bcopy(&tmp, new, sizeof (*new));
+
+ iidesc_free(new, NULL);
+ return;
+ }
+
+ hash_add(hash, new);
+}
+
+void
+iter_iidescs_by_name(tdata_t *td, char const *name,
+ int (*func)(void *, void *), void *data)
+{
+ iidesc_t tmpdesc;
+ bzero(&tmpdesc, sizeof(tmpdesc));
+ tmpdesc.ii_name = xstrdup(name);
+ (void) hash_match(td->td_iihash, &tmpdesc, func, data);
+ free(tmpdesc.ii_name);
+}
+
+iidesc_t *
+iidesc_dup(iidesc_t *src)
+{
+ iidesc_t *tgt;
+
+ tgt = xmalloc(sizeof (iidesc_t));
+ bcopy(src, tgt, sizeof (iidesc_t));
+
+ tgt->ii_name = src->ii_name ? xstrdup(src->ii_name) : NULL;
+ tgt->ii_owner = src->ii_owner ? xstrdup(src->ii_owner) : NULL;
+
+ if (tgt->ii_nargs) {
+ tgt->ii_args = xmalloc(sizeof (tdesc_t *) * tgt->ii_nargs);
+ bcopy(src->ii_args, tgt->ii_args,
+ sizeof (tdesc_t *) * tgt->ii_nargs);
+ }
+
+ return (tgt);
+}
+
+iidesc_t *
+iidesc_dup_rename(iidesc_t *src, char const *name, char const *owner)
+{
+ iidesc_t *tgt = iidesc_dup(src);
+ free(tgt->ii_name);
+ free(tgt->ii_owner);
+
+ tgt->ii_name = name ? xstrdup(name) : NULL;
+ tgt->ii_owner = owner ? xstrdup(owner) : NULL;
+
+ return (tgt);
+}
+
+/*ARGSUSED*/
+void
+iidesc_free(void *arg, void *private __unused)
+{
+ iidesc_t *idp = arg;
+ if (idp->ii_name)
+ free(idp->ii_name);
+ if (idp->ii_nargs)
+ free(idp->ii_args);
+ if (idp->ii_owner)
+ free(idp->ii_owner);
+ free(idp);
+}
+
+int
+iidesc_dump(iidesc_t *ii)
+{
+ printf("type: %d name %s\n", ii->ii_type,
+ (ii->ii_name ? ii->ii_name : "(anon)"));
+
+ return (0);
+}
+
+int
+iidesc_count_type(void *data, void *private)
+{
+ iidesc_t *ii = data;
+ iitype_t match = (iitype_t)private;
+
+ return (ii->ii_type == match);
+}
+
+void
+iidesc_stats(hash_t *ii)
+{
+ printf("GFun: %5d SFun: %5d GVar: %5d SVar: %5d T %5d SOU: %5d\n",
+ hash_iter(ii, iidesc_count_type, (void *)II_GFUN),
+ hash_iter(ii, iidesc_count_type, (void *)II_SFUN),
+ hash_iter(ii, iidesc_count_type, (void *)II_GVAR),
+ hash_iter(ii, iidesc_count_type, (void *)II_SVAR),
+ hash_iter(ii, iidesc_count_type, (void *)II_TYPE),
+ hash_iter(ii, iidesc_count_type, (void *)II_SOU));
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/input.c b/cddl/contrib/opensolaris/tools/ctf/cvt/input.c
new file mode 100644
index 000000000000..240094212f5b
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/input.c
@@ -0,0 +1,422 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for retrieving CTF data from a .SUNW_ctf ELF section
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <gelf.h>
+#include <strings.h>
+#include <sys/types.h>
+
+#include "ctftools.h"
+#include "memory.h"
+#include "symbol.h"
+
+typedef int read_cb_f(tdata_t *, char *, void *);
+
+/*
+ * Return the source types that the object was generated from.
+ */
+source_types_t
+built_source_types(Elf *elf, char const *file)
+{
+ source_types_t types = SOURCE_NONE;
+ symit_data_t *si;
+
+ if ((si = symit_new(elf, file)) == NULL)
+ return (SOURCE_NONE);
+
+ while (symit_next(si, STT_FILE) != NULL) {
+ char *name = symit_name(si);
+ size_t len = strlen(name);
+ if (len < 2 || name[len - 2] != '.') {
+ types |= SOURCE_UNKNOWN;
+ continue;
+ }
+
+ switch (name[len - 1]) {
+ case 'c':
+ types |= SOURCE_C;
+ break;
+ case 'h':
+ /* ignore */
+ break;
+ case 's':
+ case 'S':
+ types |= SOURCE_S;
+ break;
+ default:
+ types |= SOURCE_UNKNOWN;
+ }
+ }
+
+ symit_free(si);
+ return (types);
+}
+
+static int
+read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg,
+ int require_ctf)
+{
+ Elf_Scn *ctfscn;
+ Elf_Data *ctfdata = NULL;
+ symit_data_t *si = NULL;
+ int ctfscnidx;
+ tdata_t *td;
+
+ if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) {
+ if (require_ctf &&
+ (built_source_types(elf, file) & SOURCE_C)) {
+ terminate("Input file %s was partially built from "
+ "C sources, but no CTF data was present\n", file);
+ }
+ return (0);
+ }
+
+ if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL ||
+ (ctfdata = elf_getdata(ctfscn, NULL)) == NULL)
+ elfterminate(file, "Cannot read CTF section");
+
+ /* Reconstruction of type tree */
+ if ((si = symit_new(elf, file)) == NULL) {
+ warning("%s has no symbol table - skipping", file);
+ return (0);
+ }
+
+ td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label);
+ tdata_build_hashes(td);
+
+ symit_free(si);
+
+ if (td != NULL) {
+ if (func(td, file, arg) < 0)
+ return (-1);
+ else
+ return (1);
+ }
+ return (0);
+}
+
+static int
+read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func,
+ void *arg, int require_ctf)
+{
+ Elf *melf;
+ Elf_Cmd cmd = ELF_C_READ;
+ Elf_Arhdr *arh;
+ int secnum = 1, found = 0;
+
+ while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
+ int rc = 0;
+
+ if ((arh = elf_getarhdr(melf)) == NULL) {
+ elfterminate(file, "Can't get archive header for "
+ "member %d", secnum);
+ }
+
+ /* skip special sections - their names begin with "/" */
+ if (*arh->ar_name != '/') {
+ size_t memlen = strlen(file) + 1 +
+ strlen(arh->ar_name) + 1 + 1;
+ char *memname = xmalloc(memlen);
+
+ snprintf(memname, memlen, "%s(%s)", file, arh->ar_name);
+
+ switch (elf_kind(melf)) {
+ case ELF_K_AR:
+ rc = read_archive(fd, melf, memname, label,
+ func, arg, require_ctf);
+ break;
+ case ELF_K_ELF:
+ rc = read_file(melf, memname, label,
+ func, arg, require_ctf);
+ break;
+ default:
+ terminate("%s: Unknown elf kind %d\n",
+ memname, elf_kind(melf));
+ }
+
+ free(memname);
+ }
+
+ cmd = elf_next(melf);
+ (void) elf_end(melf);
+ secnum++;
+
+ if (rc < 0)
+ return (rc);
+ else
+ found += rc;
+ }
+
+ return (found);
+}
+
+static int
+read_ctf_common(char *file, char *label, read_cb_f *func, void *arg,
+ int require_ctf)
+{
+ Elf *elf;
+ int found = 0;
+ int fd;
+
+ debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE"));
+
+ (void) elf_version(EV_CURRENT);
+
+ if ((fd = open(file, O_RDONLY)) < 0)
+ terminate("%s: Cannot open for reading", file);
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
+ elfterminate(file, "Cannot read");
+
+ switch (elf_kind(elf)) {
+ case ELF_K_AR:
+ found = read_archive(fd, elf, file, label,
+ func, arg, require_ctf);
+ break;
+
+ case ELF_K_ELF:
+ found = read_file(elf, file, label,
+ func, arg, require_ctf);
+ break;
+
+ default:
+ terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf));
+ }
+
+ (void) elf_end(elf);
+ (void) close(fd);
+
+ return (found);
+}
+
+/*ARGSUSED*/
+int
+read_ctf_save_cb(tdata_t *td, char *name __unused, void *retp)
+{
+ tdata_t **tdp = retp;
+
+ *tdp = td;
+
+ return (1);
+}
+
+int
+read_ctf(char **files, int n, char *label, read_cb_f *func, void *private,
+ int require_ctf)
+{
+ int found;
+ int i, rc;
+
+ for (i = 0, found = 0; i < n; i++) {
+ if ((rc = read_ctf_common(files[i], label, func,
+ private, require_ctf)) < 0)
+ return (rc);
+ found += rc;
+ }
+
+ return (found);
+}
+
+static int
+count_archive(int fd, Elf *elf, char *file)
+{
+ Elf *melf;
+ Elf_Cmd cmd = ELF_C_READ;
+ Elf_Arhdr *arh;
+ int nfiles = 0, err = 0;
+
+ while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
+ if ((arh = elf_getarhdr(melf)) == NULL) {
+ warning("Can't process input archive %s\n",
+ file);
+ err++;
+ }
+
+ if (*arh->ar_name != '/')
+ nfiles++;
+
+ cmd = elf_next(melf);
+ (void) elf_end(melf);
+ }
+
+ if (err > 0)
+ return (-1);
+
+ return (nfiles);
+}
+
+int
+count_files(char **files, int n)
+{
+ int nfiles = 0, err = 0;
+ Elf *elf;
+ int fd, rc, i;
+
+ (void) elf_version(EV_CURRENT);
+
+ for (i = 0; i < n; i++) {
+ char *file = files[i];
+
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ warning("Can't read input file %s", file);
+ err++;
+ continue;
+ }
+
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
+ warning("Can't open input file %s: %s\n", file,
+ elf_errmsg(-1));
+ err++;
+ (void) close(fd);
+ continue;
+ }
+
+ switch (elf_kind(elf)) {
+ case ELF_K_AR:
+ if ((rc = count_archive(fd, elf, file)) < 0)
+ err++;
+ else
+ nfiles += rc;
+ break;
+ case ELF_K_ELF:
+ nfiles++;
+ break;
+ default:
+ warning("Input file %s is corrupt\n", file);
+ err++;
+ }
+
+ (void) elf_end(elf);
+ (void) close(fd);
+ }
+
+ if (err > 0)
+ return (-1);
+
+ debug(2, "Found %d files in %d input files\n", nfiles, n);
+
+ return (nfiles);
+}
+
+struct symit_data {
+ GElf_Shdr si_shdr;
+ Elf_Data *si_symd;
+ Elf_Data *si_strd;
+ GElf_Sym si_cursym;
+ char *si_curname;
+ char *si_curfile;
+ int si_nument;
+ int si_next;
+};
+
+symit_data_t *
+symit_new(Elf *elf, const char *file)
+{
+ symit_data_t *si;
+ Elf_Scn *scn;
+ int symtabidx;
+
+ if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0)
+ return (NULL);
+
+ si = xcalloc(sizeof (symit_data_t));
+
+ if ((scn = elf_getscn(elf, symtabidx)) == NULL ||
+ gelf_getshdr(scn, &si->si_shdr) == NULL ||
+ (si->si_symd = elf_getdata(scn, NULL)) == NULL)
+ elfterminate(file, "Cannot read .symtab");
+
+ if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL ||
+ (si->si_strd = elf_getdata(scn, NULL)) == NULL)
+ elfterminate(file, "Cannot read strings for .symtab");
+
+ si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize;
+
+ return (si);
+}
+
+void
+symit_free(symit_data_t *si)
+{
+ free(si);
+}
+
+void
+symit_reset(symit_data_t *si)
+{
+ si->si_next = 0;
+}
+
+char *
+symit_curfile(symit_data_t *si)
+{
+ return (si->si_curfile);
+}
+
+GElf_Sym *
+symit_next(symit_data_t *si, int type)
+{
+ GElf_Sym sym;
+ char *bname;
+ int check_sym = (type == STT_OBJECT || type == STT_FUNC);
+
+ for (; si->si_next < si->si_nument; si->si_next++) {
+ gelf_getsym(si->si_symd, si->si_next, &si->si_cursym);
+ gelf_getsym(si->si_symd, si->si_next, &sym);
+ si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name;
+
+ if (GELF_ST_TYPE(sym.st_info) == STT_FILE) {
+ bname = strrchr(si->si_curname, '/');
+ si->si_curfile = bname == NULL ? si->si_curname : bname + 1;
+ }
+
+ if (GELF_ST_TYPE(sym.st_info) != type ||
+ sym.st_shndx == SHN_UNDEF)
+ continue;
+
+ if (check_sym && ignore_symbol(&sym, si->si_curname))
+ continue;
+
+ si->si_next++;
+
+ return (&si->si_cursym);
+ }
+
+ return (NULL);
+}
+
+char *
+symit_name(symit_data_t *si)
+{
+ return (si->si_curname);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/merge.c b/cddl/contrib/opensolaris/tools/ctf/cvt/merge.c
new file mode 100644
index 000000000000..3dc2ad0cbdad
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/merge.c
@@ -0,0 +1,1134 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains routines that merge one tdata_t tree, called the child,
+ * into another, called the parent. Note that these names are used mainly for
+ * convenience and to represent the direction of the merge. They are not meant
+ * to imply any relationship between the tdata_t graphs prior to the merge.
+ *
+ * tdata_t structures contain two main elements - a hash of iidesc_t nodes, and
+ * a directed graph of tdesc_t nodes, pointed to by the iidesc_t nodes. Simply
+ * put, we merge the tdesc_t graphs, followed by the iidesc_t nodes, and then we
+ * clean up loose ends.
+ *
+ * The algorithm is as follows:
+ *
+ * 1. Mapping iidesc_t nodes
+ *
+ * For each child iidesc_t node, we first try to map its tdesc_t subgraph
+ * against the tdesc_t graph in the parent. For each node in the child subgraph
+ * that exists in the parent, a mapping between the two (between their type IDs)
+ * is established. For the child nodes that cannot be mapped onto existing
+ * parent nodes, a mapping is established between the child node ID and a
+ * newly-allocated ID that the node will use when it is re-created in the
+ * parent. These unmappable nodes are added to the md_tdtba (tdesc_t To Be
+ * Added) hash, which tracks nodes that need to be created in the parent.
+ *
+ * If all of the nodes in the subgraph for an iidesc_t in the child can be
+ * mapped to existing nodes in the parent, then we can try to map the child
+ * iidesc_t onto an iidesc_t in the parent. If we cannot find an equivalent
+ * iidesc_t, or if we were not able to completely map the tdesc_t subgraph(s),
+ * then we add this iidesc_t to the md_iitba (iidesc_t To Be Added) list. This
+ * list tracks iidesc_t nodes that are to be created in the parent.
+ *
+ * While visiting the tdesc_t nodes, we may discover a forward declaration (a
+ * FORWARD tdesc_t) in the parent that is resolved in the child. That is, there
+ * may be a structure or union definition in the child with the same name as the
+ * forward declaration in the parent. If we find such a node, we record an
+ * association in the md_fdida (Forward => Definition ID Association) list
+ * between the parent ID of the forward declaration and the ID that the
+ * definition will use when re-created in the parent.
+ *
+ * 2. Creating new tdesc_t nodes (the md_tdtba hash)
+ *
+ * We have now attempted to map all tdesc_t nodes from the child into the
+ * parent, and have, in md_tdtba, a hash of all tdesc_t nodes that need to be
+ * created (or, as we so wittily call it, conjured) in the parent. We iterate
+ * through this hash, creating the indicated tdesc_t nodes. For a given tdesc_t
+ * node, conjuring requires two steps - the copying of the common tdesc_t data
+ * (name, type, etc) from the child node, and the creation of links from the
+ * newly-created node to the parent equivalents of other tdesc_t nodes pointed
+ * to by node being conjured. Note that in some cases, the targets of these
+ * links will be on the md_tdtba hash themselves, and may not have been created
+ * yet. As such, we can't establish the links from these new nodes into the
+ * parent graph. We therefore conjure them with links to nodes in the *child*
+ * graph, and add pointers to the links to be created to the md_tdtbr (tdesc_t
+ * To Be Remapped) hash. For example, a POINTER tdesc_t that could not be
+ * resolved would have its &tdesc_t->t_tdesc added to md_tdtbr.
+ *
+ * 3. Creating new iidesc_t nodes (the md_iitba list)
+ *
+ * When we have completed step 2, all tdesc_t nodes have been created (or
+ * already existed) in the parent. Some of them may have incorrect links (the
+ * members of the md_tdtbr list), but they've all been created. As such, we can
+ * create all of the iidesc_t nodes, as we can attach the tdesc_t subgraph
+ * pointers correctly. We create each node, and attach the pointers to the
+ * appropriate parts of the parent tdesc_t graph.
+ *
+ * 4. Resolving newly-created tdesc_t node links (the md_tdtbr list)
+ *
+ * As in step 3, we rely on the fact that all of the tdesc_t nodes have been
+ * created. Each entry in the md_tdtbr list is a pointer to where a link into
+ * the parent will be established. As saved in the md_tdtbr list, these
+ * pointers point into the child tdesc_t subgraph. We can thus get the target
+ * type ID from the child, look at the ID mapping to determine the desired link
+ * target, and redirect the link accordingly.
+ *
+ * 5. Parent => child forward declaration resolution
+ *
+ * If entries were made in the md_fdida list in step 1, we have forward
+ * declarations in the parent that need to be resolved to their definitions
+ * re-created in step 2 from the child. Using the md_fdida list, we can locate
+ * the definition for the forward declaration, and we can redirect all inbound
+ * edges to the forward declaration node to the actual definition.
+ *
+ * A pox on the house of anyone who changes the algorithm without updating
+ * this comment.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+#include <pthread.h>
+
+#include "ctf_headers.h"
+#include "ctftools.h"
+#include "list.h"
+#include "alist.h"
+#include "memory.h"
+#include "traverse.h"
+
+typedef struct equiv_data equiv_data_t;
+typedef struct merge_cb_data merge_cb_data_t;
+
+/*
+ * There are two traversals in this file, for equivalency and for tdesc_t
+ * re-creation, that do not fit into the tdtraverse() framework. We have our
+ * own traversal mechanism and ops vector here for those two cases.
+ */
+typedef struct tdesc_ops {
+ const char *name;
+ int (*equiv)(tdesc_t *, tdesc_t *, equiv_data_t *);
+ tdesc_t *(*conjure)(tdesc_t *, int, merge_cb_data_t *);
+} tdesc_ops_t;
+extern tdesc_ops_t tdesc_ops[];
+
+/*
+ * The workhorse structure of tdata_t merging. Holds all lists of nodes to be
+ * processed during various phases of the merge algorithm.
+ */
+struct merge_cb_data {
+ tdata_t *md_parent;
+ tdata_t *md_tgt;
+ alist_t *md_ta; /* Type Association */
+ alist_t *md_fdida; /* Forward -> Definition ID Association */
+ list_t **md_iitba; /* iidesc_t nodes To Be Added to the parent */
+ hash_t *md_tdtba; /* tdesc_t nodes To Be Added to the parent */
+ list_t **md_tdtbr; /* tdesc_t nodes To Be Remapped */
+ int md_flags;
+}; /* merge_cb_data_t */
+
+/*
+ * When we first create a tdata_t from stabs data, we will have duplicate nodes.
+ * Normal merges, however, assume that the child tdata_t is already self-unique,
+ * and for speed reasons do not attempt to self-uniquify. If this flag is set,
+ * the merge algorithm will self-uniquify by avoiding the insertion of
+ * duplicates in the md_tdtdba list.
+ */
+#define MCD_F_SELFUNIQUIFY 0x1
+
+/*
+ * When we merge the CTF data for the modules, we don't want it to contain any
+ * data that can be found in the reference module (usually genunix). If this
+ * flag is set, we're doing a merge between the fully merged tdata_t for this
+ * module and the tdata_t for the reference module, with the data unique to this
+ * module ending up in a third tdata_t. It is this third tdata_t that will end
+ * up in the .SUNW_ctf section for the module.
+ */
+#define MCD_F_REFMERGE 0x2
+
+/*
+ * Mapping of child type IDs to parent type IDs
+ */
+
+static void
+add_mapping(alist_t *ta, tid_t srcid, tid_t tgtid)
+{
+ debug(3, "Adding mapping %u <%x> => %u <%x>\n", srcid, srcid, tgtid, tgtid);
+
+ assert(!alist_find(ta, (void *)(uintptr_t)srcid, NULL));
+ assert(srcid != 0 && tgtid != 0);
+
+ alist_add(ta, (void *)(uintptr_t)srcid, (void *)(uintptr_t)tgtid);
+}
+
+static tid_t
+get_mapping(alist_t *ta, int srcid)
+{
+ void *ltgtid;
+
+ if (alist_find(ta, (void *)(uintptr_t)srcid, (void **)&ltgtid))
+ return ((uintptr_t)ltgtid);
+ else
+ return (0);
+}
+
+/*
+ * Determining equivalence of tdesc_t subgraphs
+ */
+
+struct equiv_data {
+ alist_t *ed_ta;
+ tdesc_t *ed_node;
+ tdesc_t *ed_tgt;
+
+ int ed_clear_mark;
+ int ed_cur_mark;
+ int ed_selfuniquify;
+}; /* equiv_data_t */
+
+static int equiv_node(tdesc_t *, tdesc_t *, equiv_data_t *);
+
+/*ARGSUSED2*/
+static int
+equiv_intrinsic(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed __unused)
+{
+ intr_t *si = stdp->t_intr;
+ intr_t *ti = ttdp->t_intr;
+
+ if (si->intr_type != ti->intr_type ||
+ si->intr_signed != ti->intr_signed ||
+ si->intr_offset != ti->intr_offset ||
+ si->intr_nbits != ti->intr_nbits)
+ return (0);
+
+ if (si->intr_type == INTR_INT &&
+ si->intr_iformat != ti->intr_iformat)
+ return (0);
+ else if (si->intr_type == INTR_REAL &&
+ si->intr_fformat != ti->intr_fformat)
+ return (0);
+
+ return (1);
+}
+
+static int
+equiv_plain(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed)
+{
+ return (equiv_node(stdp->t_tdesc, ttdp->t_tdesc, ed));
+}
+
+static int
+equiv_function(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed)
+{
+ fndef_t *fn1 = stdp->t_fndef, *fn2 = ttdp->t_fndef;
+ int i;
+
+ if (fn1->fn_nargs != fn2->fn_nargs ||
+ fn1->fn_vargs != fn2->fn_vargs)
+ return (0);
+
+ if (!equiv_node(fn1->fn_ret, fn2->fn_ret, ed))
+ return (0);
+
+ for (i = 0; i < (int) fn1->fn_nargs; i++) {
+ if (!equiv_node(fn1->fn_args[i], fn2->fn_args[i], ed))
+ return (0);
+ }
+
+ return (1);
+}
+
+static int
+equiv_array(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed)
+{
+ ardef_t *ar1 = stdp->t_ardef, *ar2 = ttdp->t_ardef;
+
+ if (!equiv_node(ar1->ad_contents, ar2->ad_contents, ed) ||
+ !equiv_node(ar1->ad_idxtype, ar2->ad_idxtype, ed))
+ return (0);
+
+ if (ar1->ad_nelems != ar2->ad_nelems)
+ return (0);
+
+ return (1);
+}
+
+static int
+equiv_su(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed)
+{
+ mlist_t *ml1 = stdp->t_members, *ml2 = ttdp->t_members;
+
+ while (ml1 && ml2) {
+ if (ml1->ml_offset != ml2->ml_offset ||
+ strcmp(ml1->ml_name, ml2->ml_name) != 0 ||
+ ml1->ml_size != ml2->ml_size ||
+ !equiv_node(ml1->ml_type, ml2->ml_type, ed))
+ return (0);
+
+ ml1 = ml1->ml_next;
+ ml2 = ml2->ml_next;
+ }
+
+ if (ml1 || ml2)
+ return (0);
+
+ return (1);
+}
+
+/*ARGSUSED2*/
+static int
+equiv_enum(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed __unused)
+{
+ elist_t *el1 = stdp->t_emem;
+ elist_t *el2 = ttdp->t_emem;
+
+ while (el1 && el2) {
+ if (el1->el_number != el2->el_number ||
+ strcmp(el1->el_name, el2->el_name) != 0)
+ return (0);
+
+ el1 = el1->el_next;
+ el2 = el2->el_next;
+ }
+
+ if (el1 || el2)
+ return (0);
+
+ return (1);
+}
+
+/*ARGSUSED*/
+static int
+equiv_assert(tdesc_t *stdp __unused, tdesc_t *ttdp __unused, equiv_data_t *ed __unused)
+{
+ /* foul, evil, and very bad - this is a "shouldn't happen" */
+ assert(1 == 0);
+
+ return (0);
+}
+
+static int
+fwd_equiv(tdesc_t *ctdp, tdesc_t *mtdp)
+{
+ tdesc_t *defn = (ctdp->t_type == FORWARD ? mtdp : ctdp);
+
+ return (defn->t_type == STRUCT || defn->t_type == UNION ||
+ defn->t_type == ENUM);
+}
+
+static int
+equiv_node(tdesc_t *ctdp, tdesc_t *mtdp, equiv_data_t *ed)
+{
+ int (*equiv)(tdesc_t *, tdesc_t *, equiv_data_t *);
+ int mapping;
+
+ if (ctdp->t_emark > ed->ed_clear_mark &&
+ mtdp->t_emark > ed->ed_clear_mark)
+ return (ctdp->t_emark == mtdp->t_emark);
+
+ /*
+ * In normal (non-self-uniquify) mode, we don't want to do equivalency
+ * checking on a subgraph that has already been checked. If a mapping
+ * has already been established for a given child node, we can simply
+ * compare the mapping for the child node with the ID of the parent
+ * node. If we are in self-uniquify mode, then we're comparing two
+ * subgraphs within the child graph, and thus need to ignore any
+ * type mappings that have been created, as they are only valid into the
+ * parent.
+ */
+ if ((mapping = get_mapping(ed->ed_ta, ctdp->t_id)) > 0 &&
+ mapping == mtdp->t_id && !ed->ed_selfuniquify)
+ return (1);
+
+ if (!streq(ctdp->t_name, mtdp->t_name))
+ return (0);
+
+ if (ctdp->t_type != mtdp->t_type) {
+ if (ctdp->t_type == FORWARD || mtdp->t_type == FORWARD)
+ return (fwd_equiv(ctdp, mtdp));
+ else
+ return (0);
+ }
+
+ ctdp->t_emark = ed->ed_cur_mark;
+ mtdp->t_emark = ed->ed_cur_mark;
+ ed->ed_cur_mark++;
+
+ if ((equiv = tdesc_ops[ctdp->t_type].equiv) != NULL)
+ return (equiv(ctdp, mtdp, ed));
+
+ return (1);
+}
+
+/*
+ * We perform an equivalency check on two subgraphs by traversing through them
+ * in lockstep. If a given node is equivalent in both the parent and the child,
+ * we mark it in both subgraphs, using the t_emark field, with a monotonically
+ * increasing number. If, in the course of the traversal, we reach a node that
+ * we have visited and numbered during this equivalency check, we have a cycle.
+ * If the previously-visited nodes don't have the same emark, then the edges
+ * that brought us to these nodes are not equivalent, and so the check ends.
+ * If the emarks are the same, the edges are equivalent. We then backtrack and
+ * continue the traversal. If we have exhausted all edges in the subgraph, and
+ * have not found any inequivalent nodes, then the subgraphs are equivalent.
+ */
+static int
+equiv_cb(void *bucket, void *arg)
+{
+ equiv_data_t *ed = arg;
+ tdesc_t *mtdp = bucket;
+ tdesc_t *ctdp = ed->ed_node;
+
+ ed->ed_clear_mark = ed->ed_cur_mark + 1;
+ ed->ed_cur_mark = ed->ed_clear_mark + 1;
+
+ if (equiv_node(ctdp, mtdp, ed)) {
+ debug(3, "equiv_node matched %d <%x> %d <%x>\n",
+ ctdp->t_id, ctdp->t_id, mtdp->t_id, mtdp->t_id);
+ ed->ed_tgt = mtdp;
+ /* matched. stop looking */
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED1*/
+static int
+map_td_tree_pre(tdesc_t *ctdp, tdesc_t **ctdpp __unused, void *private)
+{
+ merge_cb_data_t *mcd = private;
+
+ if (get_mapping(mcd->md_ta, ctdp->t_id) > 0)
+ return (0);
+
+ return (1);
+}
+
+/*ARGSUSED1*/
+static int
+map_td_tree_post(tdesc_t *ctdp, tdesc_t **ctdpp __unused, void *private)
+{
+ merge_cb_data_t *mcd = private;
+ equiv_data_t ed;
+
+ ed.ed_ta = mcd->md_ta;
+ ed.ed_clear_mark = mcd->md_parent->td_curemark;
+ ed.ed_cur_mark = mcd->md_parent->td_curemark + 1;
+ ed.ed_node = ctdp;
+ ed.ed_selfuniquify = 0;
+
+ debug(3, "map_td_tree_post on %d <%x> %s\n", ctdp->t_id, ctdp->t_id,tdesc_name(ctdp));
+
+ if (hash_find_iter(mcd->md_parent->td_layouthash, ctdp,
+ equiv_cb, &ed) < 0) {
+ /* We found an equivalent node */
+ if (ed.ed_tgt->t_type == FORWARD && ctdp->t_type != FORWARD) {
+ int id = mcd->md_tgt->td_nextid++;
+
+ debug(3, "Creating new defn type %d <%x>\n", id, id);
+ add_mapping(mcd->md_ta, ctdp->t_id, id);
+ alist_add(mcd->md_fdida, (void *)(ulong_t)ed.ed_tgt,
+ (void *)(ulong_t)id);
+ hash_add(mcd->md_tdtba, ctdp);
+ } else
+ add_mapping(mcd->md_ta, ctdp->t_id, ed.ed_tgt->t_id);
+
+ } else if (debug_level > 1 && hash_iter(mcd->md_parent->td_idhash,
+ equiv_cb, &ed) < 0) {
+ /*
+ * We didn't find an equivalent node by looking through the
+ * layout hash, but we somehow found it by performing an
+ * exhaustive search through the entire graph. This usually
+ * means that the "name" hash function is broken.
+ */
+ aborterr("Second pass for %d (%s) == %d\n", ctdp->t_id,
+ tdesc_name(ctdp), ed.ed_tgt->t_id);
+ } else {
+ int id = mcd->md_tgt->td_nextid++;
+
+ debug(3, "Creating new type %d <%x>\n", id, id);
+ add_mapping(mcd->md_ta, ctdp->t_id, id);
+ hash_add(mcd->md_tdtba, ctdp);
+ }
+
+ mcd->md_parent->td_curemark = ed.ed_cur_mark + 1;
+
+ return (1);
+}
+
+/*ARGSUSED1*/
+static int
+map_td_tree_self_post(tdesc_t *ctdp, tdesc_t **ctdpp __unused, void *private)
+{
+ merge_cb_data_t *mcd = private;
+ equiv_data_t ed;
+
+ ed.ed_ta = mcd->md_ta;
+ ed.ed_clear_mark = mcd->md_parent->td_curemark;
+ ed.ed_cur_mark = mcd->md_parent->td_curemark + 1;
+ ed.ed_node = ctdp;
+ ed.ed_selfuniquify = 1;
+ ed.ed_tgt = NULL;
+
+ if (hash_find_iter(mcd->md_tdtba, ctdp, equiv_cb, &ed) < 0) {
+ debug(3, "Self check found %d <%x> in %d <%x>\n", ctdp->t_id,
+ ctdp->t_id, ed.ed_tgt->t_id, ed.ed_tgt->t_id);
+ add_mapping(mcd->md_ta, ctdp->t_id,
+ get_mapping(mcd->md_ta, ed.ed_tgt->t_id));
+ } else if (debug_level > 1 && hash_iter(mcd->md_tdtba,
+ equiv_cb, &ed) < 0) {
+ /*
+ * We didn't find an equivalent node using the quick way (going
+ * through the hash normally), but we did find it by iterating
+ * through the entire hash. This usually means that the hash
+ * function is broken.
+ */
+ aborterr("Self-unique second pass for %d <%x> (%s) == %d <%x>\n",
+ ctdp->t_id, ctdp->t_id, tdesc_name(ctdp), ed.ed_tgt->t_id,
+ ed.ed_tgt->t_id);
+ } else {
+ int id = mcd->md_tgt->td_nextid++;
+
+ debug(3, "Creating new type %d <%x>\n", id, id);
+ add_mapping(mcd->md_ta, ctdp->t_id, id);
+ hash_add(mcd->md_tdtba, ctdp);
+ }
+
+ mcd->md_parent->td_curemark = ed.ed_cur_mark + 1;
+
+ return (1);
+}
+
+static tdtrav_cb_f map_pre[] = {
+ NULL,
+ map_td_tree_pre, /* intrinsic */
+ map_td_tree_pre, /* pointer */
+ map_td_tree_pre, /* array */
+ map_td_tree_pre, /* function */
+ map_td_tree_pre, /* struct */
+ map_td_tree_pre, /* union */
+ map_td_tree_pre, /* enum */
+ map_td_tree_pre, /* forward */
+ map_td_tree_pre, /* typedef */
+ tdtrav_assert, /* typedef_unres */
+ map_td_tree_pre, /* volatile */
+ map_td_tree_pre, /* const */
+ map_td_tree_pre /* restrict */
+};
+
+static tdtrav_cb_f map_post[] = {
+ NULL,
+ map_td_tree_post, /* intrinsic */
+ map_td_tree_post, /* pointer */
+ map_td_tree_post, /* array */
+ map_td_tree_post, /* function */
+ map_td_tree_post, /* struct */
+ map_td_tree_post, /* union */
+ map_td_tree_post, /* enum */
+ map_td_tree_post, /* forward */
+ map_td_tree_post, /* typedef */
+ tdtrav_assert, /* typedef_unres */
+ map_td_tree_post, /* volatile */
+ map_td_tree_post, /* const */
+ map_td_tree_post /* restrict */
+};
+
+static tdtrav_cb_f map_self_post[] = {
+ NULL,
+ map_td_tree_self_post, /* intrinsic */
+ map_td_tree_self_post, /* pointer */
+ map_td_tree_self_post, /* array */
+ map_td_tree_self_post, /* function */
+ map_td_tree_self_post, /* struct */
+ map_td_tree_self_post, /* union */
+ map_td_tree_self_post, /* enum */
+ map_td_tree_self_post, /* forward */
+ map_td_tree_self_post, /* typedef */
+ tdtrav_assert, /* typedef_unres */
+ map_td_tree_self_post, /* volatile */
+ map_td_tree_self_post, /* const */
+ map_td_tree_self_post /* restrict */
+};
+
+/*
+ * Determining equivalence of iidesc_t nodes
+ */
+
+typedef struct iifind_data {
+ iidesc_t *iif_template;
+ alist_t *iif_ta;
+ int iif_newidx;
+ int iif_refmerge;
+} iifind_data_t;
+
+/*
+ * Check to see if this iidesc_t (node) - the current one on the list we're
+ * iterating through - matches the target one (iif->iif_template). Return -1
+ * if it matches, to stop the iteration.
+ */
+static int
+iidesc_match(void *data, void *arg)
+{
+ iidesc_t *node = data;
+ iifind_data_t *iif = arg;
+ int i;
+
+ if (node->ii_type != iif->iif_template->ii_type ||
+ !streq(node->ii_name, iif->iif_template->ii_name) ||
+ node->ii_dtype->t_id != iif->iif_newidx)
+ return (0);
+
+ if ((node->ii_type == II_SVAR || node->ii_type == II_SFUN) &&
+ !streq(node->ii_owner, iif->iif_template->ii_owner))
+ return (0);
+
+ if (node->ii_nargs != iif->iif_template->ii_nargs)
+ return (0);
+
+ for (i = 0; i < node->ii_nargs; i++) {
+ if (get_mapping(iif->iif_ta,
+ iif->iif_template->ii_args[i]->t_id) !=
+ node->ii_args[i]->t_id)
+ return (0);
+ }
+
+ if (iif->iif_refmerge) {
+ switch (iif->iif_template->ii_type) {
+ case II_GFUN:
+ case II_SFUN:
+ case II_GVAR:
+ case II_SVAR:
+ debug(3, "suppressing duping of %d %s from %s\n",
+ iif->iif_template->ii_type,
+ iif->iif_template->ii_name,
+ (iif->iif_template->ii_owner ?
+ iif->iif_template->ii_owner : "NULL"));
+ return (0);
+ case II_NOT:
+ case II_PSYM:
+ case II_SOU:
+ case II_TYPE:
+ break;
+ }
+ }
+
+ return (-1);
+}
+
+static int
+merge_type_cb(void *data, void *arg)
+{
+ iidesc_t *sii = data;
+ merge_cb_data_t *mcd = arg;
+ iifind_data_t iif;
+ tdtrav_cb_f *post;
+
+ post = (mcd->md_flags & MCD_F_SELFUNIQUIFY ? map_self_post : map_post);
+
+ /* Map the tdesc nodes */
+ (void) iitraverse(sii, &mcd->md_parent->td_curvgen, NULL, map_pre, post,
+ mcd);
+
+ /* Map the iidesc nodes */
+ iif.iif_template = sii;
+ iif.iif_ta = mcd->md_ta;
+ iif.iif_newidx = get_mapping(mcd->md_ta, sii->ii_dtype->t_id);
+ iif.iif_refmerge = (mcd->md_flags & MCD_F_REFMERGE);
+
+ if (hash_match(mcd->md_parent->td_iihash, sii, iidesc_match,
+ &iif) == 1)
+ /* successfully mapped */
+ return (1);
+
+ debug(3, "tba %s (%d)\n", (sii->ii_name ? sii->ii_name : "(anon)"),
+ sii->ii_type);
+
+ list_add(mcd->md_iitba, sii);
+
+ return (0);
+}
+
+static int
+remap_node(tdesc_t **tgtp, tdesc_t *oldtgt, int selftid, tdesc_t *newself,
+ merge_cb_data_t *mcd)
+{
+ tdesc_t *tgt = NULL;
+ tdesc_t template;
+ int oldid = oldtgt->t_id;
+
+ if (oldid == selftid) {
+ *tgtp = newself;
+ return (1);
+ }
+
+ if ((template.t_id = get_mapping(mcd->md_ta, oldid)) == 0)
+ aborterr("failed to get mapping for tid %d <%x>\n", oldid, oldid);
+
+ if (!hash_find(mcd->md_parent->td_idhash, (void *)&template,
+ (void *)&tgt) && (!(mcd->md_flags & MCD_F_REFMERGE) ||
+ !hash_find(mcd->md_tgt->td_idhash, (void *)&template,
+ (void *)&tgt))) {
+ debug(3, "Remap couldn't find %d <%x> (from %d <%x>)\n", template.t_id,
+ template.t_id, oldid, oldid);
+ *tgtp = oldtgt;
+ list_add(mcd->md_tdtbr, tgtp);
+ return (0);
+ }
+
+ *tgtp = tgt;
+ return (1);
+}
+
+static tdesc_t *
+conjure_template(tdesc_t *old, int newselfid)
+{
+ tdesc_t *new = xcalloc(sizeof (tdesc_t));
+
+ new->t_name = old->t_name ? xstrdup(old->t_name) : NULL;
+ new->t_type = old->t_type;
+ new->t_size = old->t_size;
+ new->t_id = newselfid;
+ new->t_flags = old->t_flags;
+
+ return (new);
+}
+
+/*ARGSUSED2*/
+static tdesc_t *
+conjure_intrinsic(tdesc_t *old, int newselfid, merge_cb_data_t *mcd __unused)
+{
+ tdesc_t *new = conjure_template(old, newselfid);
+
+ new->t_intr = xmalloc(sizeof (intr_t));
+ bcopy(old->t_intr, new->t_intr, sizeof (intr_t));
+
+ return (new);
+}
+
+static tdesc_t *
+conjure_plain(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)
+{
+ tdesc_t *new = conjure_template(old, newselfid);
+
+ (void) remap_node(&new->t_tdesc, old->t_tdesc, old->t_id, new, mcd);
+
+ return (new);
+}
+
+static tdesc_t *
+conjure_function(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)
+{
+ tdesc_t *new = conjure_template(old, newselfid);
+ fndef_t *nfn = xmalloc(sizeof (fndef_t));
+ fndef_t *ofn = old->t_fndef;
+ int i;
+
+ (void) remap_node(&nfn->fn_ret, ofn->fn_ret, old->t_id, new, mcd);
+
+ nfn->fn_nargs = ofn->fn_nargs;
+ nfn->fn_vargs = ofn->fn_vargs;
+
+ if (nfn->fn_nargs > 0)
+ nfn->fn_args = xcalloc(sizeof (tdesc_t *) * ofn->fn_nargs);
+
+ for (i = 0; i < (int) ofn->fn_nargs; i++) {
+ (void) remap_node(&nfn->fn_args[i], ofn->fn_args[i], old->t_id,
+ new, mcd);
+ }
+
+ new->t_fndef = nfn;
+
+ return (new);
+}
+
+static tdesc_t *
+conjure_array(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)
+{
+ tdesc_t *new = conjure_template(old, newselfid);
+ ardef_t *nar = xmalloc(sizeof (ardef_t));
+ ardef_t *oar = old->t_ardef;
+
+ (void) remap_node(&nar->ad_contents, oar->ad_contents, old->t_id, new,
+ mcd);
+ (void) remap_node(&nar->ad_idxtype, oar->ad_idxtype, old->t_id, new,
+ mcd);
+
+ nar->ad_nelems = oar->ad_nelems;
+
+ new->t_ardef = nar;
+
+ return (new);
+}
+
+static tdesc_t *
+conjure_su(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)
+{
+ tdesc_t *new = conjure_template(old, newselfid);
+ mlist_t *omem, **nmemp;
+
+ for (omem = old->t_members, nmemp = &new->t_members;
+ omem; omem = omem->ml_next, nmemp = &((*nmemp)->ml_next)) {
+ *nmemp = xmalloc(sizeof (mlist_t));
+ (*nmemp)->ml_offset = omem->ml_offset;
+ (*nmemp)->ml_size = omem->ml_size;
+ (*nmemp)->ml_name = xstrdup(omem->ml_name ? omem->ml_name : "empty omem->ml_name");
+ (void) remap_node(&((*nmemp)->ml_type), omem->ml_type,
+ old->t_id, new, mcd);
+ }
+ *nmemp = NULL;
+
+ return (new);
+}
+
+/*ARGSUSED2*/
+static tdesc_t *
+conjure_enum(tdesc_t *old, int newselfid, merge_cb_data_t *mcd __unused)
+{
+ tdesc_t *new = conjure_template(old, newselfid);
+ elist_t *oel, **nelp;
+
+ for (oel = old->t_emem, nelp = &new->t_emem;
+ oel; oel = oel->el_next, nelp = &((*nelp)->el_next)) {
+ *nelp = xmalloc(sizeof (elist_t));
+ (*nelp)->el_name = xstrdup(oel->el_name);
+ (*nelp)->el_number = oel->el_number;
+ }
+ *nelp = NULL;
+
+ return (new);
+}
+
+/*ARGSUSED2*/
+static tdesc_t *
+conjure_forward(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)
+{
+ tdesc_t *new = conjure_template(old, newselfid);
+
+ list_add(&mcd->md_tgt->td_fwdlist, new);
+
+ return (new);
+}
+
+/*ARGSUSED*/
+static tdesc_t *
+conjure_assert(tdesc_t *old __unused, int newselfid __unused, merge_cb_data_t *mcd __unused)
+{
+ assert(1 == 0);
+ return (NULL);
+}
+
+static iidesc_t *
+conjure_iidesc(iidesc_t *old, merge_cb_data_t *mcd)
+{
+ iidesc_t *new = iidesc_dup(old);
+ int i;
+
+ (void) remap_node(&new->ii_dtype, old->ii_dtype, -1, NULL, mcd);
+ for (i = 0; i < new->ii_nargs; i++) {
+ (void) remap_node(&new->ii_args[i], old->ii_args[i], -1, NULL,
+ mcd);
+ }
+
+ return (new);
+}
+
+static int
+fwd_redir(tdesc_t *fwd, tdesc_t **fwdp, void *private)
+{
+ alist_t *map = private;
+ void *defn;
+
+ if (!alist_find(map, (void *)fwd, (void **)&defn))
+ return (0);
+
+ debug(3, "Redirecting an edge to %s\n", tdesc_name(defn));
+
+ *fwdp = defn;
+
+ return (1);
+}
+
+static tdtrav_cb_f fwd_redir_cbs[] = {
+ NULL,
+ NULL, /* intrinsic */
+ NULL, /* pointer */
+ NULL, /* array */
+ NULL, /* function */
+ NULL, /* struct */
+ NULL, /* union */
+ NULL, /* enum */
+ fwd_redir, /* forward */
+ NULL, /* typedef */
+ tdtrav_assert, /* typedef_unres */
+ NULL, /* volatile */
+ NULL, /* const */
+ NULL /* restrict */
+};
+
+typedef struct redir_mstr_data {
+ tdata_t *rmd_tgt;
+ alist_t *rmd_map;
+} redir_mstr_data_t;
+
+static int
+redir_mstr_fwd_cb(void *name, void *value, void *arg)
+{
+ tdesc_t *fwd = name;
+ int defnid = (uintptr_t)value;
+ redir_mstr_data_t *rmd = arg;
+ tdesc_t template;
+ tdesc_t *defn;
+
+ template.t_id = defnid;
+
+ if (!hash_find(rmd->rmd_tgt->td_idhash, (void *)&template,
+ (void *)&defn)) {
+ aborterr("Couldn't unforward %d (%s)\n", defnid,
+ tdesc_name(defn));
+ }
+
+ debug(3, "Forward map: resolved %d to %s\n", defnid, tdesc_name(defn));
+
+ alist_add(rmd->rmd_map, (void *)fwd, (void *)defn);
+
+ return (1);
+}
+
+static void
+redir_mstr_fwds(merge_cb_data_t *mcd)
+{
+ redir_mstr_data_t rmd;
+ alist_t *map = alist_new(NULL, NULL);
+
+ rmd.rmd_tgt = mcd->md_tgt;
+ rmd.rmd_map = map;
+
+ if (alist_iter(mcd->md_fdida, redir_mstr_fwd_cb, &rmd)) {
+ (void) iitraverse_hash(mcd->md_tgt->td_iihash,
+ &mcd->md_tgt->td_curvgen, fwd_redir_cbs, NULL, NULL, map);
+ }
+
+ alist_free(map);
+}
+
+static int
+add_iitba_cb(void *data, void *private)
+{
+ merge_cb_data_t *mcd = private;
+ iidesc_t *tba = data;
+ iidesc_t *new;
+ iifind_data_t iif;
+ int newidx;
+
+ newidx = get_mapping(mcd->md_ta, tba->ii_dtype->t_id);
+ assert(newidx != -1);
+
+ (void) list_remove(mcd->md_iitba, data, NULL, NULL);
+
+ iif.iif_template = tba;
+ iif.iif_ta = mcd->md_ta;
+ iif.iif_newidx = newidx;
+ iif.iif_refmerge = (mcd->md_flags & MCD_F_REFMERGE);
+
+ if (hash_match(mcd->md_parent->td_iihash, tba, iidesc_match,
+ &iif) == 1) {
+ debug(3, "iidesc_t %s already exists\n",
+ (tba->ii_name ? tba->ii_name : "(anon)"));
+ return (1);
+ }
+
+ new = conjure_iidesc(tba, mcd);
+ hash_add(mcd->md_tgt->td_iihash, new);
+
+ return (1);
+}
+
+static int
+add_tdesc(tdesc_t *oldtdp, int newid, merge_cb_data_t *mcd)
+{
+ tdesc_t *newtdp;
+ tdesc_t template;
+
+ template.t_id = newid;
+ assert(hash_find(mcd->md_parent->td_idhash,
+ (void *)&template, NULL) == 0);
+
+ debug(3, "trying to conjure %d %s (%d, <%x>) as %d, <%x>\n",
+ oldtdp->t_type, tdesc_name(oldtdp), oldtdp->t_id,
+ oldtdp->t_id, newid, newid);
+
+ if ((newtdp = tdesc_ops[oldtdp->t_type].conjure(oldtdp, newid,
+ mcd)) == NULL)
+ /* couldn't map everything */
+ return (0);
+
+ debug(3, "succeeded\n");
+
+ hash_add(mcd->md_tgt->td_idhash, newtdp);
+ hash_add(mcd->md_tgt->td_layouthash, newtdp);
+
+ return (1);
+}
+
+static int
+add_tdtba_cb(void *data, void *arg)
+{
+ tdesc_t *tdp = data;
+ merge_cb_data_t *mcd = arg;
+ int newid;
+ int rc;
+
+ newid = get_mapping(mcd->md_ta, tdp->t_id);
+ assert(newid != -1);
+
+ if ((rc = add_tdesc(tdp, newid, mcd)))
+ hash_remove(mcd->md_tdtba, (void *)tdp);
+
+ return (rc);
+}
+
+static int
+add_tdtbr_cb(void *data, void *arg)
+{
+ tdesc_t **tdpp = data;
+ merge_cb_data_t *mcd = arg;
+
+ debug(3, "Remapping %s (%d)\n", tdesc_name(*tdpp), (*tdpp)->t_id);
+
+ if (!remap_node(tdpp, *tdpp, -1, NULL, mcd))
+ return (0);
+
+ (void) list_remove(mcd->md_tdtbr, (void *)tdpp, NULL, NULL);
+ return (1);
+}
+
+static void
+merge_types(hash_t *src, merge_cb_data_t *mcd)
+{
+ list_t *iitba = NULL;
+ list_t *tdtbr = NULL;
+ int iirc, tdrc;
+
+ mcd->md_iitba = &iitba;
+ mcd->md_tdtba = hash_new(TDATA_LAYOUT_HASH_SIZE, tdesc_layouthash,
+ tdesc_layoutcmp);
+ mcd->md_tdtbr = &tdtbr;
+
+ (void) hash_iter(src, merge_type_cb, mcd);
+
+ tdrc = hash_iter(mcd->md_tdtba, add_tdtba_cb, mcd);
+ debug(3, "add_tdtba_cb added %d items\n", tdrc);
+
+ iirc = list_iter(*mcd->md_iitba, add_iitba_cb, mcd);
+ debug(3, "add_iitba_cb added %d items\n", iirc);
+
+ assert(list_count(*mcd->md_iitba) == 0 &&
+ hash_count(mcd->md_tdtba) == 0);
+
+ tdrc = list_iter(*mcd->md_tdtbr, add_tdtbr_cb, mcd);
+ debug(3, "add_tdtbr_cb added %d items\n", tdrc);
+
+ if (list_count(*mcd->md_tdtbr) != 0)
+ aborterr("Couldn't remap all nodes\n");
+
+ /*
+ * We now have an alist of master forwards and the ids of the new master
+ * definitions for those forwards in mcd->md_fdida. By this point,
+ * we're guaranteed that all of the master definitions referenced in
+ * fdida have been added to the master tree. We now traverse through
+ * the master tree, redirecting all edges inbound to forwards that have
+ * definitions to those definitions.
+ */
+ if (mcd->md_parent == mcd->md_tgt) {
+ redir_mstr_fwds(mcd);
+ }
+}
+
+void
+merge_into_master(tdata_t *cur, tdata_t *mstr, tdata_t *tgt, int selfuniquify)
+{
+ merge_cb_data_t mcd;
+
+ cur->td_ref++;
+ mstr->td_ref++;
+ if (tgt)
+ tgt->td_ref++;
+
+ assert(cur->td_ref == 1 && mstr->td_ref == 1 &&
+ (tgt == NULL || tgt->td_ref == 1));
+
+ mcd.md_parent = mstr;
+ mcd.md_tgt = (tgt ? tgt : mstr);
+ mcd.md_ta = alist_new(NULL, NULL);
+ mcd.md_fdida = alist_new(NULL, NULL);
+ mcd.md_flags = 0;
+
+ if (selfuniquify)
+ mcd.md_flags |= MCD_F_SELFUNIQUIFY;
+ if (tgt)
+ mcd.md_flags |= MCD_F_REFMERGE;
+
+ mstr->td_curvgen = MAX(mstr->td_curvgen, cur->td_curvgen);
+ mstr->td_curemark = MAX(mstr->td_curemark, cur->td_curemark);
+
+ merge_types(cur->td_iihash, &mcd);
+
+ if (debug_level >= 3) {
+ debug(3, "Type association stats\n");
+ alist_stats(mcd.md_ta, 0);
+ debug(3, "Layout hash stats\n");
+ hash_stats(mcd.md_tgt->td_layouthash, 1);
+ }
+
+ alist_free(mcd.md_fdida);
+ alist_free(mcd.md_ta);
+
+ cur->td_ref--;
+ mstr->td_ref--;
+ if (tgt)
+ tgt->td_ref--;
+}
+
+tdesc_ops_t tdesc_ops[] = {
+ { "ERROR! BAD tdesc TYPE", NULL, NULL },
+ { "intrinsic", equiv_intrinsic, conjure_intrinsic },
+ { "pointer", equiv_plain, conjure_plain },
+ { "array", equiv_array, conjure_array },
+ { "function", equiv_function, conjure_function },
+ { "struct", equiv_su, conjure_su },
+ { "union", equiv_su, conjure_su },
+ { "enum", equiv_enum, conjure_enum },
+ { "forward", NULL, conjure_forward },
+ { "typedef", equiv_plain, conjure_plain },
+ { "typedef_unres", equiv_assert, conjure_assert },
+ { "volatile", equiv_plain, conjure_plain },
+ { "const", equiv_plain, conjure_plain },
+ { "restrict", equiv_plain, conjure_plain }
+};
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/output.c b/cddl/contrib/opensolaris/tools/ctf/cvt/output.c
new file mode 100644
index 000000000000..3385e4b2d09f
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/output.c
@@ -0,0 +1,775 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Routines for preparing tdata trees for conversion into CTF data, and
+ * for placing the resulting data into an output file.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <unistd.h>
+
+#include "ctftools.h"
+#include "list.h"
+#include "memory.h"
+#include "traverse.h"
+#include "symbol.h"
+
+typedef struct iidesc_match {
+ int iim_fuzzy;
+ iidesc_t *iim_ret;
+ char *iim_name;
+ char *iim_file;
+ uchar_t iim_bind;
+} iidesc_match_t;
+
+static int
+burst_iitypes(void *data, void *arg)
+{
+ iidesc_t *ii = data;
+ iiburst_t *iiburst = arg;
+
+ switch (ii->ii_type) {
+ case II_GFUN:
+ case II_SFUN:
+ case II_GVAR:
+ case II_SVAR:
+ if (!(ii->ii_flags & IIDESC_F_USED))
+ return (0);
+ break;
+ default:
+ break;
+ }
+
+ ii->ii_dtype->t_flags |= TDESC_F_ISROOT;
+ (void) iitraverse_td(ii, iiburst->iib_tdtd);
+ return (1);
+}
+
+/*ARGSUSED1*/
+static int
+save_type_by_id(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private)
+{
+ iiburst_t *iiburst = private;
+
+ /*
+ * Doing this on every node is horribly inefficient, but given that
+ * we may be suppressing some types, we can't trust nextid in the
+ * tdata_t.
+ */
+ if (tdp->t_id > iiburst->iib_maxtypeid)
+ iiburst->iib_maxtypeid = tdp->t_id;
+
+ slist_add(&iiburst->iib_types, tdp, tdesc_idcmp);
+
+ return (1);
+}
+
+static tdtrav_cb_f burst_types_cbs[] = {
+ NULL,
+ save_type_by_id, /* intrinsic */
+ save_type_by_id, /* pointer */
+ save_type_by_id, /* array */
+ save_type_by_id, /* function */
+ save_type_by_id, /* struct */
+ save_type_by_id, /* union */
+ save_type_by_id, /* enum */
+ save_type_by_id, /* forward */
+ save_type_by_id, /* typedef */
+ tdtrav_assert, /* typedef_unres */
+ save_type_by_id, /* volatile */
+ save_type_by_id, /* const */
+ save_type_by_id /* restrict */
+};
+
+
+static iiburst_t *
+iiburst_new(tdata_t *td, int max)
+{
+ iiburst_t *iiburst = xcalloc(sizeof (iiburst_t));
+ iiburst->iib_td = td;
+ iiburst->iib_funcs = xcalloc(sizeof (iidesc_t *) * max);
+ iiburst->iib_nfuncs = 0;
+ iiburst->iib_objts = xcalloc(sizeof (iidesc_t *) * max);
+ iiburst->iib_nobjts = 0;
+ return (iiburst);
+}
+
+static void
+iiburst_types(iiburst_t *iiburst)
+{
+ tdtrav_data_t tdtd;
+
+ tdtrav_init(&tdtd, &iiburst->iib_td->td_curvgen, NULL, burst_types_cbs,
+ NULL, (void *)iiburst);
+
+ iiburst->iib_tdtd = &tdtd;
+
+ (void) hash_iter(iiburst->iib_td->td_iihash, burst_iitypes, iiburst);
+}
+
+static void
+iiburst_free(iiburst_t *iiburst)
+{
+ free(iiburst->iib_funcs);
+ free(iiburst->iib_objts);
+ list_free(iiburst->iib_types, NULL, NULL);
+ free(iiburst);
+}
+
+/*
+ * See if this iidesc matches the ELF symbol data we pass in.
+ *
+ * A fuzzy match is where we have a local symbol matching the name of a
+ * global type description. This is common when a mapfile is used for a
+ * DSO, but we don't accept it by default.
+ *
+ * A weak fuzzy match is when a weak symbol was resolved and matched to
+ * a global type description.
+ */
+static int
+matching_iidesc(void *arg1, void *arg2)
+{
+ iidesc_t *iidesc = arg1;
+ iidesc_match_t *match = arg2;
+ if (streq(iidesc->ii_name, match->iim_name) == 0)
+ return (0);
+
+ switch (iidesc->ii_type) {
+ case II_GFUN:
+ case II_GVAR:
+ if (match->iim_bind == STB_GLOBAL) {
+ match->iim_ret = iidesc;
+ return (-1);
+ } else if (match->iim_fuzzy && match->iim_ret == NULL) {
+ match->iim_ret = iidesc;
+ /* continue to look for strong match */
+ return (0);
+ }
+ break;
+ case II_SFUN:
+ case II_SVAR:
+ if (match->iim_bind == STB_LOCAL &&
+ match->iim_file != NULL &&
+ streq(iidesc->ii_owner, match->iim_file)) {
+ match->iim_ret = iidesc;
+ return (-1);
+ }
+ break;
+ default:
+ break;
+ }
+ return (0);
+}
+
+static iidesc_t *
+find_iidesc(tdata_t *td, iidesc_match_t *match)
+{
+ match->iim_ret = NULL;
+ iter_iidescs_by_name(td, match->iim_name,
+ matching_iidesc, match);
+ return (match->iim_ret);
+}
+
+/*
+ * If we have a weak symbol, attempt to find the strong symbol it will
+ * resolve to. Note: the code where this actually happens is in
+ * sym_process() in cmd/sgs/libld/common/syms.c
+ *
+ * Finding the matching symbol is unfortunately not trivial. For a
+ * symbol to be a candidate, it must:
+ *
+ * - have the same type (function, object)
+ * - have the same value (address)
+ * - have the same size
+ * - not be another weak symbol
+ * - belong to the same section (checked via section index)
+ *
+ * If such a candidate is global, then we assume we've found it. The
+ * linker generates the symbol table such that the curfile might be
+ * incorrect; this is OK for global symbols, since find_iidesc() doesn't
+ * need to check for the source file for the symbol.
+ *
+ * We might have found a strong local symbol, where the curfile is
+ * accurate and matches that of the weak symbol. We assume this is a
+ * reasonable match.
+ *
+ * If we've got a local symbol with a non-matching curfile, there are
+ * two possibilities. Either this is a completely different symbol, or
+ * it's a once-global symbol that was scoped to local via a mapfile. In
+ * the latter case, curfile is likely inaccurate since the linker does
+ * not preserve the needed curfile in the order of the symbol table (see
+ * the comments about locally scoped symbols in libld's update_osym()).
+ * As we can't tell this case from the former one, we use this symbol
+ * iff no other matching symbol is found.
+ *
+ * What we really need here is a SUNW section containing weak<->strong
+ * mappings that we can consume.
+ */
+static int
+check_for_weak(GElf_Sym *weak, char const *weakfile,
+ Elf_Data *data, int nent, Elf_Data *strdata,
+ GElf_Sym *retsym, char **curfilep)
+{
+ char *curfile = NULL;
+ char *tmpfile1 = NULL;
+ GElf_Sym tmpsym;
+ int candidate = 0;
+ int i;
+ tmpsym.st_info = 0;
+ tmpsym.st_name = 0;
+
+ if (GELF_ST_BIND(weak->st_info) != STB_WEAK)
+ return (0);
+
+ for (i = 0; i < nent; i++) {
+ GElf_Sym sym;
+ uchar_t type;
+
+ if (gelf_getsym(data, i, &sym) == NULL)
+ continue;
+
+ type = GELF_ST_TYPE(sym.st_info);
+
+ if (type == STT_FILE)
+ curfile = (char *)strdata->d_buf + sym.st_name;
+
+ if (GELF_ST_TYPE(weak->st_info) != type ||
+ weak->st_value != sym.st_value)
+ continue;
+
+ if (weak->st_size != sym.st_size)
+ continue;
+
+ if (GELF_ST_BIND(sym.st_info) == STB_WEAK)
+ continue;
+
+ if (sym.st_shndx != weak->st_shndx)
+ continue;
+
+ if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
+ (curfile == NULL || weakfile == NULL ||
+ strcmp(curfile, weakfile) != 0)) {
+ candidate = 1;
+ tmpfile1 = curfile;
+ tmpsym = sym;
+ continue;
+ }
+
+ *curfilep = curfile;
+ *retsym = sym;
+ return (1);
+ }
+
+ if (candidate) {
+ *curfilep = tmpfile1;
+ *retsym = tmpsym;
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * When we've found the underlying symbol's type description
+ * for a weak symbol, we need to copy it and rename it to match
+ * the weak symbol. We also need to add it to the td so it's
+ * handled along with the others later.
+ */
+static iidesc_t *
+copy_from_strong(tdata_t *td, GElf_Sym *sym, iidesc_t *strongdesc,
+ const char *weakname, const char *weakfile)
+{
+ iidesc_t *new = iidesc_dup_rename(strongdesc, weakname, weakfile);
+ uchar_t type = GELF_ST_TYPE(sym->st_info);
+
+ switch (type) {
+ case STT_OBJECT:
+ new->ii_type = II_GVAR;
+ break;
+ case STT_FUNC:
+ new->ii_type = II_GFUN;
+ break;
+ }
+
+ hash_add(td->td_iihash, new);
+
+ return (new);
+}
+
+/*
+ * Process the symbol table of the output file, associating each symbol
+ * with a type description if possible, and sorting them into functions
+ * and data, maintaining symbol table order.
+ */
+static iiburst_t *
+sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch,
+ int dynsym)
+{
+ iiburst_t *iiburst;
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+ Elf_Data *data, *strdata;
+ int i, stidx;
+ int nent;
+ iidesc_match_t match;
+
+ match.iim_fuzzy = fuzzymatch;
+ match.iim_file = NULL;
+
+ if ((stidx = findelfsecidx(elf, file,
+ dynsym ? ".dynsym" : ".symtab")) < 0)
+ terminate("%s: Can't open symbol table\n", file);
+ scn = elf_getscn(elf, stidx);
+ data = elf_getdata(scn, NULL);
+ gelf_getshdr(scn, &shdr);
+ nent = shdr.sh_size / shdr.sh_entsize;
+
+ scn = elf_getscn(elf, shdr.sh_link);
+ strdata = elf_getdata(scn, NULL);
+
+ iiburst = iiburst_new(td, nent);
+
+ for (i = 0; i < nent; i++) {
+ GElf_Sym sym;
+ char *bname;
+ iidesc_t **tolist;
+ GElf_Sym ssym;
+ iidesc_match_t smatch;
+ int *curr;
+ iidesc_t *iidesc;
+
+ if (gelf_getsym(data, i, &sym) == NULL)
+ elfterminate(file, "Couldn't read symbol %d", i);
+
+ match.iim_name = (char *)strdata->d_buf + sym.st_name;
+ match.iim_bind = GELF_ST_BIND(sym.st_info);
+
+ switch (GELF_ST_TYPE(sym.st_info)) {
+ case STT_FILE:
+ bname = strrchr(match.iim_name, '/');
+ match.iim_file = bname == NULL ? match.iim_name : bname + 1;
+ continue;
+ case STT_OBJECT:
+ tolist = iiburst->iib_objts;
+ curr = &iiburst->iib_nobjts;
+ break;
+ case STT_FUNC:
+ tolist = iiburst->iib_funcs;
+ curr = &iiburst->iib_nfuncs;
+ break;
+ default:
+ continue;
+ }
+
+ if (ignore_symbol(&sym, match.iim_name))
+ continue;
+
+ iidesc = find_iidesc(td, &match);
+
+ if (iidesc != NULL) {
+ tolist[*curr] = iidesc;
+ iidesc->ii_flags |= IIDESC_F_USED;
+ (*curr)++;
+ continue;
+ }
+
+ if (!check_for_weak(&sym, match.iim_file, data, nent, strdata,
+ &ssym, &smatch.iim_file)) {
+ (*curr)++;
+ continue;
+ }
+
+ smatch.iim_fuzzy = fuzzymatch;
+ smatch.iim_name = (char *)strdata->d_buf + ssym.st_name;
+ smatch.iim_bind = GELF_ST_BIND(ssym.st_info);
+
+ debug(3, "Weak symbol %s resolved to %s\n", match.iim_name,
+ smatch.iim_name);
+
+ iidesc = find_iidesc(td, &smatch);
+
+ if (iidesc != NULL) {
+ tolist[*curr] = copy_from_strong(td, &sym,
+ iidesc, match.iim_name, match.iim_file);
+ tolist[*curr]->ii_flags |= IIDESC_F_USED;
+ }
+
+ (*curr)++;
+ }
+
+ /*
+ * Stabs are generated for every function declared in a given C source
+ * file. When converting an object file, we may encounter a stab that
+ * has no symbol table entry because the optimizer has decided to omit
+ * that item (for example, an unreferenced static function). We may
+ * see iidescs that do not have an associated symtab entry, and so
+ * we do not write records for those functions into the CTF data.
+ * All others get marked as a root by this function.
+ */
+ iiburst_types(iiburst);
+
+ /*
+ * By not adding some of the functions and/or objects, we may have
+ * caused some types that were referenced solely by those
+ * functions/objects to be suppressed. This could cause a label,
+ * generated prior to the evisceration, to be incorrect. Find the
+ * highest type index, and change the label indicies to be no higher
+ * than this value.
+ */
+ tdata_label_newmax(td, iiburst->iib_maxtypeid);
+
+ return (iiburst);
+}
+
+static void
+write_file(Elf *src, const char *srcname, Elf *dst, const char *dstname,
+ caddr_t ctfdata, size_t ctfsize, int flags)
+{
+ GElf_Ehdr sehdr, dehdr;
+ Elf_Scn *sscn, *dscn;
+ Elf_Data *sdata, *ddata;
+ GElf_Shdr shdr;
+ GElf_Word symtab_type;
+ int symtab_idx = -1;
+ off_t new_offset = 0;
+ off_t ctfnameoff = 0;
+ int dynsym = (flags & CTF_USE_DYNSYM);
+ int keep_stabs = (flags & CTF_KEEP_STABS);
+ int *secxlate;
+ int srcidx, dstidx;
+ int curnmoff = 0;
+ int changing = 0;
+ int pad;
+ int i;
+
+ if (gelf_newehdr(dst, gelf_getclass(src)) == NULL)
+ elfterminate(dstname, "Cannot copy ehdr to temp file");
+ gelf_getehdr(src, &sehdr);
+ memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
+ gelf_update_ehdr(dst, &dehdr);
+
+ symtab_type = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
+
+ /*
+ * Neither the existing stab sections nor the SUNW_ctf sections (new or
+ * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
+ * program headers. As such, we can just blindly copy the program
+ * headers from the existing file to the new file.
+ */
+ if (sehdr.e_phnum != 0) {
+ (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
+ if (gelf_newphdr(dst, sehdr.e_phnum) == NULL)
+ elfterminate(dstname, "Cannot make phdrs in temp file");
+
+ for (i = 0; i < sehdr.e_phnum; i++) {
+ GElf_Phdr phdr;
+
+ gelf_getphdr(src, i, &phdr);
+ gelf_update_phdr(dst, i, &phdr);
+ }
+ }
+
+ secxlate = xmalloc(sizeof (int) * sehdr.e_shnum);
+ for (srcidx = dstidx = 0; srcidx < sehdr.e_shnum; srcidx++) {
+ Elf_Scn *scn = elf_getscn(src, srcidx);
+ GElf_Shdr shdr1;
+ char *sname;
+
+ gelf_getshdr(scn, &shdr1);
+ sname = elf_strptr(src, sehdr.e_shstrndx, shdr1.sh_name);
+ if (sname == NULL) {
+ elfterminate(srcname, "Can't find string at %u",
+ shdr1.sh_name);
+ }
+
+ if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
+ secxlate[srcidx] = -1;
+ } else if (!keep_stabs &&
+ (strncmp(sname, ".stab", 5) == 0 ||
+ strncmp(sname, ".debug", 6) == 0 ||
+ strncmp(sname, ".rel.debug", 10) == 0 ||
+ strncmp(sname, ".rela.debug", 11) == 0)) {
+ secxlate[srcidx] = -1;
+ } else if (dynsym && shdr1.sh_type == SHT_SYMTAB) {
+ /*
+ * If we're building CTF against the dynsym,
+ * we'll rip out the symtab so debuggers aren't
+ * confused.
+ */
+ secxlate[srcidx] = -1;
+ } else {
+ secxlate[srcidx] = dstidx++;
+ curnmoff += strlen(sname) + 1;
+ }
+
+ new_offset = (off_t)dehdr.e_phoff;
+ }
+
+ for (srcidx = 1; srcidx < sehdr.e_shnum; srcidx++) {
+ char *sname;
+
+ sscn = elf_getscn(src, srcidx);
+ gelf_getshdr(sscn, &shdr);
+
+ if (secxlate[srcidx] == -1) {
+ changing = 1;
+ continue;
+ }
+
+ dscn = elf_newscn(dst);
+
+ /*
+ * If this file has program headers, we need to explicitly lay
+ * out sections. If none of the sections prior to this one have
+ * been removed, then we can just use the existing location. If
+ * one or more sections have been changed, then we need to
+ * adjust this one to avoid holes.
+ */
+ if (changing && sehdr.e_phnum != 0) {
+ pad = new_offset % shdr.sh_addralign;
+
+ if (pad)
+ new_offset += shdr.sh_addralign - pad;
+ shdr.sh_offset = new_offset;
+ }
+
+ shdr.sh_link = secxlate[shdr.sh_link];
+
+ if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
+ shdr.sh_info = secxlate[shdr.sh_info];
+
+ sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name);
+ if (sname == NULL) {
+ elfterminate(srcname, "Can't find string at %u",
+ shdr.sh_name);
+ }
+
+#ifndef illumos
+ if (gelf_update_shdr(dscn, &shdr) == 0)
+ elfterminate(dstname, "Cannot update sect %s", sname);
+#endif
+
+ if ((sdata = elf_getdata(sscn, NULL)) == NULL)
+ elfterminate(srcname, "Cannot get sect %s data", sname);
+ if ((ddata = elf_newdata(dscn)) == NULL)
+ elfterminate(dstname, "Can't make sect %s data", sname);
+#ifdef illumos
+ bcopy(sdata, ddata, sizeof (Elf_Data));
+#else
+ /*
+ * FreeBSD's Elf_Data has private fields which the
+ * elf_* routines manage. Simply copying the
+ * entire structure corrupts the data. So we need
+ * to copy the public fields explictly.
+ */
+ ddata->d_align = sdata->d_align;
+ ddata->d_off = sdata->d_off;
+ ddata->d_size = sdata->d_size;
+ ddata->d_type = sdata->d_type;
+ ddata->d_version = sdata->d_version;
+#endif
+
+ if (srcidx == sehdr.e_shstrndx) {
+ char seclen = strlen(CTF_ELF_SCN_NAME);
+
+ ddata->d_buf = xmalloc(ddata->d_size + shdr.sh_size +
+ seclen + 1);
+ bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
+ strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
+ CTF_ELF_SCN_NAME);
+ ctfnameoff = (off_t)shdr.sh_size;
+ shdr.sh_size += seclen + 1;
+ ddata->d_size += seclen + 1;
+
+ if (sehdr.e_phnum != 0)
+ changing = 1;
+ }
+
+ if (shdr.sh_type == symtab_type && shdr.sh_entsize != 0) {
+ int nsym = shdr.sh_size / shdr.sh_entsize;
+
+ symtab_idx = secxlate[srcidx];
+
+ ddata->d_buf = xmalloc(shdr.sh_size);
+ bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
+
+ for (i = 0; i < nsym; i++) {
+ GElf_Sym sym;
+ short newscn;
+
+ if (gelf_getsym(ddata, i, &sym) == NULL)
+ printf("Could not get symbol %d\n",i);
+
+ if (sym.st_shndx >= SHN_LORESERVE)
+ continue;
+
+ if ((newscn = secxlate[sym.st_shndx]) !=
+ sym.st_shndx) {
+ sym.st_shndx =
+ (newscn == -1 ? 1 : newscn);
+
+ gelf_update_sym(ddata, i, &sym);
+ }
+ }
+ }
+
+#ifndef illumos
+ if (ddata->d_buf == NULL && sdata->d_buf != NULL) {
+ ddata->d_buf = xmalloc(shdr.sh_size);
+ bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
+ }
+#endif
+
+ if (gelf_update_shdr(dscn, &shdr) == 0)
+ elfterminate(dstname, "Cannot update sect %s", sname);
+
+ new_offset = (off_t)shdr.sh_offset;
+ if (shdr.sh_type != SHT_NOBITS)
+ new_offset += shdr.sh_size;
+ }
+
+ if (symtab_idx == -1) {
+ terminate("%s: Cannot find %s section\n", srcname,
+ dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB");
+ }
+
+ /* Add the ctf section */
+ dscn = elf_newscn(dst);
+ gelf_getshdr(dscn, &shdr);
+ shdr.sh_name = ctfnameoff;
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_size = ctfsize;
+ shdr.sh_link = symtab_idx;
+ shdr.sh_addralign = 4;
+ if (changing && sehdr.e_phnum != 0) {
+ pad = new_offset % shdr.sh_addralign;
+
+ if (pad)
+ new_offset += shdr.sh_addralign - pad;
+
+ shdr.sh_offset = new_offset;
+ new_offset += shdr.sh_size;
+ }
+
+ ddata = elf_newdata(dscn);
+ ddata->d_buf = ctfdata;
+ ddata->d_size = ctfsize;
+ ddata->d_align = shdr.sh_addralign;
+ ddata->d_off = 0;
+
+ gelf_update_shdr(dscn, &shdr);
+
+ /* update the section header location */
+ if (sehdr.e_phnum != 0) {
+ size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
+ size_t r = new_offset % align;
+
+ if (r)
+ new_offset += align - r;
+
+ dehdr.e_shoff = new_offset;
+ }
+
+ /* commit to disk */
+ dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
+ gelf_update_ehdr(dst, &dehdr);
+ if (elf_update(dst, ELF_C_WRITE) < 0)
+ elfterminate(dstname, "Cannot finalize temp file");
+
+ free(secxlate);
+}
+
+static caddr_t
+make_ctf_data(tdata_t *td, Elf *elf, const char *file, size_t *lenp, int flags)
+{
+ iiburst_t *iiburst;
+ caddr_t data;
+
+ iiburst = sort_iidescs(elf, file, td, flags & CTF_FUZZY_MATCH,
+ flags & CTF_USE_DYNSYM);
+ data = ctf_gen(iiburst, lenp, flags & (CTF_COMPRESS | CTF_SWAP_BYTES));
+
+ iiburst_free(iiburst);
+
+ return (data);
+}
+
+void
+write_ctf(tdata_t *td, const char *curname, const char *newname, int flags)
+{
+ struct stat st;
+ Elf *elf = NULL;
+ Elf *telf = NULL;
+ GElf_Ehdr ehdr;
+ caddr_t data;
+ size_t len;
+ int fd = -1;
+ int tfd = -1;
+ int byteorder;
+
+ (void) elf_version(EV_CURRENT);
+ if ((fd = open(curname, O_RDONLY)) < 0 || fstat(fd, &st) < 0)
+ terminate("%s: Cannot open for re-reading", curname);
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
+ elfterminate(curname, "Cannot re-read");
+
+ if ((tfd = open(newname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0)
+ terminate("Cannot open temp file %s for writing", newname);
+ if ((telf = elf_begin(tfd, ELF_C_WRITE, NULL)) == NULL)
+ elfterminate(curname, "Cannot write");
+
+ if (gelf_getehdr(elf, &ehdr)) {
+#if BYTE_ORDER == _BIG_ENDIAN
+ byteorder = ELFDATA2MSB;
+#else
+ byteorder = ELFDATA2LSB;
+#endif
+ /*
+ * If target and host has the same byte order
+ * clear byte swapping request
+ */
+ if (ehdr.e_ident[EI_DATA] == byteorder)
+ flags &= ~CTF_SWAP_BYTES;
+ }
+ else
+ elfterminate(curname, "Failed to get EHDR");
+
+ data = make_ctf_data(td, elf, curname, &len, flags);
+ write_file(elf, curname, telf, newname, data, len, flags);
+ free(data);
+
+ elf_end(telf);
+ elf_end(elf);
+ (void) close(fd);
+ (void) close(tfd);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/st_parse.c b/cddl/contrib/opensolaris/tools/ctf/cvt/st_parse.c
new file mode 100644
index 000000000000..a452ca5960a7
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/st_parse.c
@@ -0,0 +1,1214 @@
+/*
+ * 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 (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * This file is a sewer.
+ */
+
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <assert.h>
+#include <strings.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <uts/common/sys/ctf.h>
+
+#include "ctftools.h"
+#include "memory.h"
+#include "list.h"
+
+#define HASH(NUM) ((int)(NUM & (BUCKETS - 1)))
+#define BUCKETS 128
+
+#define TYPEPAIRMULT 10000
+#define MAKETYPEID(file, num) ((file) * TYPEPAIRMULT + num)
+#define TYPEFILE(tid) ((tid) / TYPEPAIRMULT)
+#define TYPENUM(tid) ((tid) % TYPEPAIRMULT)
+
+#define expected(a, b, c) _expected(a, b, c, __LINE__)
+
+static int faketypenumber = 100000000;
+
+static tdesc_t *hash_table[BUCKETS];
+static tdesc_t *name_table[BUCKETS];
+
+static list_t *typedbitfldmems;
+
+static void reset(void);
+static jmp_buf resetbuf;
+
+static char *soudef(char *cp, stabtype_t type, tdesc_t **rtdp);
+static void enumdef(char *cp, tdesc_t **rtdp);
+static int compute_sum(const char *w);
+
+static char *number(char *cp, int *n);
+static char *name(char *cp, char **w);
+static char *id(char *cp, int *h);
+static char *whitesp(char *cp);
+static void addhash(tdesc_t *tdp, int num);
+static int tagadd(char *w, int h, tdesc_t *tdp);
+static char *tdefdecl(char *cp, int h, tdesc_t **rtdp);
+static char *intrinsic(char *cp, tdesc_t **rtdp);
+static char *arraydef(char *cp, tdesc_t **rtdp);
+
+int debug_parse = DEBUG_PARSE;
+
+/*PRINTFLIKE3*/
+static void
+parse_debug(int level, char *cp, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[1024];
+ char tmp[32];
+ int i;
+
+ if (level > debug_level || !debug_parse)
+ return;
+
+ if (cp != NULL) {
+ for (i = 0; i < 30; i++) {
+ if (cp[i] == '\0')
+ break;
+ if (!iscntrl(cp[i]))
+ tmp[i] = cp[i];
+ }
+ tmp[i] = '\0';
+ (void) snprintf(buf, sizeof (buf), "%s [cp='%s']\n", fmt, tmp);
+ } else {
+ strcpy(buf, fmt);
+ strcat(buf, "\n");
+ }
+
+ va_start(ap, fmt);
+ vadebug(level, buf, ap);
+ va_end(ap);
+}
+
+/* Report unexpected syntax in stabs. */
+static void
+_expected(
+ const char *who, /* what function, or part thereof, is reporting */
+ const char *what, /* what was expected */
+ const char *where, /* where we were in the line of input */
+ int line)
+{
+ fprintf(stderr, "%s, expecting \"%s\" at \"%s\"\n", who, what, where);
+ fprintf(stderr, "code line: %d, file %s\n", line,
+ (curhdr ? curhdr : "NO FILE"));
+ reset();
+}
+
+/*ARGSUSED*/
+void
+parse_init(tdata_t *td __unused)
+{
+ int i;
+
+ for (i = 0; i < BUCKETS; i++) {
+ hash_table[i] = NULL;
+ name_table[i] = NULL;
+ }
+
+ if (typedbitfldmems != NULL) {
+ list_free(typedbitfldmems, NULL, NULL);
+ typedbitfldmems = NULL;
+ }
+}
+
+void
+parse_finish(tdata_t *td)
+{
+ td->td_nextid = ++faketypenumber;
+}
+
+static tdesc_t *
+unres_new(int tid)
+{
+ tdesc_t *tdp;
+
+ tdp = xcalloc(sizeof (*tdp));
+ tdp->t_type = TYPEDEF_UNRES;
+ tdp->t_id = tid;
+
+ return (tdp);
+}
+
+static char *
+read_tid(char *cp, tdesc_t **tdpp)
+{
+ tdesc_t *tdp;
+ int tid;
+
+ cp = id(cp, &tid);
+
+ assert(tid != 0);
+
+ if (*cp == '=') {
+ if (!(cp = tdefdecl(cp + 1, tid, &tdp)))
+ return (NULL);
+ if (tdp->t_id && tdp->t_id != tid) {
+ tdesc_t *ntdp = xcalloc(sizeof (*ntdp));
+
+ ntdp->t_type = TYPEDEF;
+ ntdp->t_tdesc = tdp;
+ tdp = ntdp;
+ }
+ addhash(tdp, tid);
+ } else if ((tdp = lookup(tid)) == NULL)
+ tdp = unres_new(tid);
+
+ *tdpp = tdp;
+ return (cp);
+}
+
+static iitype_t
+parse_fun(char *cp, iidesc_t *ii)
+{
+ iitype_t iitype = 0;
+ tdesc_t *tdp;
+ tdesc_t **args = NULL;
+ int nargs = 0;
+ int va = 0;
+
+ /*
+ * name:P prototype
+ * name:F global function
+ * name:f static function
+ */
+ switch (*cp++) {
+ case 'P':
+ iitype = II_NOT; /* not interesting */
+ break;
+
+ case 'F':
+ iitype = II_GFUN;
+ break;
+
+ case 'f':
+ iitype = II_SFUN;
+ break;
+
+ default:
+ expected("parse_nfun", "[PfF]", cp - 1);
+ }
+
+ if (!(cp = read_tid(cp, &tdp)))
+ return (-1);
+
+ if (*cp)
+ args = xmalloc(sizeof (tdesc_t *) * FUNCARG_DEF);
+
+ while (*cp && *++cp) {
+ if (*cp == '0') {
+ va = 1;
+ continue;
+ }
+
+ nargs++;
+ if (nargs > FUNCARG_DEF)
+ args = xrealloc(args, sizeof (tdesc_t *) * nargs);
+ if (!(cp = read_tid(cp, &args[nargs - 1]))) {
+ if (tdp->t_type == TYPEDEF_UNRES)
+ free(tdp);
+ free(args);
+ return (-1);
+ }
+ }
+
+ ii->ii_type = iitype;
+ ii->ii_dtype = tdp;
+ ii->ii_nargs = nargs;
+ ii->ii_args = args;
+ ii->ii_vargs = va;
+
+ return (iitype);
+}
+
+static iitype_t
+parse_sym(char *cp, iidesc_t *ii)
+{
+ tdesc_t *tdp;
+ iitype_t iitype = 0;
+
+ /*
+ * name:G global variable
+ * name:S static variable
+ */
+ switch (*cp++) {
+ case 'G':
+ iitype = II_GVAR;
+ break;
+ case 'S':
+ iitype = II_SVAR;
+ break;
+ case 'p':
+ iitype = II_PSYM;
+ break;
+ case '(':
+ cp--;
+ /*FALLTHROUGH*/
+ case 'r':
+ case 'V':
+ iitype = II_NOT; /* not interesting */
+ break;
+ default:
+ expected("parse_sym", "[GprSV(]", cp - 1);
+ }
+
+ if (!(cp = read_tid(cp, &tdp)))
+ return (-1);
+
+ ii->ii_type = iitype;
+ ii->ii_dtype = tdp;
+
+ return (iitype);
+}
+
+static iitype_t
+parse_type(char *cp, iidesc_t *ii)
+{
+ tdesc_t *tdp, *ntdp;
+ int tid;
+
+ if (*cp++ != 't')
+ expected("parse_type", "t (type)", cp - 1);
+
+ cp = id(cp, &tid);
+ if ((tdp = lookup(tid)) == NULL) {
+ if (*cp++ != '=')
+ expected("parse_type", "= (definition)", cp - 1);
+
+ (void) tdefdecl(cp, tid, &tdp);
+
+ if (tdp->t_id == tid) {
+ assert(tdp->t_type != TYPEDEF);
+ assert(!lookup(tdp->t_id));
+
+ if (!streq(tdp->t_name, ii->ii_name)) {
+ ntdp = xcalloc(sizeof (*ntdp));
+ ntdp->t_name = xstrdup(ii->ii_name);
+ ntdp->t_type = TYPEDEF;
+ ntdp->t_tdesc = tdp;
+ tdp->t_id = faketypenumber++;
+ tdp = ntdp;
+ }
+ } else if (tdp->t_id == 0) {
+ assert(tdp->t_type == FORWARD ||
+ tdp->t_type == INTRINSIC);
+
+ if (tdp->t_name && !streq(tdp->t_name, ii->ii_name)) {
+ ntdp = xcalloc(sizeof (*ntdp));
+ ntdp->t_name = xstrdup(ii->ii_name);
+ ntdp->t_type = TYPEDEF;
+ ntdp->t_tdesc = tdp;
+ tdp->t_id = faketypenumber++;
+ tdp = ntdp;
+ }
+ } else if (tdp->t_id != tid) {
+ ntdp = xcalloc(sizeof (*ntdp));
+ ntdp->t_name = xstrdup(ii->ii_name);
+ ntdp->t_type = TYPEDEF;
+ ntdp->t_tdesc = tdp;
+ tdp = ntdp;
+ }
+
+ if (tagadd(ii->ii_name, tid, tdp) < 0)
+ return (-1);
+ }
+
+ ii->ii_type = II_TYPE;
+ ii->ii_dtype = tdp;
+ return (II_TYPE);
+}
+
+static iitype_t
+parse_sou(char *cp, iidesc_t *idp)
+{
+ tdesc_t *rtdp;
+ int tid;
+
+ if (*cp++ != 'T')
+ expected("parse_sou", "T (sou)", cp - 1);
+
+ cp = id(cp, &tid);
+ if (*cp++ != '=')
+ expected("parse_sou", "= (definition)", cp - 1);
+
+ parse_debug(1, NULL, "parse_sou: declaring '%s'", idp->ii_name ?
+ idp->ii_name : "(anon)");
+ if ((rtdp = lookup(tid)) != NULL) {
+ if (idp->ii_name != NULL) {
+ if (rtdp->t_name != NULL &&
+ strcmp(rtdp->t_name, idp->ii_name) != 0) {
+ tdesc_t *tdp;
+
+ tdp = xcalloc(sizeof (*tdp));
+ tdp->t_name = xstrdup(idp->ii_name);
+ tdp->t_type = TYPEDEF;
+ tdp->t_tdesc = rtdp;
+ addhash(tdp, tid); /* for *(x,y) types */
+ parse_debug(3, NULL, " %s defined as %s(%d)",
+ idp->ii_name, tdesc_name(rtdp), tid);
+ } else if (rtdp->t_name == NULL) {
+ rtdp->t_name = xstrdup(idp->ii_name);
+ addhash(rtdp, tid);
+ }
+ }
+ } else {
+ rtdp = xcalloc(sizeof (*rtdp));
+ rtdp->t_name = idp->ii_name ? xstrdup(idp->ii_name) : NULL;
+ addhash(rtdp, tid);
+ }
+
+ switch (*cp++) {
+ case 's':
+ (void) soudef(cp, STRUCT, &rtdp);
+ break;
+ case 'u':
+ (void) soudef(cp, UNION, &rtdp);
+ break;
+ case 'e':
+ enumdef(cp, &rtdp);
+ break;
+ default:
+ expected("parse_sou", "<tag type s/u/e>", cp - 1);
+ break;
+ }
+
+ idp->ii_type = II_SOU;
+ idp->ii_dtype = rtdp;
+ return (II_SOU);
+}
+
+int
+parse_stab(stab_t *stab, char *cp, iidesc_t **iidescp)
+{
+ iidesc_t *ii = NULL;
+ iitype_t (*parse)(char *, iidesc_t *);
+ int rc;
+
+ /*
+ * set up for reset()
+ */
+ if (setjmp(resetbuf))
+ return (-1);
+
+ cp = whitesp(cp);
+ ii = iidesc_new(NULL);
+ cp = name(cp, &ii->ii_name);
+
+ switch (stab->n_type) {
+ case N_FUN:
+ parse = parse_fun;
+ break;
+
+ case N_LSYM:
+ if (*cp == 't')
+ parse = parse_type;
+ else if (*cp == 'T')
+ parse = parse_sou;
+ else
+ parse = parse_sym;
+ break;
+
+ case N_GSYM:
+ case N_LCSYM:
+ case N_PSYM:
+ case N_ROSYM:
+ case N_RSYM:
+ case N_STSYM:
+ parse = parse_sym;
+ break;
+ default:
+ parse_debug(1, cp, "Unknown stab type %#x", stab->n_type);
+ bzero(&resetbuf, sizeof (resetbuf));
+ return (-1);
+ }
+
+ rc = parse(cp, ii);
+ bzero(&resetbuf, sizeof (resetbuf));
+
+ if (rc < 0 || ii->ii_type == II_NOT) {
+ iidesc_free(ii, NULL);
+ return (rc);
+ }
+
+ *iidescp = ii;
+
+ return (1);
+}
+
+/*
+ * Check if we have this node in the hash table already
+ */
+tdesc_t *
+lookup(int h)
+{
+ int bucket = HASH(h);
+ tdesc_t *tdp = hash_table[bucket];
+
+ while (tdp != NULL) {
+ if (tdp->t_id == h)
+ return (tdp);
+ tdp = tdp->t_hash;
+ }
+ return (NULL);
+}
+
+static char *
+whitesp(char *cp)
+{
+ char c;
+
+ for (c = *cp++; isspace(c); c = *cp++)
+ ;
+ --cp;
+ return (cp);
+}
+
+static char *
+name(char *cp, char **w)
+{
+ char *new, *orig, c;
+ int len;
+
+ orig = cp;
+ c = *cp++;
+ if (c == ':')
+ *w = NULL;
+ else if (isalpha(c) || strchr("_.$#", c)) {
+ for (c = *cp++; isalnum(c) || strchr(" _.$#", c); c = *cp++)
+ ;
+ if (c != ':')
+ reset();
+ len = cp - orig;
+ new = xmalloc(len);
+ while (orig < cp - 1)
+ *new++ = *orig++;
+ *new = '\0';
+ *w = new - (len - 1);
+ } else
+ reset();
+
+ return (cp);
+}
+
+static char *
+number(char *cp, int *n)
+{
+ char *next;
+
+ *n = (int)strtol(cp, &next, 10);
+ if (next == cp)
+ expected("number", "<number>", cp);
+ return (next);
+}
+
+static char *
+id(char *cp, int *h)
+{
+ int n1, n2;
+
+ if (*cp == '(') { /* SunPro style */
+ cp++;
+ cp = number(cp, &n1);
+ if (*cp++ != ',')
+ expected("id", ",", cp - 1);
+ cp = number(cp, &n2);
+ if (*cp++ != ')')
+ expected("id", ")", cp - 1);
+ *h = MAKETYPEID(n1, n2);
+ } else if (isdigit(*cp)) { /* gcc style */
+ cp = number(cp, &n1);
+ *h = n1;
+ } else {
+ expected("id", "(/0-9", cp);
+ }
+ return (cp);
+}
+
+static int
+tagadd(char *w, int h, tdesc_t *tdp)
+{
+ tdesc_t *otdp;
+
+ tdp->t_name = w;
+ if (!(otdp = lookup(h)))
+ addhash(tdp, h);
+ else if (otdp != tdp) {
+ warning("duplicate entry\n");
+ warning(" old: %s %d (%d,%d)\n", tdesc_name(otdp),
+ otdp->t_type, TYPEFILE(otdp->t_id), TYPENUM(otdp->t_id));
+ warning(" new: %s %d (%d,%d)\n", tdesc_name(tdp),
+ tdp->t_type, TYPEFILE(tdp->t_id), TYPENUM(tdp->t_id));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static char *
+tdefdecl(char *cp, int h, tdesc_t **rtdp)
+{
+ tdesc_t *ntdp;
+ char *w;
+ int c, h2;
+ char type;
+
+ parse_debug(3, cp, "tdefdecl h=%d", h);
+
+ /* Type codes */
+ switch (type = *cp) {
+ case 'b': /* integer */
+ case 'R': /* fp */
+ cp = intrinsic(cp, rtdp);
+ break;
+ case '(': /* equiv to another type */
+ cp = id(cp, &h2);
+ ntdp = lookup(h2);
+
+ if (ntdp != NULL && *cp == '=') {
+ if (ntdp->t_type == FORWARD && *(cp + 1) == 'x') {
+ /*
+ * The 6.2 compiler, and possibly others, will
+ * sometimes emit the same stab for a forward
+ * declaration twice. That is, "(1,2)=xsfoo:"
+ * will sometimes show up in two different
+ * places. This is, of course, quite fun. We
+ * want CTF to work in spite of the compiler,
+ * so we'll let this one through.
+ */
+ char *c2 = cp + 2;
+ char *nm;
+
+ if (!strchr("sue", *c2++)) {
+ expected("tdefdecl/x-redefine", "[sue]",
+ c2 - 1);
+ }
+
+ c2 = name(c2, &nm);
+ if (strcmp(nm, ntdp->t_name) != 0) {
+ terminate("Stabs error: Attempt to "
+ "redefine type (%d,%d) as "
+ "something else: %s\n",
+ TYPEFILE(h2), TYPENUM(h2),
+ c2 - 1);
+ }
+ free(nm);
+
+ h2 = faketypenumber++;
+ ntdp = NULL;
+ } else {
+ terminate("Stabs error: Attempting to "
+ "redefine type (%d,%d)\n", TYPEFILE(h2),
+ TYPENUM(h2));
+ }
+ }
+
+ if (ntdp == NULL) { /* if that type isn't defined yet */
+ if (*cp != '=') {
+ /* record it as unresolved */
+ parse_debug(3, NULL, "tdefdecl unres type %d",
+ h2);
+ *rtdp = calloc(sizeof (**rtdp), 1);
+ (*rtdp)->t_type = TYPEDEF_UNRES;
+ (*rtdp)->t_id = h2;
+ break;
+ } else
+ cp++;
+
+ /* define a new type */
+ cp = tdefdecl(cp, h2, rtdp);
+ if ((*rtdp)->t_id && (*rtdp)->t_id != h2) {
+ ntdp = calloc(sizeof (*ntdp), 1);
+ ntdp->t_type = TYPEDEF;
+ ntdp->t_tdesc = *rtdp;
+ *rtdp = ntdp;
+ }
+
+ addhash(*rtdp, h2);
+
+ } else { /* that type is already defined */
+ if (ntdp->t_type != TYPEDEF || ntdp->t_name != NULL) {
+ *rtdp = ntdp;
+ } else {
+ parse_debug(3, NULL,
+ "No duplicate typedef anon for ref");
+ *rtdp = ntdp;
+ }
+ }
+ break;
+ case '*':
+ ntdp = NULL;
+ cp = tdefdecl(cp + 1, h, &ntdp);
+ if (ntdp == NULL)
+ expected("tdefdecl/*", "id", cp);
+
+ if (!ntdp->t_id)
+ ntdp->t_id = faketypenumber++;
+
+ *rtdp = xcalloc(sizeof (**rtdp));
+ (*rtdp)->t_type = POINTER;
+ (*rtdp)->t_size = 0;
+ (*rtdp)->t_id = h;
+ (*rtdp)->t_tdesc = ntdp;
+ break;
+ case 'f':
+ cp = tdefdecl(cp + 1, h, &ntdp);
+ *rtdp = xcalloc(sizeof (**rtdp));
+ (*rtdp)->t_type = FUNCTION;
+ (*rtdp)->t_size = 0;
+ (*rtdp)->t_id = h;
+ (*rtdp)->t_fndef = xcalloc(sizeof (fndef_t));
+ /*
+ * The 6.1 compiler will sometimes generate incorrect stabs for
+ * function pointers (it'll get the return type wrong). This
+ * causes merges to fail. We therefore treat function pointers
+ * as if they all point to functions that return int. When
+ * 4432549 is fixed, the lookupname() call below should be
+ * replaced with `ntdp'.
+ */
+ (*rtdp)->t_fndef->fn_ret = lookupname("int");
+ break;
+ case 'a':
+ case 'z':
+ cp++;
+ if (*cp++ != 'r')
+ expected("tdefdecl/[az]", "r", cp - 1);
+ *rtdp = xcalloc(sizeof (**rtdp));
+ (*rtdp)->t_type = ARRAY;
+ (*rtdp)->t_id = h;
+ cp = arraydef(cp, rtdp);
+ break;
+ case 'x':
+ c = *++cp;
+ if (c != 's' && c != 'u' && c != 'e')
+ expected("tdefdecl/x", "[sue]", cp - 1);
+ cp = name(cp + 1, &w);
+
+ ntdp = xcalloc(sizeof (*ntdp));
+ ntdp->t_type = FORWARD;
+ ntdp->t_name = w;
+ /*
+ * We explicitly don't set t_id here - the caller will do it.
+ * The caller may want to use a real type ID, or they may
+ * choose to make one up.
+ */
+
+ *rtdp = ntdp;
+ break;
+
+ case 'B': /* volatile */
+ cp = tdefdecl(cp + 1, h, &ntdp);
+
+ if (!ntdp->t_id)
+ ntdp->t_id = faketypenumber++;
+
+ *rtdp = xcalloc(sizeof (**rtdp));
+ (*rtdp)->t_type = VOLATILE;
+ (*rtdp)->t_size = 0;
+ (*rtdp)->t_tdesc = ntdp;
+ (*rtdp)->t_id = h;
+ break;
+
+ case 'k': /* const */
+ cp = tdefdecl(cp + 1, h, &ntdp);
+
+ if (!ntdp->t_id)
+ ntdp->t_id = faketypenumber++;
+
+ *rtdp = xcalloc(sizeof (**rtdp));
+ (*rtdp)->t_type = CONST;
+ (*rtdp)->t_size = 0;
+ (*rtdp)->t_tdesc = ntdp;
+ (*rtdp)->t_id = h;
+ break;
+
+ case 'K': /* restricted */
+ cp = tdefdecl(cp + 1, h, &ntdp);
+
+ if (!ntdp->t_id)
+ ntdp->t_id = faketypenumber++;
+
+ *rtdp = xcalloc(sizeof (**rtdp));
+ (*rtdp)->t_type = RESTRICT;
+ (*rtdp)->t_size = 0;
+ (*rtdp)->t_tdesc = ntdp;
+ (*rtdp)->t_id = h;
+ break;
+
+ case 'u':
+ case 's':
+ cp++;
+
+ *rtdp = xcalloc(sizeof (**rtdp));
+ (*rtdp)->t_name = NULL;
+ cp = soudef(cp, (type == 'u') ? UNION : STRUCT, rtdp);
+ break;
+ default:
+ expected("tdefdecl", "<type code>", cp);
+ }
+ return (cp);
+}
+
+static char *
+intrinsic(char *cp, tdesc_t **rtdp)
+{
+ intr_t *intr = xcalloc(sizeof (intr_t));
+ tdesc_t *tdp;
+ int width, fmt, i;
+
+ switch (*cp++) {
+ case 'b':
+ intr->intr_type = INTR_INT;
+ if (*cp == 's')
+ intr->intr_signed = 1;
+ else if (*cp != 'u')
+ expected("intrinsic/b", "[su]", cp);
+ cp++;
+
+ if (strchr("cbv", *cp))
+ intr->intr_iformat = *cp++;
+
+ cp = number(cp, &width);
+ if (*cp++ != ';')
+ expected("intrinsic/b", "; (post-width)", cp - 1);
+
+ cp = number(cp, &intr->intr_offset);
+ if (*cp++ != ';')
+ expected("intrinsic/b", "; (post-offset)", cp - 1);
+
+ cp = number(cp, &intr->intr_nbits);
+ break;
+
+ case 'R':
+ intr->intr_type = INTR_REAL;
+ for (fmt = 0, i = 0; isdigit(*(cp + i)); i++)
+ fmt = fmt * 10 + (*(cp + i) - '0');
+
+ if (fmt < 1 || fmt > CTF_FP_MAX)
+ expected("intrinsic/R", "number <= CTF_FP_MAX", cp);
+
+ intr->intr_fformat = fmt;
+ cp += i;
+
+ if (*cp++ != ';')
+ expected("intrinsic/R", ";", cp - 1);
+ cp = number(cp, &width);
+
+ intr->intr_nbits = width * 8;
+ break;
+ }
+
+ tdp = xcalloc(sizeof (*tdp));
+ tdp->t_type = INTRINSIC;
+ tdp->t_size = width;
+ tdp->t_name = NULL;
+ tdp->t_intr = intr;
+ parse_debug(3, NULL, "intrinsic: size=%d", width);
+ *rtdp = tdp;
+
+ return (cp);
+}
+
+static tdesc_t *
+bitintrinsic(tdesc_t *template, int nbits)
+{
+ tdesc_t *newtdp = xcalloc(sizeof (tdesc_t));
+
+ newtdp->t_name = xstrdup(template->t_name);
+ newtdp->t_id = faketypenumber++;
+ newtdp->t_type = INTRINSIC;
+ newtdp->t_size = template->t_size;
+ newtdp->t_intr = xmalloc(sizeof (intr_t));
+ bcopy(template->t_intr, newtdp->t_intr, sizeof (intr_t));
+ newtdp->t_intr->intr_nbits = nbits;
+
+ return (newtdp);
+}
+
+static char *
+offsize(char *cp, mlist_t *mlp)
+{
+ int offset, size;
+
+ if (*cp == ',')
+ cp++;
+ cp = number(cp, &offset);
+ if (*cp++ != ',')
+ expected("offsize/2", ",", cp - 1);
+ cp = number(cp, &size);
+ if (*cp++ != ';')
+ expected("offsize/3", ";", cp - 1);
+ mlp->ml_offset = offset;
+ mlp->ml_size = size;
+ return (cp);
+}
+
+static tdesc_t *
+find_intrinsic(tdesc_t *tdp)
+{
+ for (;;) {
+ switch (tdp->t_type) {
+ case TYPEDEF:
+ case VOLATILE:
+ case CONST:
+ case RESTRICT:
+ tdp = tdp->t_tdesc;
+ break;
+
+ default:
+ return (tdp);
+ }
+ }
+}
+
+static char *
+soudef(char *cp, stabtype_t type, tdesc_t **rtdp)
+{
+ mlist_t *mlp, **prev;
+ char *w;
+ int h;
+ int size;
+ tdesc_t *tdp, *itdp;
+
+ cp = number(cp, &size);
+ (*rtdp)->t_size = size;
+ (*rtdp)->t_type = type; /* s or u */
+
+ /*
+ * An '@' here indicates a bitmask follows. This is so the
+ * compiler can pass information to debuggers about how structures
+ * are passed in the v9 world. We don't need this information
+ * so we skip over it.
+ */
+ if (cp[0] == '@') {
+ cp += 3;
+ }
+
+ parse_debug(3, cp, "soudef: %s size=%d", tdesc_name(*rtdp),
+ (*rtdp)->t_size);
+
+ prev = &((*rtdp)->t_members);
+ /* now fill up the fields */
+ while ((*cp != '\0') && (*cp != ';')) { /* signifies end of fields */
+ mlp = xcalloc(sizeof (*mlp));
+ *prev = mlp;
+ cp = name(cp, &w);
+ mlp->ml_name = w;
+ cp = id(cp, &h);
+ /*
+ * find the tdesc struct in the hash table for this type
+ * and stick a ptr in here
+ */
+ tdp = lookup(h);
+ if (tdp == NULL) { /* not in hash list */
+ parse_debug(3, NULL, " defines %s (%d)", w, h);
+ if (*cp++ != '=') {
+ tdp = unres_new(h);
+ parse_debug(3, NULL,
+ " refers to %s (unresolved %d)",
+ (w ? w : "anon"), h);
+ } else {
+ cp = tdefdecl(cp, h, &tdp);
+
+ if (tdp->t_id && tdp->t_id != h) {
+ tdesc_t *ntdp = xcalloc(sizeof (*ntdp));
+
+ ntdp->t_type = TYPEDEF;
+ ntdp->t_tdesc = tdp;
+ tdp = ntdp;
+ }
+
+ addhash(tdp, h);
+ parse_debug(4, cp,
+ " soudef now looking at ");
+ cp++;
+ }
+ } else {
+ parse_debug(3, NULL, " refers to %s (%d, %s)",
+ w ? w : "anon", h, tdesc_name(tdp));
+ }
+
+ cp = offsize(cp, mlp);
+
+ itdp = find_intrinsic(tdp);
+ if (itdp->t_type == INTRINSIC) {
+ if (mlp->ml_size != itdp->t_intr->intr_nbits) {
+ parse_debug(4, cp, "making %d bit intrinsic "
+ "from %s", mlp->ml_size, tdesc_name(itdp));
+ mlp->ml_type = bitintrinsic(itdp, mlp->ml_size);
+ } else
+ mlp->ml_type = tdp;
+ } else if (itdp->t_type == TYPEDEF_UNRES) {
+ list_add(&typedbitfldmems, mlp);
+ mlp->ml_type = tdp;
+ } else {
+ mlp->ml_type = tdp;
+ }
+
+ /* cp is now pointing to next field */
+ prev = &mlp->ml_next;
+ }
+ return (cp);
+}
+
+static char *
+arraydef(char *cp, tdesc_t **rtdp)
+{
+ int start, end, h;
+
+ cp = id(cp, &h);
+ if (*cp++ != ';')
+ expected("arraydef/1", ";", cp - 1);
+
+ (*rtdp)->t_ardef = xcalloc(sizeof (ardef_t));
+ (*rtdp)->t_ardef->ad_idxtype = lookup(h);
+
+ cp = number(cp, &start); /* lower */
+ if (*cp++ != ';')
+ expected("arraydef/2", ";", cp - 1);
+
+ if (*cp == 'S') {
+ /*
+ * variable length array - treat as null dimensioned
+ *
+ * For VLA variables on sparc, SS12 generated stab entry
+ * looks as follows:
+ * .stabs "buf:(0,28)=zr(0,4);0;S-12;(0,1)", 0x80, 0, 0, -16
+ * Whereas SS12u1 generated stab entry looks like this:
+ * .stabs "buf:(0,28)=zr(0,4);0;S0;(0,1)", 0x80, 0, 0, 0
+ * On x86, both versions generate the first type of entry.
+ * We should be able to parse both.
+ */
+ cp++;
+ if (*cp == '-')
+ cp++;
+ cp = number(cp, &end);
+ end = start;
+ } else {
+ /*
+ * normal fixed-dimension array
+ * Stab entry for this looks as follows :
+ * .stabs "x:(0,28)=ar(0,4);0;9;(0,3)", 0x80, 0, 40, 0
+ */
+ cp = number(cp, &end); /* upper */
+ }
+
+ if (*cp++ != ';')
+ expected("arraydef/3", ";", cp - 1);
+ (*rtdp)->t_ardef->ad_nelems = end - start + 1;
+ cp = tdefdecl(cp, h, &((*rtdp)->t_ardef->ad_contents));
+
+ parse_debug(3, cp, "defined array idx type %d %d-%d next ",
+ h, start, end);
+
+ return (cp);
+}
+
+static void
+enumdef(char *cp, tdesc_t **rtdp)
+{
+ elist_t *elp, **prev;
+ char *w;
+
+ (*rtdp)->t_type = ENUM;
+ (*rtdp)->t_emem = NULL;
+
+ prev = &((*rtdp)->t_emem);
+ while (*cp != ';') {
+ elp = xcalloc(sizeof (*elp));
+ elp->el_next = NULL;
+ *prev = elp;
+ cp = name(cp, &w);
+ elp->el_name = w;
+ cp = number(cp, &elp->el_number);
+ parse_debug(3, NULL, "enum %s: %s=%d", tdesc_name(*rtdp),
+ elp->el_name, elp->el_number);
+ prev = &elp->el_next;
+ if (*cp++ != ',')
+ expected("enumdef", ",", cp - 1);
+ }
+}
+
+static tdesc_t *
+lookup_name(tdesc_t **hash, const char *name1)
+{
+ int bucket = compute_sum(name1);
+ tdesc_t *tdp, *ttdp = NULL;
+
+ for (tdp = hash[bucket]; tdp != NULL; tdp = tdp->t_next) {
+ if (tdp->t_name != NULL && strcmp(tdp->t_name, name1) == 0) {
+ if (tdp->t_type == STRUCT || tdp->t_type == UNION ||
+ tdp->t_type == ENUM || tdp->t_type == INTRINSIC)
+ return (tdp);
+ if (tdp->t_type == TYPEDEF)
+ ttdp = tdp;
+ }
+ }
+ return (ttdp);
+}
+
+tdesc_t *
+lookupname(const char *name1)
+{
+ return (lookup_name(name_table, name1));
+}
+
+/*
+ * Add a node to the hash queues.
+ */
+static void
+addhash(tdesc_t *tdp, int num)
+{
+ int hash = HASH(num);
+ tdesc_t *ttdp;
+ char added_num = 0, added_name = 0;
+
+ /*
+ * If it already exists in the hash table don't add it again
+ * (but still check to see if the name should be hashed).
+ */
+ ttdp = lookup(num);
+
+ if (ttdp == NULL) {
+ tdp->t_id = num;
+ tdp->t_hash = hash_table[hash];
+ hash_table[hash] = tdp;
+ added_num = 1;
+ }
+
+ if (tdp->t_name != NULL) {
+ ttdp = lookupname(tdp->t_name);
+ if (ttdp == NULL) {
+ hash = compute_sum(tdp->t_name);
+ tdp->t_next = name_table[hash];
+ name_table[hash] = tdp;
+ added_name = 1;
+ }
+ }
+ if (!added_num && !added_name) {
+ terminate("stabs: broken hash\n");
+ }
+}
+
+static int
+compute_sum(const char *w)
+{
+ char c;
+ int sum;
+
+ for (sum = 0; (c = *w) != '\0'; sum += c, w++)
+ ;
+ return (HASH(sum));
+}
+
+static void
+reset(void)
+{
+ longjmp(resetbuf, 1);
+}
+
+void
+check_hash(void)
+{
+ tdesc_t *tdp;
+ int i;
+
+ printf("checking hash\n");
+ for (i = 0; i < BUCKETS; i++) {
+ if (hash_table[i]) {
+ for (tdp = hash_table[i]->t_hash;
+ tdp && tdp != hash_table[i];
+ tdp = tdp->t_hash)
+ continue;
+ if (tdp) {
+ terminate("cycle in hash bucket %d\n", i);
+ return;
+ }
+ }
+
+ if (name_table[i]) {
+ for (tdp = name_table[i]->t_next;
+ tdp && tdp != name_table[i];
+ tdp = tdp->t_next)
+ continue;
+ if (tdp) {
+ terminate("cycle in name bucket %d\n", i);
+ return;
+ }
+ }
+ }
+ printf("done\n");
+}
+
+/*ARGSUSED1*/
+static int
+resolve_typed_bitfields_cb(void *arg, void *private __unused)
+{
+ mlist_t *ml = arg;
+ tdesc_t *tdp = ml->ml_type;
+
+ debug(3, "Resolving typed bitfields (member %s)\n",
+ (ml->ml_name ? ml->ml_name : "(anon)"));
+
+ while (tdp) {
+ switch (tdp->t_type) {
+ case INTRINSIC:
+ if (ml->ml_size != tdp->t_intr->intr_nbits) {
+ debug(3, "making %d bit intrinsic from %s",
+ ml->ml_size, tdesc_name(tdp));
+ ml->ml_type = bitintrinsic(tdp, ml->ml_size);
+ } else {
+ debug(3, "using existing %d bit %s intrinsic",
+ ml->ml_size, tdesc_name(tdp));
+ ml->ml_type = tdp;
+ }
+ return (1);
+
+ case POINTER:
+ case TYPEDEF:
+ case VOLATILE:
+ case CONST:
+ case RESTRICT:
+ tdp = tdp->t_tdesc;
+ break;
+
+ default:
+ return (1);
+ }
+ }
+
+ terminate("type chain for bitfield member %s has a NULL", ml->ml_name);
+ /*NOTREACHED*/
+ return (0);
+}
+
+void
+resolve_typed_bitfields(void)
+{
+ (void) list_iter(typedbitfldmems,
+ resolve_typed_bitfields_cb, NULL);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/stabs.c b/cddl/contrib/opensolaris/tools/ctf/cvt/stabs.c
new file mode 100644
index 000000000000..c0c68b53e030
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/stabs.c
@@ -0,0 +1,381 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines used to read stabs data from a file, and to build a tdata structure
+ * based on the interesting parts of that data.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <libgen.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include "ctftools.h"
+#include "list.h"
+#include "stack.h"
+#include "memory.h"
+#include "traverse.h"
+
+char *curhdr;
+
+/*
+ * The stabs generator will sometimes reference types before they've been
+ * defined. If this is the case, a TYPEDEF_UNRES tdesc will be generated.
+ * Note that this is different from a forward declaration, in which the
+ * stab is defined, but is defined as something that doesn't exist yet.
+ * When we have read all of the stabs from the file, we can go back and
+ * fix up all of the unresolved types. We should be able to fix all of them.
+ */
+/*ARGSUSED2*/
+static int
+resolve_tou_node(tdesc_t *node, tdesc_t **nodep, void *private __unused)
+{
+ tdesc_t *new;
+
+ debug(3, "Trying to resolve %s (%d)\n", tdesc_name(node), node->t_id);
+ new = lookup(node->t_id);
+
+ if (new == NULL) {
+ terminate("Couldn't resolve type %d\n", node->t_id);
+ }
+
+ debug(3, " Resolving to %d\n", new->t_id);
+
+ *nodep = new;
+
+ return (1);
+}
+
+/*ARGSUSED*/
+static int
+resolve_fwd_node(tdesc_t *node, tdesc_t **nodep, void *private __unused)
+{
+ tdesc_t *new = lookupname(node->t_name);
+
+ debug(3, "Trying to unforward %s (%d)\n", tdesc_name(node), node->t_id);
+
+ if (!new || (new->t_type != STRUCT && new->t_type != UNION))
+ return (0);
+
+ debug(3, " Unforwarded to %d\n", new->t_id);
+
+ *nodep = new;
+
+ return (1);
+}
+
+static tdtrav_cb_f resolve_cbs[] = {
+ NULL,
+ NULL, /* intrinsic */
+ NULL, /* pointer */
+ NULL, /* array */
+ NULL, /* function */
+ NULL, /* struct */
+ NULL, /* union */
+ NULL, /* enum */
+ resolve_fwd_node, /* forward */
+ NULL, /* typedef */
+ resolve_tou_node, /* typedef unres */
+ NULL, /* volatile */
+ NULL, /* const */
+ NULL, /* restrict */
+};
+
+static void
+resolve_nodes(tdata_t *td)
+{
+ debug(2, "Resolving unresolved stabs\n");
+
+ (void) iitraverse_hash(td->td_iihash, &td->td_curvgen, resolve_cbs,
+ NULL, NULL, td);
+}
+
+static char *
+concat(char *s1, char *s2, int s2strip)
+{
+ int savelen = strlen(s2) - s2strip;
+ int newlen = (s1 ? strlen(s1) : 0) + savelen + 1;
+ char *out;
+
+ out = xrealloc(s1, newlen);
+ if (s1)
+ strncpy(out + strlen(out), s2, savelen);
+ else
+ strncpy(out, s2, savelen);
+
+ out[newlen - 1] = '\0';
+
+ return (out);
+}
+
+/*
+ * N_FUN stabs come with their arguments in promoted form. In order to get the
+ * actual arguments, we need to wait for the N_PSYM stabs that will come towards
+ * the end of the function. These routines free the arguments (fnarg_free) we
+ * got from the N_FUN stab and add (fnarg_add) the ones from the N_PSYM stabs.
+ */
+static void
+fnarg_add(iidesc_t *curfun, iidesc_t *arg)
+{
+ curfun->ii_nargs++;
+
+ if (curfun->ii_nargs == 1)
+ curfun->ii_args = xmalloc(sizeof (tdesc_t *) * FUNCARG_DEF);
+ else if (curfun->ii_nargs > FUNCARG_DEF) {
+ curfun->ii_args = xrealloc(curfun->ii_args,
+ sizeof (tdesc_t *) * curfun->ii_nargs);
+ }
+
+ curfun->ii_args[curfun->ii_nargs - 1] = arg->ii_dtype;
+ arg->ii_dtype = NULL;
+}
+
+static void
+fnarg_free(iidesc_t *ii)
+{
+ ii->ii_nargs = 0;
+ free(ii->ii_args);
+ ii->ii_args = NULL;
+}
+
+/*
+ * Read the stabs from the stab ELF section, and turn them into a tdesc tree,
+ * assembled under an iidesc list.
+ */
+int
+stabs_read(tdata_t *td, Elf *elf, char *file)
+{
+ Elf_Scn *scn;
+ Elf_Data *data;
+ stab_t *stab;
+ stk_t *file_stack;
+ iidesc_t *iidescp;
+ iidesc_t *curfun = NULL;
+ char curpath[MAXPATHLEN];
+ char *curfile = NULL;
+ char *str;
+ char *fstr = NULL, *ofstr = NULL;
+ int stabidx, stabstridx;
+ int nstabs, rc, i;
+ int scope = 0;
+
+ if (!((stabidx = findelfsecidx(elf, file, ".stab.excl")) >= 0 &&
+ (stabstridx = findelfsecidx(elf, file, ".stab.exclstr")) >= 0) &&
+ !((stabidx = findelfsecidx(elf, file, ".stab")) >= 0 &&
+ (stabstridx = findelfsecidx(elf, file, ".stabstr")) >= 0)) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ file_stack = stack_new(free);
+
+ stack_push(file_stack, file);
+ curhdr = file;
+
+ debug(3, "Found stabs in %d, strings in %d\n", stabidx, stabstridx);
+
+ scn = elf_getscn(elf, stabidx);
+ data = elf_rawdata(scn, NULL);
+ nstabs = data->d_size / sizeof (stab_t);
+
+ parse_init(td);
+ for (i = 0; i < nstabs; i++) {
+ stab = &((stab_t *)data->d_buf)[i];
+
+ /* We don't want any local definitions */
+ if (stab->n_type == N_LBRAC) {
+ scope++;
+ debug(3, "stab %d: opening scope (%d)\n", i + 1, scope);
+ continue;
+ } else if (stab->n_type == N_RBRAC) {
+ scope--;
+ debug(3, "stab %d: closing scope (%d)\n", i + 1, scope);
+ continue;
+ } else if (stab->n_type == N_EINCL) {
+ /*
+ * There's a bug in the 5.2 (Taz) compilers that causes
+ * them to emit an extra N_EINCL if there's no actual
+ * text in the file being compiled. To work around this
+ * bug, we explicitly check to make sure we're not
+ * trying to pop a stack that only has the outer scope
+ * on it.
+ */
+ if (stack_level(file_stack) != 1) {
+ str = (char *)stack_pop(file_stack);
+ free(str);
+ curhdr = (char *)stack_peek(file_stack);
+ }
+ }
+
+ /* We only care about a subset of the stabs */
+ if (!(stab->n_type == N_FUN || stab->n_type == N_GSYM ||
+ stab->n_type == N_LCSYM || stab->n_type == N_LSYM ||
+ stab->n_type == N_PSYM || stab->n_type == N_ROSYM ||
+ stab->n_type == N_RSYM ||
+ stab->n_type == N_STSYM || stab->n_type == N_BINCL ||
+ stab->n_type == N_SO || stab->n_type == N_OPT))
+ continue;
+
+ if ((str = elf_strptr(elf, stabstridx,
+ (size_t)stab->n_strx)) == NULL) {
+ terminate("%s: Can't find string at %u for stab %d\n",
+ file, stab->n_strx, i);
+ }
+
+ if (stab->n_type == N_BINCL) {
+ curhdr = xstrdup(str);
+ stack_push(file_stack, curhdr);
+ continue;
+ } else if (stab->n_type == N_SO) {
+ if (str[strlen(str) - 1] != '/') {
+ strcpy(curpath, str);
+ curfile = basename(curpath);
+ }
+ continue;
+ } else if (stab->n_type == N_OPT) {
+ if (strcmp(str, "gcc2_compiled.") == 0) {
+ terminate("%s: GCC-generated stabs are "
+ "unsupported. Use DWARF instead.\n", file);
+ }
+ continue;
+ }
+
+ if (str[strlen(str) - 1] == '\\') {
+ int offset = 1;
+ /*
+ * There's a bug in the compilers that causes them to
+ * generate \ for continuations with just -g (this is
+ * ok), and \\ for continuations with -g -O (this is
+ * broken). This bug is "fixed" in the 6.2 compilers
+ * via the elimination of continuation stabs.
+ */
+ if (str[strlen(str) - 2] == '\\')
+ offset = 2;
+ fstr = concat(fstr, str, offset);
+ continue;
+ } else
+ fstr = concat(fstr, str, 0);
+
+ debug(3, "%4d: .stabs \"%s\", %#x, %d, %hd, %d (from %s)\n", i,
+ fstr, stab->n_type, 0, stab->n_desc,
+ stab->n_value, curhdr);
+
+ if (debug_level >= 3)
+ check_hash();
+
+ /*
+ * Sometimes the compiler stutters, and emits the same stab
+ * twice. This is bad for the parser, which will attempt to
+ * redefine the type IDs indicated in the stabs. This is
+ * compiler bug 4433511.
+ */
+ if (ofstr && strcmp(fstr, ofstr) == 0) {
+ debug(3, "Stutter stab\n");
+ free(fstr);
+ fstr = NULL;
+ continue;
+ }
+
+ if (ofstr)
+ free(ofstr);
+ ofstr = fstr;
+
+ iidescp = NULL;
+
+ if ((rc = parse_stab(stab, fstr, &iidescp)) < 0) {
+ terminate("%s: Couldn't parse stab \"%s\" "
+ "(source file %s)\n", file, str, curhdr);
+ }
+
+ if (rc == 0)
+ goto parse_loop_end;
+
+ /* Make sure the scope tracking is working correctly */
+ assert(stab->n_type != N_FUN || (iidescp->ii_type != II_GFUN &&
+ iidescp->ii_type != II_SFUN) || scope == 0);
+
+ /*
+ * The only things we care about that are in local scope are
+ * the N_PSYM stabs.
+ */
+ if (scope && stab->n_type != N_PSYM) {
+ if (iidescp)
+ iidesc_free(iidescp, NULL);
+ goto parse_loop_end;
+ }
+
+ switch (iidescp->ii_type) {
+ case II_SFUN:
+ iidescp->ii_owner = xstrdup(curfile);
+ /*FALLTHROUGH*/
+ case II_GFUN:
+ curfun = iidescp;
+ fnarg_free(iidescp);
+ iidesc_add(td->td_iihash, iidescp);
+ break;
+
+ case II_SVAR:
+ iidescp->ii_owner = xstrdup(curfile);
+ /*FALLTHROUGH*/
+ case II_GVAR:
+ case II_TYPE:
+ case II_SOU:
+ iidesc_add(td->td_iihash, iidescp);
+ break;
+
+ case II_PSYM:
+ fnarg_add(curfun, iidescp);
+ iidesc_free(iidescp, NULL);
+ break;
+ default:
+ aborterr("invalid ii_type %d for stab type %d",
+ iidescp->ii_type, stab->n_type);
+ }
+
+parse_loop_end:
+ fstr = NULL;
+ }
+
+ if (ofstr)
+ free(ofstr);
+
+ resolve_nodes(td);
+ resolve_typed_bitfields();
+ parse_finish(td);
+
+ cvt_fixstabs(td);
+ cvt_fixups(td, elf_ptrsz(elf));
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/stack.c b/cddl/contrib/opensolaris/tools/ctf/cvt/stack.c
new file mode 100644
index 000000000000..7c36cd5ef149
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/stack.c
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ *
+ * 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 (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for manipulating stacks
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "stack.h"
+#include "memory.h"
+
+#define STACK_SEEDSIZE 5
+
+struct stk {
+ int st_nument;
+ int st_top;
+ void **st_data;
+
+ void (*st_free)(void *);
+};
+
+stk_t *
+stack_new(void (*freep)(void *))
+{
+ stk_t *sp;
+
+ sp = xmalloc(sizeof (stk_t));
+ sp->st_nument = STACK_SEEDSIZE;
+ sp->st_top = -1;
+ sp->st_data = xmalloc(sizeof (void *) * sp->st_nument);
+ sp->st_free = freep;
+
+ return (sp);
+}
+
+void
+stack_free(stk_t *sp)
+{
+ int i;
+
+ if (sp->st_free) {
+ for (i = 0; i <= sp->st_top; i++)
+ sp->st_free(sp->st_data[i]);
+ }
+ free(sp->st_data);
+ free(sp);
+}
+
+void *
+stack_pop(stk_t *sp)
+{
+ assert(sp->st_top >= 0);
+
+ return (sp->st_data[sp->st_top--]);
+}
+
+void *
+stack_peek(stk_t *sp)
+{
+ if (sp->st_top == -1)
+ return (NULL);
+
+ return (sp->st_data[sp->st_top]);
+}
+
+void
+stack_push(stk_t *sp, void *data)
+{
+ sp->st_top++;
+
+ if (sp->st_top == sp->st_nument) {
+ sp->st_nument += STACK_SEEDSIZE;
+ sp->st_data = xrealloc(sp->st_data,
+ sizeof (void *) * sp->st_nument);
+ }
+
+ sp->st_data[sp->st_top] = data;
+}
+
+int
+stack_level(stk_t *sp)
+{
+ return (sp->st_top + 1);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/stack.h b/cddl/contrib/opensolaris/tools/ctf/cvt/stack.h
new file mode 100644
index 000000000000..7dca7cfb10d8
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/stack.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ * 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 (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _STACK_H
+#define _STACK_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for manipulating stacks
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct stk stk_t;
+
+stk_t *stack_new(void (*)(void *));
+void stack_free(stk_t *);
+void *stack_pop(stk_t *);
+void *stack_peek(stk_t *);
+void stack_push(stk_t *, void *);
+int stack_level(stk_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STACK_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/strtab.c b/cddl/contrib/opensolaris/tools/ctf/cvt/strtab.c
new file mode 100644
index 000000000000..d8b2bf0e8176
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/strtab.c
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ *
+ * 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 (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "strtab.h"
+#include "memory.h"
+
+#define STRTAB_HASHSZ 211 /* use a prime number of hash buckets */
+#define STRTAB_BUFSZ (64 * 1024) /* use 64K data buffers by default */
+
+static void
+strtab_grow(strtab_t *sp)
+{
+ sp->str_nbufs++;
+ sp->str_bufs = xrealloc(sp->str_bufs, sp->str_nbufs * sizeof (char *));
+ sp->str_ptr = xmalloc(sp->str_bufsz);
+ sp->str_bufs[sp->str_nbufs - 1] = sp->str_ptr;
+}
+
+void
+strtab_create(strtab_t *sp)
+{
+ sp->str_hash = xcalloc(STRTAB_HASHSZ * sizeof (strhash_t *));
+ sp->str_hashsz = STRTAB_HASHSZ;
+ sp->str_bufs = NULL;
+ sp->str_ptr = NULL;
+ sp->str_nbufs = 0;
+ sp->str_bufsz = STRTAB_BUFSZ;
+ sp->str_nstrs = 1;
+ sp->str_size = 1;
+
+ strtab_grow(sp);
+ *sp->str_ptr++ = '\0';
+}
+
+void
+strtab_destroy(strtab_t *sp)
+{
+ strhash_t *hp, *hq;
+ ulong_t i;
+
+ for (i = 0; i < sp->str_hashsz; i++) {
+ for (hp = sp->str_hash[i]; hp != NULL; hp = hq) {
+ hq = hp->str_next;
+ free(hp);
+ }
+ }
+
+ for (i = 0; i < sp->str_nbufs; i++)
+ free(sp->str_bufs[i]);
+
+ free(sp->str_hash);
+ free(sp->str_bufs);
+}
+
+static ulong_t
+strtab_hash(const char *key, size_t *len)
+{
+ ulong_t g, h = 0;
+ const char *p;
+ size_t n = 0;
+
+ for (p = key; *p != '\0'; p++, n++) {
+ h = (h << 4) + *p;
+
+ if ((g = (h & 0xf0000000)) != 0) {
+ h ^= (g >> 24);
+ h ^= g;
+ }
+ }
+
+ *len = n;
+ return (h);
+}
+
+static int
+strtab_compare(strtab_t *sp, strhash_t *hp, const char *str, size_t len)
+{
+ ulong_t b = hp->str_buf;
+ const char *buf = hp->str_data;
+ size_t resid, n;
+ int rv;
+
+ while (len != 0) {
+ if (buf == sp->str_bufs[b] + sp->str_bufsz)
+ buf = sp->str_bufs[++b];
+
+ resid = sp->str_bufs[b] + sp->str_bufsz - buf;
+ n = MIN(resid, len);
+
+ if ((rv = strncmp(buf, str, n)) != 0)
+ return (rv);
+
+ buf += n;
+ str += n;
+ len -= n;
+ }
+
+ return (0);
+}
+
+static void
+strtab_copyin(strtab_t *sp, const char *str, size_t len)
+{
+ ulong_t b = sp->str_nbufs - 1;
+ size_t resid, n;
+
+ while (len != 0) {
+ if (sp->str_ptr == sp->str_bufs[b] + sp->str_bufsz) {
+ strtab_grow(sp);
+ b++;
+ }
+
+ resid = sp->str_bufs[b] + sp->str_bufsz - sp->str_ptr;
+ n = MIN(resid, len);
+ bcopy(str, sp->str_ptr, n);
+
+ sp->str_ptr += n;
+ str += n;
+ len -= n;
+ }
+}
+
+size_t
+strtab_insert(strtab_t *sp, const char *str)
+{
+ strhash_t *hp;
+ size_t len;
+ ulong_t h;
+
+ if (str == NULL || str[0] == '\0')
+ return (0); /* we keep a \0 at offset 0 to simplify things */
+
+ h = strtab_hash(str, &len) % sp->str_hashsz;
+
+ /*
+ * If the string is already in our hash table, just return the offset
+ * of the existing string element and do not add a duplicate string.
+ */
+ for (hp = sp->str_hash[h]; hp != NULL; hp = hp->str_next) {
+ if (strtab_compare(sp, hp, str, len + 1) == 0)
+ return (hp->str_off);
+ }
+
+ /*
+ * Create a new hash bucket, initialize it, and insert it at the front
+ * of the hash chain for the appropriate bucket.
+ */
+ hp = xmalloc(sizeof (strhash_t));
+
+ hp->str_data = sp->str_ptr;
+ hp->str_buf = sp->str_nbufs - 1;
+ hp->str_off = sp->str_size;
+ hp->str_len = len;
+ hp->str_next = sp->str_hash[h];
+
+ sp->str_hash[h] = hp;
+
+ /*
+ * Now copy the string data into our buffer list, and then update
+ * the global counts of strings and bytes. Return str's byte offset.
+ */
+ strtab_copyin(sp, str, len + 1);
+ sp->str_nstrs++;
+ sp->str_size += len + 1;
+
+ return (hp->str_off);
+}
+
+size_t
+strtab_size(const strtab_t *sp)
+{
+ return (sp->str_size);
+}
+
+ssize_t
+strtab_write(const strtab_t *sp,
+ ssize_t (*func)(void *, size_t, void *), void *priv)
+{
+ ssize_t res, total = 0;
+ ulong_t i;
+ size_t n;
+
+ for (i = 0; i < sp->str_nbufs; i++, total += res) {
+ if (i == sp->str_nbufs - 1)
+ n = sp->str_ptr - sp->str_bufs[i];
+ else
+ n = sp->str_bufsz;
+
+ if ((res = func(sp->str_bufs[i], n, priv)) <= 0)
+ break;
+ }
+
+ if (total == 0 && sp->str_size != 0)
+ return (-1);
+
+ return (total);
+}
+
+void
+strtab_print(const strtab_t *sp)
+{
+ const strhash_t *hp;
+ ulong_t i;
+
+ for (i = 0; i < sp->str_hashsz; i++) {
+ for (hp = sp->str_hash[i]; hp != NULL; hp = hp->str_next) {
+ const char *buf = hp->str_data;
+ ulong_t b = hp->str_buf;
+ size_t resid, len, n;
+
+ (void) printf("[%lu] %lu \"", (ulong_t)hp->str_off, b);
+
+ for (len = hp->str_len; len != 0; len -= n) {
+ if (buf == sp->str_bufs[b] + sp->str_bufsz)
+ buf = sp->str_bufs[++b];
+
+ resid = sp->str_bufs[b] + sp->str_bufsz - buf;
+ n = MIN(resid, len);
+
+ (void) printf("%.*s", (int)n, buf);
+ buf += n;
+ }
+
+ (void) printf("\"\n");
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/strtab.h b/cddl/contrib/opensolaris/tools/ctf/cvt/strtab.h
new file mode 100644
index 000000000000..13c1e59cd916
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/strtab.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ * 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 (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _STRTAB_H
+#define _STRTAB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct strhash {
+ const char *str_data; /* pointer to actual string data */
+ ulong_t str_buf; /* index of string data buffer */
+ size_t str_off; /* offset in bytes of this string */
+ size_t str_len; /* length in bytes of this string */
+ struct strhash *str_next; /* next string in hash chain */
+} strhash_t;
+
+typedef struct strtab {
+ strhash_t **str_hash; /* array of hash buckets */
+ ulong_t str_hashsz; /* size of hash bucket array */
+ char **str_bufs; /* array of buffer pointers */
+ char *str_ptr; /* pointer to current buffer location */
+ ulong_t str_nbufs; /* size of buffer pointer array */
+ size_t str_bufsz; /* size of individual buffer */
+ ulong_t str_nstrs; /* total number of strings in strtab */
+ size_t str_size; /* total size of strings in bytes */
+} strtab_t;
+
+extern void strtab_create(strtab_t *);
+extern void strtab_destroy(strtab_t *);
+extern size_t strtab_insert(strtab_t *, const char *);
+extern size_t strtab_size(const strtab_t *);
+extern ssize_t strtab_write(const strtab_t *,
+ ssize_t (*)(void *, size_t, void *), void *);
+extern void strtab_print(const strtab_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STRTAB_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/tdata.c b/cddl/contrib/opensolaris/tools/ctf/cvt/tdata.c
new file mode 100644
index 000000000000..d1a1ad0e7d05
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/tdata.c
@@ -0,0 +1,487 @@
+/*
+ * 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 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Routines for manipulating tdesc and tdata structures
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <pthread.h>
+
+#include "ctftools.h"
+#include "memory.h"
+#include "traverse.h"
+
+/*
+ * The layout hash is used during the equivalency checking. We have a node in
+ * the child graph that may be equivalent to a node in the parent graph. To
+ * find the corresponding node (if any) in the parent, we need a quick way to
+ * get to all nodes in the parent that look like the node in the child. Since a
+ * large number of nodes don't have names, we need to incorporate the layout of
+ * the node into the hash. If we don't, we'll end up with the vast majority of
+ * nodes in bucket zero, with one or two nodes in each of the remaining buckets.
+ *
+ * There are a couple of constraints, both of which concern forward
+ * declarations. Recall that a forward declaration tdesc is equivalent to a
+ * tdesc that actually defines the structure or union. As such, we cannot
+ * incorporate anything into the hash for a named struct or union node that
+ * couldn't be found by looking at the forward, and vice versa.
+ */
+int
+tdesc_layouthash(int nbuckets, void *node)
+{
+ tdesc_t *tdp = node;
+ char *name = NULL;
+ ulong_t h = 0;
+
+ if (tdp->t_name)
+ name = tdp->t_name;
+ else {
+ switch (tdp->t_type) {
+ case POINTER:
+ case TYPEDEF:
+ case VOLATILE:
+ case CONST:
+ case RESTRICT:
+ name = tdp->t_tdesc->t_name;
+ break;
+ case FUNCTION:
+ h = tdp->t_fndef->fn_nargs +
+ tdp->t_fndef->fn_vargs;
+ name = tdp->t_fndef->fn_ret->t_name;
+ break;
+ case ARRAY:
+ h = tdp->t_ardef->ad_nelems;
+ name = tdp->t_ardef->ad_contents->t_name;
+ break;
+ case STRUCT:
+ case UNION:
+ /*
+ * Unnamed structures, which cannot have forward
+ * declarations pointing to them. We can therefore
+ * incorporate the name of the first member into
+ * the hash value, assuming there are any.
+ */
+ if (tdp->t_members != NULL)
+ name = tdp->t_members->ml_name;
+ break;
+ case ENUM:
+ /* Use the first element in the hash value */
+ name = tdp->t_emem->el_name;
+ break;
+ default:
+ /*
+ * Intrinsics, forwards, and typedefs all have
+ * names.
+ */
+ warning("Unexpected unnamed %d tdesc (ID %d)\n",
+ tdp->t_type, tdp->t_id);
+ }
+ }
+
+ if (name)
+ return (hash_name(nbuckets, name));
+
+ return (h % nbuckets);
+}
+
+int
+tdesc_layoutcmp(void *arg1, void *arg2)
+{
+ tdesc_t *tdp1 = arg1, *tdp2 = arg2;
+
+ if (tdp1->t_name == NULL) {
+ if (tdp2->t_name == NULL)
+ return (0);
+ else
+ return (-1);
+ } else if (tdp2->t_name == NULL)
+ return (1);
+ else
+ return (strcmp(tdp1->t_name, tdp2->t_name));
+}
+
+int
+tdesc_idhash(int nbuckets, void *data)
+{
+ tdesc_t *tdp = data;
+
+ return (tdp->t_id % nbuckets);
+}
+
+int
+tdesc_idcmp(void *arg1, void *arg2)
+{
+ tdesc_t *tdp1 = arg1, *tdp2 = arg2;
+
+ if (tdp1->t_id == tdp2->t_id)
+ return (0);
+ else
+ return (tdp1->t_id > tdp2->t_id ? 1 : -1);
+}
+
+int
+tdesc_namehash(int nbuckets, void *data)
+{
+ tdesc_t *tdp = data;
+ ulong_t h, g;
+ char *c;
+
+ if (tdp->t_name == NULL)
+ return (0);
+
+ for (h = 0, c = tdp->t_name; *c; c++) {
+ h = (h << 4) + *c;
+ if ((g = (h & 0xf0000000)) != 0) {
+ h ^= (g >> 24);
+ h ^= g;
+ }
+ }
+
+ return (h % nbuckets);
+}
+
+int
+tdesc_namecmp(void *arg1, void *arg2)
+{
+ tdesc_t *tdp1 = arg1, *tdp2 = arg2;
+
+ return (!streq(tdp1->t_name, tdp2->t_name));
+}
+
+#ifdef illumos
+/*ARGSUSED1*/
+static int
+tdesc_print(void *data, void *private __unused)
+{
+ tdesc_t *tdp = data;
+
+ printf("%7d %s\n", tdp->t_id, tdesc_name(tdp));
+
+ return (1);
+}
+#endif
+
+static void
+free_intr(tdesc_t *tdp)
+{
+ free(tdp->t_intr);
+}
+
+static void
+free_ardef(tdesc_t *tdp)
+{
+ free(tdp->t_ardef);
+}
+
+static void
+free_mlist(tdesc_t *tdp)
+{
+ mlist_t *ml = tdp->t_members;
+ mlist_t *oml;
+
+ while (ml) {
+ oml = ml;
+ ml = ml->ml_next;
+
+ if (oml->ml_name)
+ free(oml->ml_name);
+ free(oml);
+ }
+}
+
+static void
+free_elist(tdesc_t *tdp)
+{
+ elist_t *el = tdp->t_emem;
+ elist_t *oel;
+
+ while (el) {
+ oel = el;
+ el = el->el_next;
+
+ if (oel->el_name)
+ free(oel->el_name);
+ free(oel);
+ }
+}
+
+static void (*free_cbs[])(tdesc_t *) = {
+ NULL,
+ free_intr,
+ NULL,
+ free_ardef,
+ NULL,
+ free_mlist,
+ free_mlist,
+ free_elist,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*ARGSUSED1*/
+static void
+tdesc_free_cb(void *arg, void *private __unused)
+{
+ tdesc_t *tdp = arg;
+ if (tdp->t_name)
+ free(tdp->t_name);
+ if (free_cbs[tdp->t_type])
+ free_cbs[tdp->t_type](tdp);
+ free(tdp);
+
+ return;
+}
+
+void
+tdesc_free(tdesc_t *tdp)
+{
+ tdesc_free_cb(tdp, NULL);
+}
+
+static int
+tdata_label_cmp(void *arg1, void *arg2)
+{
+ labelent_t *le1 = arg1;
+ labelent_t *le2 = arg2;
+ return (le1->le_idx - le2->le_idx);
+}
+
+void
+tdata_label_add(tdata_t *td, const char *label, int idx)
+{
+ labelent_t *le = xmalloc(sizeof (*le));
+
+ le->le_name = xstrdup(label);
+ le->le_idx = (idx == -1 ? td->td_nextid - 1 : idx);
+
+ slist_add(&td->td_labels, le, tdata_label_cmp);
+}
+
+static int
+tdata_label_top_cb(void *data, void *arg)
+{
+ labelent_t *le = data;
+ labelent_t **topp = arg;
+
+ *topp = le;
+
+ return (1);
+}
+
+labelent_t *
+tdata_label_top(tdata_t *td)
+{
+ labelent_t *top = NULL;
+
+ (void) list_iter(td->td_labels, tdata_label_top_cb, &top);
+
+ return (top);
+}
+
+static int
+tdata_label_find_cb(void *arg1, void *arg2)
+{
+ labelent_t *le = arg1;
+ labelent_t *tmpl = arg2;
+ return (streq(le->le_name, tmpl->le_name));
+}
+
+int
+tdata_label_find(tdata_t *td, char *label)
+{
+ labelent_t let;
+ labelent_t *ret;
+
+ if (streq(label, "BASE")) {
+ ret = (labelent_t *)list_first(td->td_labels);
+ return (ret ? ret->le_idx : -1);
+ }
+
+ let.le_name = label;
+
+ if (!(ret = (labelent_t *)list_find(td->td_labels, &let,
+ tdata_label_find_cb)))
+ return (-1);
+
+ return (ret->le_idx);
+}
+
+static int
+tdata_label_newmax_cb(void *data, void *arg)
+{
+ labelent_t *le = data;
+ int *newmaxp = arg;
+
+ if (le->le_idx > *newmaxp) {
+ le->le_idx = *newmaxp;
+ return (1);
+ }
+
+ return (0);
+}
+
+void
+tdata_label_newmax(tdata_t *td, int newmax)
+{
+ (void) list_iter(td->td_labels, tdata_label_newmax_cb, &newmax);
+}
+
+/*ARGSUSED1*/
+static void
+tdata_label_free_cb(void *arg, void *private __unused)
+{
+ labelent_t *le = arg;
+ if (le->le_name)
+ free(le->le_name);
+ free(le);
+}
+
+void
+tdata_label_free(tdata_t *td)
+{
+ list_free(td->td_labels, tdata_label_free_cb, NULL);
+ td->td_labels = NULL;
+}
+
+tdata_t *
+tdata_new(void)
+{
+ tdata_t *new = xcalloc(sizeof (tdata_t));
+
+ new->td_layouthash = hash_new(TDATA_LAYOUT_HASH_SIZE, tdesc_layouthash,
+ tdesc_layoutcmp);
+ new->td_idhash = hash_new(TDATA_ID_HASH_SIZE, tdesc_idhash,
+ tdesc_idcmp);
+ /*
+ * This is also traversed as a list, but amortized O(1)
+ * lookup massively impacts part of the merge phase, so
+ * we store the iidescs as a hash.
+ */
+ new->td_iihash = hash_new(IIDESC_HASH_SIZE, iidesc_hash, NULL);
+ new->td_nextid = 1;
+ new->td_curvgen = 1;
+
+ pthread_mutex_init(&new->td_mergelock, NULL);
+
+ return (new);
+}
+
+void
+tdata_free(tdata_t *td)
+{
+ hash_free(td->td_iihash, iidesc_free, NULL);
+ hash_free(td->td_layouthash, tdesc_free_cb, NULL);
+ hash_free(td->td_idhash, NULL, NULL);
+ list_free(td->td_fwdlist, NULL, NULL);
+
+ tdata_label_free(td);
+
+ free(td->td_parlabel);
+ free(td->td_parname);
+
+ pthread_mutex_destroy(&td->td_mergelock);
+
+ free(td);
+}
+
+/*ARGSUSED1*/
+static int
+build_hashes(tdesc_t *ctdp, tdesc_t **ctdpp __unused, void *private)
+{
+ tdata_t *td = private;
+
+ hash_add(td->td_idhash, ctdp);
+ hash_add(td->td_layouthash, ctdp);
+
+ return (1);
+}
+
+static tdtrav_cb_f build_hashes_cbs[] = {
+ NULL,
+ build_hashes, /* intrinsic */
+ build_hashes, /* pointer */
+ build_hashes, /* array */
+ build_hashes, /* function */
+ build_hashes, /* struct */
+ build_hashes, /* union */
+ build_hashes, /* enum */
+ build_hashes, /* forward */
+ build_hashes, /* typedef */
+ tdtrav_assert, /* typedef_unres */
+ build_hashes, /* volatile */
+ build_hashes, /* const */
+ build_hashes /* restrict */
+};
+
+static void
+tdata_build_hashes_common(tdata_t *td, hash_t *hash)
+{
+ (void) iitraverse_hash(hash, &td->td_curvgen, NULL, NULL,
+ build_hashes_cbs, td);
+}
+
+void
+tdata_build_hashes(tdata_t *td)
+{
+ tdata_build_hashes_common(td, td->td_iihash);
+}
+
+/* Merge td2 into td1. td2 is destroyed by the merge */
+void
+tdata_merge(tdata_t *td1, tdata_t *td2)
+{
+ td1->td_curemark = MAX(td1->td_curemark, td2->td_curemark);
+ td1->td_curvgen = MAX(td1->td_curvgen, td2->td_curvgen);
+ td1->td_nextid = MAX(td1->td_nextid, td2->td_nextid);
+
+ hash_merge(td1->td_iihash, td2->td_iihash);
+
+ /* Add td2's type tree to the hashes */
+ tdata_build_hashes_common(td1, td2->td_iihash);
+
+ list_concat(&td1->td_fwdlist, td2->td_fwdlist);
+ td2->td_fwdlist = NULL;
+
+ slist_merge(&td1->td_labels, td2->td_labels,
+ tdata_label_cmp);
+ td2->td_labels = NULL;
+
+ /* free the td2 hashes (data is now part of td1) */
+
+ hash_free(td2->td_layouthash, NULL, NULL);
+ td2->td_layouthash = NULL;
+
+ hash_free(td2->td_iihash, NULL, NULL);
+ td2->td_iihash = NULL;
+
+ tdata_free(td2);
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/traverse.c b/cddl/contrib/opensolaris/tools/ctf/cvt/traverse.c
new file mode 100644
index 000000000000..2d6d74bc78b1
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/traverse.c
@@ -0,0 +1,226 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines used to traverse tdesc trees, invoking user-supplied callbacks
+ * as the tree is traversed.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "ctftools.h"
+#include "traverse.h"
+#include "memory.h"
+
+static int (*tddescenders[])(tdesc_t *, tdtrav_data_t *);
+static tdtrav_cb_f tdnops[];
+
+void
+tdtrav_init(tdtrav_data_t *tdtd, int *vgenp, tdtrav_cb_f *firstops,
+ tdtrav_cb_f *preops, tdtrav_cb_f *postops, void *private)
+{
+ tdtd->vgen = ++(*vgenp);
+ tdtd->firstops = firstops ? firstops : tdnops;
+ tdtd->preops = preops ? preops : tdnops;
+ tdtd->postops = postops ? postops : tdnops;
+ tdtd->private = private;
+}
+
+static int
+tdtrav_plain(tdesc_t *this, tdtrav_data_t *tdtd)
+{
+ return (tdtraverse(this->t_tdesc, &this->t_tdesc, tdtd));
+}
+
+static int
+tdtrav_func(tdesc_t *this, tdtrav_data_t *tdtd)
+{
+ fndef_t *fn = this->t_fndef;
+ int i, rc;
+
+ if ((rc = tdtraverse(fn->fn_ret, &fn->fn_ret, tdtd)) < 0)
+ return (rc);
+
+ for (i = 0; i < (int) fn->fn_nargs; i++) {
+ if ((rc = tdtraverse(fn->fn_args[i], &fn->fn_args[i],
+ tdtd)) < 0)
+ return (rc);
+ }
+
+ return (0);
+}
+
+static int
+tdtrav_array(tdesc_t *this, tdtrav_data_t *tdtd)
+{
+ ardef_t *ardef = this->t_ardef;
+ int rc;
+
+ if ((rc = tdtraverse(ardef->ad_contents, &ardef->ad_contents,
+ tdtd)) < 0)
+ return (rc);
+
+ return (tdtraverse(ardef->ad_idxtype, &ardef->ad_idxtype, tdtd));
+}
+
+static int
+tdtrav_su(tdesc_t *this, tdtrav_data_t *tdtd)
+{
+ mlist_t *ml;
+ int rc = 0;
+
+ for (ml = this->t_members; ml; ml = ml->ml_next) {
+ if ((rc = tdtraverse(ml->ml_type, &ml->ml_type, tdtd)) < 0)
+ return (rc);
+ }
+
+ return (rc);
+}
+
+/*ARGSUSED*/
+int
+tdtrav_assert(tdesc_t *node __unused, tdesc_t **nodep __unused, void *private __unused)
+{
+ assert(1 == 0);
+
+ return (-1);
+}
+
+static tdtrav_cb_f tdnops[] = {
+ NULL,
+ NULL, /* intrinsic */
+ NULL, /* pointer */
+ NULL, /* array */
+ NULL, /* function */
+ NULL, /* struct */
+ NULL, /* union */
+ NULL, /* enum */
+ NULL, /* forward */
+ NULL, /* typedef */
+ NULL, /* typedef_unres */
+ NULL, /* volatile */
+ NULL, /* const */
+ NULL /* restrict */
+};
+
+static int (*tddescenders[])(tdesc_t *, tdtrav_data_t *) = {
+ NULL,
+ NULL, /* intrinsic */
+ tdtrav_plain, /* pointer */
+ tdtrav_array, /* array */
+ tdtrav_func, /* function */
+ tdtrav_su, /* struct */
+ tdtrav_su, /* union */
+ NULL, /* enum */
+ NULL, /* forward */
+ tdtrav_plain, /* typedef */
+ NULL, /* typedef_unres */
+ tdtrav_plain, /* volatile */
+ tdtrav_plain, /* const */
+ tdtrav_plain /* restrict */
+};
+
+int
+tdtraverse(tdesc_t *this, tdesc_t **thisp, tdtrav_data_t *tdtd)
+{
+ tdtrav_cb_f travcb;
+ int (*descender)(tdesc_t *, tdtrav_data_t *);
+ int descend = 1;
+ int rc;
+
+ if ((travcb = tdtd->firstops[this->t_type]) != NULL) {
+ if ((rc = travcb(this, thisp, tdtd->private)) < 0)
+ return (rc);
+ else if (rc == 0)
+ descend = 0;
+ }
+
+ if (this->t_vgen == tdtd->vgen)
+ return (1);
+ this->t_vgen = tdtd->vgen;
+
+ if (descend && (travcb = tdtd->preops[this->t_type]) != NULL) {
+ if ((rc = travcb(this, thisp, tdtd->private)) < 0)
+ return (rc);
+ else if (rc == 0)
+ descend = 0;
+ }
+
+ if (descend) {
+ if ((descender = tddescenders[this->t_type]) != NULL &&
+ (rc = descender(this, tdtd)) < 0)
+ return (rc);
+
+ if ((travcb = tdtd->postops[this->t_type]) != NULL &&
+ (rc = travcb(this, thisp, tdtd->private)) < 0)
+ return (rc);
+ }
+
+ return (1);
+}
+
+int
+iitraverse_td(void *arg1, void *arg2)
+{
+ iidesc_t *ii = arg1;
+ tdtrav_data_t *tdtd = arg2;
+ int i, rc;
+
+ if ((rc = tdtraverse(ii->ii_dtype, &ii->ii_dtype, tdtd)) < 0)
+ return (rc);
+
+ for (i = 0; i < ii->ii_nargs; i++) {
+ if ((rc = tdtraverse(ii->ii_args[i], &ii->ii_args[i],
+ tdtd)) < 0)
+ return (rc);
+ }
+
+ return (1);
+}
+
+int
+iitraverse(iidesc_t *ii, int *vgenp, tdtrav_cb_f *firstops, tdtrav_cb_f *preops,
+ tdtrav_cb_f *postops, void *private)
+{
+ tdtrav_data_t tdtd;
+
+ tdtrav_init(&tdtd, vgenp, firstops, preops, postops, private);
+
+ return (iitraverse_td(ii, &tdtd));
+}
+
+int
+iitraverse_hash(hash_t *iihash, int *vgenp, tdtrav_cb_f *firstops,
+ tdtrav_cb_f *preops, tdtrav_cb_f *postops, void *private)
+{
+ tdtrav_data_t tdtd;
+
+ tdtrav_init(&tdtd, vgenp, firstops, preops, postops, private);
+
+ return (hash_iter(iihash, iitraverse_td, &tdtd));
+}
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/traverse.h b/cddl/contrib/opensolaris/tools/ctf/cvt/traverse.h
new file mode 100644
index 000000000000..6a56370abc40
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/traverse.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _TRAVERSE_H
+#define _TRAVERSE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines used to traverse tdesc trees, invoking user-supplied callbacks
+ * as the tree is traversed.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ctftools.h"
+
+typedef int (*tdtrav_cb_f)(tdesc_t *, tdesc_t **, void *);
+
+typedef struct tdtrav_data {
+ int vgen;
+
+ tdtrav_cb_f *firstops;
+ tdtrav_cb_f *preops;
+ tdtrav_cb_f *postops;
+
+ void *private;
+} tdtrav_data_t;
+
+void tdtrav_init(tdtrav_data_t *, int *, tdtrav_cb_f *, tdtrav_cb_f *,
+ tdtrav_cb_f *, void *);
+int tdtraverse(tdesc_t *, tdesc_t **, tdtrav_data_t *);
+
+int iitraverse(iidesc_t *, int *, tdtrav_cb_f *, tdtrav_cb_f *, tdtrav_cb_f *,
+ void *);
+int iitraverse_hash(hash_t *, int *, tdtrav_cb_f *, tdtrav_cb_f *,
+ tdtrav_cb_f *, void *);
+int iitraverse_td(void *, void *);
+
+int tdtrav_assert(tdesc_t *, tdesc_t **, void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TRAVERSE_H */
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/util.c b/cddl/contrib/opensolaris/tools/ctf/cvt/util.c
new file mode 100644
index 000000000000..fb76cbaeb422
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/util.c
@@ -0,0 +1,283 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Utility functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+#include "ctftools.h"
+#include "memory.h"
+
+static void (*terminate_cleanup)(void) = NULL;
+
+/* returns 1 if s1 == s2, 0 otherwise */
+int
+streq(const char *s1, const char *s2)
+{
+ if (s1 == NULL) {
+ if (s2 != NULL)
+ return (0);
+ } else if (s2 == NULL)
+ return (0);
+ else if (strcmp(s1, s2) != 0)
+ return (0);
+
+ return (1);
+}
+
+int
+findelfsecidx(Elf *elf, const char *file, const char *tofind)
+{
+ Elf_Scn *scn = NULL;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+
+ if (gelf_getehdr(elf, &ehdr) == NULL)
+ elfterminate(file, "Couldn't read ehdr");
+
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ char *name;
+
+ if (gelf_getshdr(scn, &shdr) == NULL) {
+ elfterminate(file,
+ "Couldn't read header for section %d",
+ elf_ndxscn(scn));
+ }
+
+ if ((name = elf_strptr(elf, ehdr.e_shstrndx,
+ (size_t)shdr.sh_name)) == NULL) {
+ elfterminate(file,
+ "Couldn't get name for section %d",
+ elf_ndxscn(scn));
+ }
+
+ if (strcmp(name, tofind) == 0)
+ return (elf_ndxscn(scn));
+ }
+
+ return (-1);
+}
+
+size_t
+elf_ptrsz(Elf *elf)
+{
+ GElf_Ehdr ehdr;
+
+ if (gelf_getehdr(elf, &ehdr) == NULL) {
+ terminate("failed to read ELF header: %s\n",
+ elf_errmsg(-1));
+ }
+
+ if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
+ return (4);
+ else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+ return (8);
+ else
+ terminate("unknown ELF class %d\n", ehdr.e_ident[EI_CLASS]);
+
+ /*NOTREACHED*/
+ return (0);
+}
+
+/*PRINTFLIKE2*/
+static void
+whine(const char *type, const char *format, va_list ap)
+{
+ int error = errno;
+
+ fprintf(stderr, "%s: %s: ", type, progname);
+ vfprintf(stderr, format, ap);
+
+ if (format[strlen(format) - 1] != '\n')
+ fprintf(stderr, ": %s\n", strerror(error));
+}
+
+void
+set_terminate_cleanup(void (*cleanup)(void))
+{
+ terminate_cleanup = cleanup;
+}
+
+/*PRINTFLIKE1*/
+void
+terminate(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ whine("ERROR", format, ap);
+ va_end(ap);
+
+ if (terminate_cleanup)
+ terminate_cleanup();
+
+ if (getenv("CTF_ABORT_ON_TERMINATE") != NULL)
+ abort();
+#if defined(__FreeBSD__)
+/*
+ * For the time being just output the termination message, but don't
+ * return an exit status that would cause the build to fail. We need
+ * to get as much stuff built as possible before going back and
+ * figuring out what is wrong with certain files.
+ */
+ exit(0);
+#else
+ exit(1);
+#endif
+}
+
+/*PRINTFLIKE1*/
+void
+aborterr(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ whine("ERROR", format, ap);
+ va_end(ap);
+
+#ifdef illumos
+ abort();
+#else
+ exit(0);
+#endif
+}
+
+/*PRINTFLIKE1*/
+void
+warning(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ whine("WARNING", format, ap);
+ va_end(ap);
+
+ if (debug_level >= 3)
+ terminate("Termination due to warning\n");
+}
+
+/*PRINTFLIKE2*/
+void
+vadebug(int level, const char *format, va_list ap)
+{
+ if (level > debug_level)
+ return;
+
+ (void) fprintf(DEBUG_STREAM, "DEBUG: ");
+ (void) vfprintf(DEBUG_STREAM, format, ap);
+ fflush(DEBUG_STREAM);
+}
+
+/*PRINTFLIKE2*/
+void
+debug(int level, const char *format, ...)
+{
+ va_list ap;
+
+ if (level > debug_level)
+ return;
+
+ va_start(ap, format);
+ (void) vadebug(level, format, ap);
+ va_end(ap);
+}
+
+char *
+mktmpname(const char *origname, const char *suffix)
+{
+ char *newname;
+
+ newname = xmalloc(strlen(origname) + strlen(suffix) + 1);
+ (void) strcpy(newname, origname);
+ (void) strcat(newname, suffix);
+ return (newname);
+}
+
+/*PRINTFLIKE2*/
+void
+elfterminate(const char *file, const char *fmt, ...)
+{
+ static char msgbuf[BUFSIZ];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof (msgbuf), fmt, ap);
+ va_end(ap);
+
+ terminate("%s: %s: %s\n", file, msgbuf, elf_errmsg(-1));
+}
+
+const char *
+tdesc_name(tdesc_t *tdp)
+{
+ return (tdp->t_name == NULL ? "(anon)" : tdp->t_name);
+}
+
+static char *watch_address = NULL;
+static int watch_length = 0;
+
+void
+watch_set(void *addr, int len)
+{
+ watch_address = addr;
+ watch_length = len;
+}
+
+void
+watch_dump(int v)
+{
+ char *p = watch_address;
+ int i;
+
+ if (watch_address == NULL || watch_length == 0)
+ return;
+
+ printf("%d: watch %p len %d\n",v,watch_address,watch_length);
+ for (i = 0; i < watch_length; i++) {
+ if (*p >= 0x20 && *p < 0x7f) {
+ printf(" %c",*p++ & 0xff);
+ } else {
+ printf(" %02x",*p++ & 0xff);
+ }
+ }
+ printf("\n");
+
+}
+
+
diff --git a/cddl/contrib/opensolaris/tools/ctf/dump/dump.c b/cddl/contrib/opensolaris/tools/ctf/dump/dump.c
new file mode 100644
index 000000000000..740485ddff03
--- /dev/null
+++ b/cddl/contrib/opensolaris/tools/ctf/dump/dump.c
@@ -0,0 +1,1028 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <strings.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <zlib.h>
+
+#include "ctf_headers.h"
+#include "utils.h"
+#include "symbol.h"
+
+#define WARN(x) { warn(x); return (E_ERROR); }
+
+/*
+ * Flags that indicate what data is to be displayed. An explicit `all' value is
+ * provided to allow the code to distinguish between a request for everything
+ * (currently requested by invoking ctfdump without flags) and individual
+ * requests for all of the types of data (an invocation with all flags). In the
+ * former case, we want to be able to implicitly adjust the definition of `all'
+ * based on the CTF version of the file being dumped. For example, if a v2 file
+ * is being dumped, `all' includes F_LABEL - a request to dump the label
+ * section. If a v1 file is being dumped, `all' does not include F_LABEL,
+ * because v1 CTF doesn't support labels. We need to be able to distinguish
+ * between `ctfdump foo', which has an implicit request for labels if `foo'
+ * supports them, and `ctfdump -l foo', which has an explicity request. In the
+ * latter case, we exit with an error if `foo' is a v1 CTF file.
+ */
+static enum {
+ F_DATA = 0x01, /* show data object section */
+ F_FUNC = 0x02, /* show function section */
+ F_HDR = 0x04, /* show header */
+ F_STR = 0x08, /* show string table */
+ F_TYPES = 0x10, /* show type section */
+ F_STATS = 0x20, /* show statistics */
+ F_LABEL = 0x40, /* show label section */
+ F_ALL = 0x80, /* explicit request for `all' */
+ F_ALLMSK = 0xff /* show all sections and statistics */
+} flags = 0;
+
+static struct {
+ ulong_t s_ndata; /* total number of data objects */
+ ulong_t s_nfunc; /* total number of functions */
+ ulong_t s_nargs; /* total number of function arguments */
+ ulong_t s_argmax; /* longest argument list */
+ ulong_t s_ntypes; /* total number of types */
+ ulong_t s_types[16]; /* number of types by kind */
+ ulong_t s_nsmem; /* total number of struct members */
+ ulong_t s_nsbytes; /* total size of all structs */
+ ulong_t s_smmax; /* largest struct in terms of members */
+ ulong_t s_sbmax; /* largest struct in terms of bytes */
+ ulong_t s_numem; /* total number of union members */
+ ulong_t s_nubytes; /* total size of all unions */
+ ulong_t s_ummax; /* largest union in terms of members */
+ ulong_t s_ubmax; /* largest union in terms of bytes */
+ ulong_t s_nemem; /* total number of enum members */
+ ulong_t s_emmax; /* largest enum in terms of members */
+ ulong_t s_nstr; /* total number of strings */
+ size_t s_strlen; /* total length of all strings */
+ size_t s_strmax; /* longest string length */
+} stats;
+
+typedef struct ctf_data {
+ caddr_t cd_ctfdata; /* Pointer to the CTF data */
+ size_t cd_ctflen; /* Length of CTF data */
+
+ /*
+ * cd_symdata will be non-NULL if the CTF data is being retrieved from
+ * an ELF file with a symbol table. cd_strdata and cd_nsyms should be
+ * used only if cd_symdata is non-NULL.
+ */
+ Elf_Data *cd_symdata; /* Symbol table */
+ Elf_Data *cd_strdata; /* Symbol table strings */
+ int cd_nsyms; /* Number of symbol table entries */
+} ctf_data_t;
+
+static const char *
+ref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd)
+{
+ size_t offset = CTF_NAME_OFFSET(name);
+ const char *s = cd->cd_ctfdata + hp->cth_stroff + offset;
+
+ if (CTF_NAME_STID(name) != CTF_STRTAB_0)
+ return ("<< ??? - name in external strtab >>");
+
+ if (offset >= hp->cth_strlen)
+ return ("<< ??? - name exceeds strlab len >>");
+
+ if (hp->cth_stroff + offset >= cd->cd_ctflen)
+ return ("<< ??? - file truncated >>");
+
+ if (s[0] == '\0')
+ return ("(anon)");
+
+ return (s);
+}
+
+static const char *
+int_encoding_to_str(uint_t encoding)
+{
+ static char buf[32];
+
+ if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR |
+ CTF_INT_BOOL | CTF_INT_VARARGS)) != 0)
+ (void) snprintf(buf, sizeof (buf), " 0x%x", encoding);
+ else {
+ buf[0] = '\0';
+ if (encoding & CTF_INT_SIGNED)
+ (void) strcat(buf, " SIGNED");
+ if (encoding & CTF_INT_CHAR)
+ (void) strcat(buf, " CHAR");
+ if (encoding & CTF_INT_BOOL)
+ (void) strcat(buf, " BOOL");
+ if (encoding & CTF_INT_VARARGS)
+ (void) strcat(buf, " VARARGS");
+ }
+
+ return (buf + 1);
+}
+
+static const char *
+fp_encoding_to_str(uint_t encoding)
+{
+ static const char *const encs[] = {
+ NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX",
+ "LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY",
+ "DIMAGINARY", "LDIMAGINARY"
+ };
+
+ static char buf[16];
+
+ if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) {
+ (void) snprintf(buf, sizeof (buf), "%u", encoding);
+ return (buf);
+ }
+
+ return (encs[encoding]);
+}
+
+static void
+print_line(const char *s)
+{
+ static const char line[] = "----------------------------------------"
+ "----------------------------------------";
+ (void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line);
+}
+
+static int
+print_header(const ctf_header_t *hp, const ctf_data_t *cd)
+{
+ print_line("- CTF Header ");
+
+ (void) printf(" cth_magic = 0x%04x\n", hp->cth_magic);
+ (void) printf(" cth_version = %u\n", hp->cth_version);
+ (void) printf(" cth_flags = 0x%02x\n", hp->cth_flags);
+ (void) printf(" cth_parlabel = %s\n",
+ ref_to_str(hp->cth_parlabel, hp, cd));
+ (void) printf(" cth_parname = %s\n",
+ ref_to_str(hp->cth_parname, hp, cd));
+ (void) printf(" cth_lbloff = %u\n", hp->cth_lbloff);
+ (void) printf(" cth_objtoff = %u\n", hp->cth_objtoff);
+ (void) printf(" cth_funcoff = %u\n", hp->cth_funcoff);
+ (void) printf(" cth_typeoff = %u\n", hp->cth_typeoff);
+ (void) printf(" cth_stroff = %u\n", hp->cth_stroff);
+ (void) printf(" cth_strlen = %u\n", hp->cth_strlen);
+
+ return (E_SUCCESS);
+}
+
+static int
+print_labeltable(const ctf_header_t *hp, const ctf_data_t *cd)
+{
+ void *v = (void *) (cd->cd_ctfdata + hp->cth_lbloff);
+ const ctf_lblent_t *ctl = v;
+ ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl);
+
+ print_line("- Label Table ");
+
+ if (hp->cth_lbloff & 3)
+ WARN("cth_lbloff is not aligned properly\n");
+ if (hp->cth_lbloff >= cd->cd_ctflen)
+ WARN("file is truncated or cth_lbloff is corrupt\n");
+ if (hp->cth_objtoff >= cd->cd_ctflen)
+ WARN("file is truncated or cth_objtoff is corrupt\n");
+ if (hp->cth_lbloff > hp->cth_objtoff)
+ WARN("file is corrupt -- cth_lbloff > cth_objtoff\n");
+
+ for (i = 0; i < n; i++, ctl++) {
+ (void) printf(" %5u %s\n", ctl->ctl_typeidx,
+ ref_to_str(ctl->ctl_label, hp, cd));
+ }
+
+ return (E_SUCCESS);
+}
+
+/*
+ * Given the current symbol index (-1 to start at the beginning of the symbol
+ * table) and the type of symbol to match, this function returns the index of
+ * the next matching symbol (if any), and places the name of that symbol in
+ * *namep. If no symbol is found, -1 is returned.
+ */
+static int
+next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype,
+ char **namep)
+{
+ int i;
+
+ for (i = symidx + 1; i < cd->cd_nsyms; i++) {
+ GElf_Sym sym;
+ char *name;
+ int type;
+
+ if (gelf_getsym(cd->cd_symdata, i, &sym) == 0)
+ return (-1);
+
+ name = (char *)cd->cd_strdata->d_buf + sym.st_name;
+ type = GELF_ST_TYPE(sym.st_info);
+
+ /*
+ * Skip various types of symbol table entries.
+ */
+ if (type != matchtype || ignore_symbol(&sym, name))
+ continue;
+
+ /* Found one */
+ *namep = name;
+ return (i);
+ }
+
+ return (-1);
+}
+
+static int
+read_data(const ctf_header_t *hp, const ctf_data_t *cd)
+{
+ void *v = (void *) (cd->cd_ctfdata + hp->cth_objtoff);
+ const ushort_t *idp = v;
+ ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / sizeof (ushort_t);
+
+ if (flags != F_STATS)
+ print_line("- Data Objects ");
+
+ if (hp->cth_objtoff & 1)
+ WARN("cth_objtoff is not aligned properly\n");
+ if (hp->cth_objtoff >= cd->cd_ctflen)
+ WARN("file is truncated or cth_objtoff is corrupt\n");
+ if (hp->cth_funcoff >= cd->cd_ctflen)
+ WARN("file is truncated or cth_funcoff is corrupt\n");
+ if (hp->cth_objtoff > hp->cth_funcoff)
+ WARN("file is corrupt -- cth_objtoff > cth_funcoff\n");
+
+ if (flags != F_STATS) {
+ int symidx, len, i;
+ char *name = NULL;
+
+ for (symidx = -1, i = 0; i < (int) n; i++) {
+ int nextsym;
+
+ if (cd->cd_symdata == NULL || (nextsym = next_sym(cd,
+ symidx, STT_OBJECT, &name)) < 0)
+ name = NULL;
+ else
+ symidx = nextsym;
+
+ len = printf(" [%u] %u", i, *idp++);
+ if (name != NULL)
+ (void) printf("%*s%s (%u)", (15 - len), "",
+ name, symidx);
+ (void) putchar('\n');
+ }
+ }
+
+ stats.s_ndata = n;
+ return (E_SUCCESS);
+}
+
+static int
+read_funcs(const ctf_header_t *hp, const ctf_data_t *cd)
+{
+ void *v = (void *) (cd->cd_ctfdata + hp->cth_funcoff);
+ const ushort_t *fp = v;
+
+ v = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
+ const ushort_t *end = v;
+
+ ulong_t id;
+ int symidx;
+
+ if (flags != F_STATS)
+ print_line("- Functions ");
+
+ if (hp->cth_funcoff & 1)
+ WARN("cth_funcoff is not aligned properly\n");
+ if (hp->cth_funcoff >= cd->cd_ctflen)
+ WARN("file is truncated or cth_funcoff is corrupt\n");
+ if (hp->cth_typeoff >= cd->cd_ctflen)
+ WARN("file is truncated or cth_typeoff is corrupt\n");
+ if (hp->cth_funcoff > hp->cth_typeoff)
+ WARN("file is corrupt -- cth_funcoff > cth_typeoff\n");
+
+ for (symidx = -1, id = 0; fp < end; id++) {
+ ushort_t info = *fp++;
+ ushort_t kind = CTF_INFO_KIND(info);
+ ushort_t n = CTF_INFO_VLEN(info);
+ ushort_t i;
+ int nextsym;
+ char *name;
+
+ if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx,
+ STT_FUNC, &name)) < 0)
+ name = NULL;
+ else
+ symidx = nextsym;
+
+ if (kind == CTF_K_UNKNOWN && n == 0)
+ continue; /* skip padding */
+
+ if (kind != CTF_K_FUNCTION) {
+ (void) printf(" [%lu] unexpected kind -- %u\n",
+ id, kind);
+ return (E_ERROR);
+ }
+
+ if (fp + n > end) {
+ (void) printf(" [%lu] vlen %u extends past section "
+ "boundary\n", id, n);
+ return (E_ERROR);
+ }
+
+ if (flags != F_STATS) {
+ (void) printf(" [%lu] FUNC ", id);
+ if (name != NULL)
+ (void) printf("(%s) ", name);
+ (void) printf("returns: %u args: (", *fp++);
+
+ if (n != 0) {
+ (void) printf("%u", *fp++);
+ for (i = 1; i < n; i++)
+ (void) printf(", %u", *fp++);
+ }
+
+ (void) printf(")\n");
+ } else
+ fp += n + 1; /* skip to next function definition */
+
+ stats.s_nfunc++;
+ stats.s_nargs += n;
+ stats.s_argmax = MAX(stats.s_argmax, n);
+ }
+
+ return (E_SUCCESS);
+}
+
+static int
+read_types(const ctf_header_t *hp, const ctf_data_t *cd)
+{
+ void *v = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
+ const ctf_type_t *tp = v;
+
+ v = (void *) (cd->cd_ctfdata + hp->cth_stroff);
+ const ctf_type_t *end = v;
+
+ ulong_t id;
+
+ if (flags != F_STATS)
+ print_line("- Types ");
+
+ if (hp->cth_typeoff & 3)
+ WARN("cth_typeoff is not aligned properly\n");
+ if (hp->cth_typeoff >= cd->cd_ctflen)
+ WARN("file is truncated or cth_typeoff is corrupt\n");
+ if (hp->cth_stroff >= cd->cd_ctflen)
+ WARN("file is truncated or cth_stroff is corrupt\n");
+ if (hp->cth_typeoff > hp->cth_stroff)
+ WARN("file is corrupt -- cth_typeoff > cth_stroff\n");
+
+ id = 1;
+ if (hp->cth_parlabel || hp->cth_parname)
+ id += 1 << CTF_PARENT_SHIFT;
+
+ for (/* */; tp < end; id++) {
+ ulong_t i, n = CTF_INFO_VLEN(tp->ctt_info);
+ size_t size, increment, vlen = 0;
+ int kind = CTF_INFO_KIND(tp->ctt_info);
+
+ union {
+ const void *ptr;
+ ctf_array_t *ap;
+ const ctf_member_t *mp;
+ const ctf_lmember_t *lmp;
+ const ctf_enum_t *ep;
+ const ushort_t *argp;
+ } u;
+
+ if (flags != F_STATS) {
+ (void) printf(" %c%lu%c ",
+ "[<"[CTF_INFO_ISROOT(tp->ctt_info)], id,
+ "]>"[CTF_INFO_ISROOT(tp->ctt_info)]);
+ }
+
+ if (tp->ctt_size == CTF_LSIZE_SENT) {
+ increment = sizeof (ctf_type_t);
+ size = (size_t)CTF_TYPE_LSIZE(tp);
+ } else {
+ increment = sizeof (ctf_stype_t);
+ size = tp->ctt_size;
+ }
+ u.ptr = (const char *)tp + increment;
+
+ switch (kind) {
+ case CTF_K_INTEGER:
+ if (flags != F_STATS) {
+ uint_t encoding = *((const uint_t *)u.ptr);
+
+ (void) printf("INTEGER %s encoding=%s offset=%u"
+ " bits=%u", ref_to_str(tp->ctt_name, hp,
+ cd), int_encoding_to_str(
+ CTF_INT_ENCODING(encoding)),
+ CTF_INT_OFFSET(encoding),
+ CTF_INT_BITS(encoding));
+ }
+ vlen = sizeof (uint_t);
+ break;
+
+ case CTF_K_FLOAT:
+ if (flags != F_STATS) {
+ uint_t encoding = *((const uint_t *)u.ptr);
+
+ (void) printf("FLOAT %s encoding=%s offset=%u "
+ "bits=%u", ref_to_str(tp->ctt_name, hp,
+ cd), fp_encoding_to_str(
+ CTF_FP_ENCODING(encoding)),
+ CTF_FP_OFFSET(encoding),
+ CTF_FP_BITS(encoding));
+ }
+ vlen = sizeof (uint_t);
+ break;
+
+ case CTF_K_POINTER:
+ if (flags != F_STATS) {
+ (void) printf("POINTER %s refers to %u",
+ ref_to_str(tp->ctt_name, hp, cd),
+ tp->ctt_type);
+ }
+ break;
+
+ case CTF_K_ARRAY:
+ if (flags != F_STATS) {
+ (void) printf("ARRAY %s content: %u index: %u "
+ "nelems: %u\n", ref_to_str(tp->ctt_name,
+ hp, cd), u.ap->cta_contents,
+ u.ap->cta_index, u.ap->cta_nelems);
+ }
+ vlen = sizeof (ctf_array_t);
+ break;
+
+ case CTF_K_FUNCTION:
+ if (flags != F_STATS) {
+ (void) printf("FUNCTION %s returns: %u args: (",
+ ref_to_str(tp->ctt_name, hp, cd),
+ tp->ctt_type);
+
+ if (n != 0) {
+ (void) printf("%u", *u.argp++);
+ for (i = 1; i < n; i++, u.argp++)
+ (void) printf(", %u", *u.argp);
+ }
+
+ (void) printf(")");
+ }
+
+ vlen = sizeof (ushort_t) * (n + (n & 1));
+ break;
+
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ if (kind == CTF_K_STRUCT) {
+ stats.s_nsmem += n;
+ stats.s_smmax = MAX(stats.s_smmax, n);
+ stats.s_nsbytes += size;
+ stats.s_sbmax = MAX(stats.s_sbmax, size);
+
+ if (flags != F_STATS)
+ (void) printf("STRUCT");
+ } else {
+ stats.s_numem += n;
+ stats.s_ummax = MAX(stats.s_ummax, n);
+ stats.s_nubytes += size;
+ stats.s_ubmax = MAX(stats.s_ubmax, size);
+
+ if (flags != F_STATS)
+ (void) printf("UNION");
+ }
+
+ if (flags != F_STATS) {
+ (void) printf(" %s (%zd bytes)\n",
+ ref_to_str(tp->ctt_name, hp, cd), size);
+
+ if (size >= CTF_LSTRUCT_THRESH) {
+ for (i = 0; i < n; i++, u.lmp++) {
+ (void) printf(
+ "\t%s type=%u off=%llu\n",
+ ref_to_str(u.lmp->ctlm_name,
+ hp, cd), u.lmp->ctlm_type,
+ (unsigned long long)
+ CTF_LMEM_OFFSET(u.lmp));
+ }
+ } else {
+ for (i = 0; i < n; i++, u.mp++) {
+ (void) printf(
+ "\t%s type=%u off=%u\n",
+ ref_to_str(u.mp->ctm_name,
+ hp, cd), u.mp->ctm_type,
+ u.mp->ctm_offset);
+ }
+ }
+ }
+
+ vlen = n * (size >= CTF_LSTRUCT_THRESH ?
+ sizeof (ctf_lmember_t) : sizeof (ctf_member_t));
+ break;
+
+ case CTF_K_ENUM:
+ if (flags != F_STATS) {
+ (void) printf("ENUM %s\n",
+ ref_to_str(tp->ctt_name, hp, cd));
+
+ for (i = 0; i < n; i++, u.ep++) {
+ (void) printf("\t%s = %d\n",
+ ref_to_str(u.ep->cte_name, hp, cd),
+ u.ep->cte_value);
+ }
+ }
+
+ stats.s_nemem += n;
+ stats.s_emmax = MAX(stats.s_emmax, n);
+
+ vlen = sizeof (ctf_enum_t) * n;
+ break;
+
+ case CTF_K_FORWARD:
+ if (flags != F_STATS) {
+ (void) printf("FORWARD %s",
+ ref_to_str(tp->ctt_name, hp, cd));
+ }
+ break;
+
+ case CTF_K_TYPEDEF:
+ if (flags != F_STATS) {
+ (void) printf("TYPEDEF %s refers to %u",
+ ref_to_str(tp->ctt_name, hp, cd),
+ tp->ctt_type);
+ }
+ break;
+
+ case CTF_K_VOLATILE:
+ if (flags != F_STATS) {
+ (void) printf("VOLATILE %s refers to %u",
+ ref_to_str(tp->ctt_name, hp, cd),
+ tp->ctt_type);
+ }
+ break;
+
+ case CTF_K_CONST:
+ if (flags != F_STATS) {
+ (void) printf("CONST %s refers to %u",
+ ref_to_str(tp->ctt_name, hp, cd),
+ tp->ctt_type);
+ }
+ break;
+
+ case CTF_K_RESTRICT:
+ if (flags != F_STATS) {
+ (void) printf("RESTRICT %s refers to %u",
+ ref_to_str(tp->ctt_name, hp, cd),
+ tp->ctt_type);
+ }
+ break;
+
+ case CTF_K_UNKNOWN:
+ break; /* hole in type id space */
+
+ default:
+ (void) printf("unexpected kind %u\n", kind);
+ return (E_ERROR);
+ }
+
+ if (flags != F_STATS)
+ (void) printf("\n");
+
+ stats.s_ntypes++;
+ stats.s_types[kind]++;
+
+ tp = (ctf_type_t *)((uintptr_t)tp + increment + vlen);
+ }
+
+ return (E_SUCCESS);
+}
+
+static int
+read_strtab(const ctf_header_t *hp, const ctf_data_t *cd)
+{
+ size_t n, off, len = hp->cth_strlen;
+ const char *s = cd->cd_ctfdata + hp->cth_stroff;
+
+ if (flags != F_STATS)
+ print_line("- String Table ");
+
+ if (hp->cth_stroff >= cd->cd_ctflen)
+ WARN("file is truncated or cth_stroff is corrupt\n");
+ if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen)
+ WARN("file is truncated or cth_strlen is corrupt\n");
+
+ for (off = 0; len != 0; off += n) {
+ if (flags != F_STATS) {
+ (void) printf(" [%lu] %s\n", (ulong_t)off,
+ s[0] == '\0' ? "\\0" : s);
+ }
+ n = strlen(s) + 1;
+ len -= n;
+ s += n;
+
+ stats.s_nstr++;
+ stats.s_strlen += n;
+ stats.s_strmax = MAX(stats.s_strmax, n);
+ }
+
+ return (E_SUCCESS);
+}
+
+static void
+long_stat(const char *name, ulong_t value)
+{
+ (void) printf(" %-36s= %lu\n", name, value);
+}
+
+static void
+fp_stat(const char *name, float value)
+{
+ (void) printf(" %-36s= %.2f\n", name, value);
+}
+
+static int
+print_stats(void)
+{
+ print_line("- CTF Statistics ");
+
+ long_stat("total number of data objects", stats.s_ndata);
+ (void) printf("\n");
+
+ long_stat("total number of functions", stats.s_nfunc);
+ long_stat("total number of function arguments", stats.s_nargs);
+ long_stat("maximum argument list length", stats.s_argmax);
+
+ if (stats.s_nfunc != 0) {
+ fp_stat("average argument list length",
+ (float)stats.s_nargs / (float)stats.s_nfunc);
+ }
+
+ (void) printf("\n");
+
+ long_stat("total number of types", stats.s_ntypes);
+ long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]);
+ long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]);
+ long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]);
+ long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]);
+ long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]);
+ long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]);
+ long_stat("total number of unions", stats.s_types[CTF_K_UNION]);
+ long_stat("total number of enums", stats.s_types[CTF_K_ENUM]);
+ long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]);
+ long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]);
+ long_stat("total number of volatile types",
+ stats.s_types[CTF_K_VOLATILE]);
+ long_stat("total number of const types", stats.s_types[CTF_K_CONST]);
+ long_stat("total number of restrict types",
+ stats.s_types[CTF_K_RESTRICT]);
+ long_stat("total number of unknowns (holes)",
+ stats.s_types[CTF_K_UNKNOWN]);
+
+ (void) printf("\n");
+
+ long_stat("total number of struct members", stats.s_nsmem);
+ long_stat("maximum number of struct members", stats.s_smmax);
+ long_stat("total size of all structs", stats.s_nsbytes);
+ long_stat("maximum size of a struct", stats.s_sbmax);
+
+ if (stats.s_types[CTF_K_STRUCT] != 0) {
+ fp_stat("average number of struct members",
+ (float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]);
+ fp_stat("average size of a struct", (float)stats.s_nsbytes /
+ (float)stats.s_types[CTF_K_STRUCT]);
+ }
+
+ (void) printf("\n");
+
+ long_stat("total number of union members", stats.s_numem);
+ long_stat("maximum number of union members", stats.s_ummax);
+ long_stat("total size of all unions", stats.s_nubytes);
+ long_stat("maximum size of a union", stats.s_ubmax);
+
+ if (stats.s_types[CTF_K_UNION] != 0) {
+ fp_stat("average number of union members",
+ (float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]);
+ fp_stat("average size of a union", (float)stats.s_nubytes /
+ (float)stats.s_types[CTF_K_UNION]);
+ }
+
+ (void) printf("\n");
+
+ long_stat("total number of enum members", stats.s_nemem);
+ long_stat("maximum number of enum members", stats.s_emmax);
+
+ if (stats.s_types[CTF_K_ENUM] != 0) {
+ fp_stat("average number of enum members",
+ (float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]);
+ }
+
+ (void) printf("\n");
+
+ long_stat("total number of unique strings", stats.s_nstr);
+ long_stat("bytes of string data", stats.s_strlen);
+ long_stat("maximum string length", stats.s_strmax);
+
+ if (stats.s_nstr != 0) {
+ fp_stat("average string length",
+ (float)stats.s_strlen / (float)stats.s_nstr);
+ }
+
+ (void) printf("\n");
+ return (E_SUCCESS);
+}
+
+static int
+print_usage(FILE *fp, int verbose)
+{
+ (void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getpname());
+
+ if (verbose) {
+ (void) fprintf(fp,
+ "\t-d dump data object section\n"
+ "\t-f dump function section\n"
+ "\t-h dump file header\n"
+ "\t-l dump label table\n"
+ "\t-s dump string table\n"
+ "\t-S dump statistics\n"
+ "\t-t dump type section\n"
+ "\t-u save uncompressed CTF to a file\n");
+ }
+
+ return (E_USAGE);
+}
+
+static Elf_Scn *
+findelfscn(Elf *elf, GElf_Ehdr *ehdr, const char *secname)
+{
+ GElf_Shdr shdr;
+ Elf_Scn *scn;
+ char *name;
+
+ for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) {
+ if (gelf_getshdr(scn, &shdr) != NULL && (name =
+ elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL &&
+ strcmp(name, secname) == 0)
+ return (scn);
+ }
+
+ return (NULL);
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *filename = NULL;
+ const char *ufile = NULL;
+ int error = 0;
+ int c, fd, ufd;
+
+ ctf_data_t cd;
+ const ctf_preamble_t *pp;
+ ctf_header_t *hp = NULL;
+ Elf *elf;
+ GElf_Ehdr ehdr;
+
+ (void) elf_version(EV_CURRENT);
+
+ for (opterr = 0; optind < argc; optind++) {
+ while ((c = getopt(argc, argv, "dfhlsStu:")) != (int)EOF) {
+ switch (c) {
+ case 'd':
+ flags |= F_DATA;
+ break;
+ case 'f':
+ flags |= F_FUNC;
+ break;
+ case 'h':
+ flags |= F_HDR;
+ break;
+ case 'l':
+ flags |= F_LABEL;
+ break;
+ case 's':
+ flags |= F_STR;
+ break;
+ case 'S':
+ flags |= F_STATS;
+ break;
+ case 't':
+ flags |= F_TYPES;
+ break;
+ case 'u':
+ ufile = optarg;
+ break;
+ default:
+ if (optopt == '?')
+ return (print_usage(stdout, 1));
+ warn("illegal option -- %c\n", optopt);
+ return (print_usage(stderr, 0));
+ }
+ }
+
+ if (optind < argc) {
+ if (filename != NULL)
+ return (print_usage(stderr, 0));
+ filename = argv[optind];
+ }
+ }
+
+ if (filename == NULL)
+ return (print_usage(stderr, 0));
+
+ if (flags == 0 && ufile == NULL)
+ flags = F_ALLMSK;
+
+ if ((fd = open(filename, O_RDONLY)) == -1)
+ die("failed to open %s", filename);
+
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL &&
+ gelf_getehdr(elf, &ehdr) != NULL) {
+
+ Elf_Data *dp = NULL;
+ Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf");
+ Elf_Scn *symscn;
+ GElf_Shdr ctfshdr;
+
+ if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL)
+ die("%s does not contain .SUNW_ctf data\n", filename);
+
+ cd.cd_ctfdata = dp->d_buf;
+ cd.cd_ctflen = dp->d_size;
+
+ /*
+ * If the sh_link field of the CTF section header is non-zero
+ * it indicates which section contains the symbol table that
+ * should be used. We default to the .symtab section if sh_link
+ * is zero or if there's an error reading the section header.
+ */
+ if (gelf_getshdr(ctfscn, &ctfshdr) != NULL &&
+ ctfshdr.sh_link != 0) {
+ symscn = elf_getscn(elf, ctfshdr.sh_link);
+ } else {
+ symscn = findelfscn(elf, &ehdr, ".symtab");
+ }
+
+ /* If we found a symbol table, find the corresponding strings */
+ if (symscn != NULL) {
+ GElf_Shdr shdr;
+ Elf_Scn *symstrscn;
+
+ if (gelf_getshdr(symscn, &shdr) != NULL) {
+ symstrscn = elf_getscn(elf, shdr.sh_link);
+
+ cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;
+ cd.cd_symdata = elf_getdata(symscn, NULL);
+ cd.cd_strdata = elf_getdata(symstrscn, NULL);
+ }
+ }
+ } else {
+ struct stat st;
+
+ if (fstat(fd, &st) == -1)
+ die("failed to fstat %s", filename);
+
+ cd.cd_ctflen = st.st_size;
+ cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ,
+ MAP_PRIVATE, fd, 0);
+ if (cd.cd_ctfdata == MAP_FAILED)
+ die("failed to mmap %s", filename);
+ }
+
+ /*
+ * Get a pointer to the CTF data buffer and interpret the first portion
+ * as a ctf_header_t. Validate the magic number and size.
+ */
+
+ if (cd.cd_ctflen < sizeof (ctf_preamble_t))
+ die("%s does not contain a CTF preamble\n", filename);
+
+ void *v = (void *) cd.cd_ctfdata;
+ pp = v;
+
+ if (pp->ctp_magic != CTF_MAGIC)
+ die("%s does not appear to contain CTF data\n", filename);
+
+ if (pp->ctp_version == CTF_VERSION) {
+ v = (void *) cd.cd_ctfdata;
+ hp = v;
+ cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t);
+
+ if (cd.cd_ctflen < sizeof (ctf_header_t)) {
+ die("%s does not contain a v%d CTF header\n", filename,
+ CTF_VERSION);
+ }
+
+ } else {
+ die("%s contains unsupported CTF version %d\n", filename,
+ pp->ctp_version);
+ }
+
+ /*
+ * If the data buffer is compressed, then malloc a buffer large enough
+ * to hold the decompressed data, and use zlib to decompress it.
+ */
+ if (hp->cth_flags & CTF_F_COMPRESS) {
+ z_stream zstr;
+ void *buf;
+ int rc;
+
+ if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL)
+ die("failed to allocate decompression buffer");
+
+ bzero(&zstr, sizeof (z_stream));
+ zstr.next_in = (void *)cd.cd_ctfdata;
+ zstr.avail_in = cd.cd_ctflen;
+ zstr.next_out = buf;
+ zstr.avail_out = hp->cth_stroff + hp->cth_strlen;
+
+ if ((rc = inflateInit(&zstr)) != Z_OK)
+ die("failed to initialize zlib: %s\n", zError(rc));
+
+ if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END)
+ die("failed to decompress CTF data: %s\n", zError(rc));
+
+ if ((rc = inflateEnd(&zstr)) != Z_OK)
+ die("failed to finish decompression: %s\n", zError(rc));
+
+ if (zstr.total_out != hp->cth_stroff + hp->cth_strlen)
+ die("CTF data is corrupt -- short decompression\n");
+
+ cd.cd_ctfdata = buf;
+ cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen;
+ }
+
+ if (flags & F_HDR)
+ error |= print_header(hp, &cd);
+ if (flags & (F_LABEL))
+ error |= print_labeltable(hp, &cd);
+ if (flags & (F_DATA | F_STATS))
+ error |= read_data(hp, &cd);
+ if (flags & (F_FUNC | F_STATS))
+ error |= read_funcs(hp, &cd);
+ if (flags & (F_TYPES | F_STATS))
+ error |= read_types(hp, &cd);
+ if (flags & (F_STR | F_STATS))
+ error |= read_strtab(hp, &cd);
+ if (flags & F_STATS)
+ error |= print_stats();
+
+ /*
+ * If the -u option is specified, write the uncompressed CTF data to a
+ * raw CTF file. CTF data can already be extracted compressed by
+ * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother.
+ */
+ if (ufile != NULL) {
+ ctf_header_t h;
+
+ bcopy(hp, &h, sizeof (h));
+ h.cth_flags &= ~CTF_F_COMPRESS;
+
+ if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 ||
+ write(ufd, &h, sizeof (h)) != sizeof (h) ||
+ write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != (int) cd.cd_ctflen) {
+ warn("failed to write CTF data to '%s'", ufile);
+ error |= E_ERROR;
+ }
+
+ (void) close(ufd);
+ }
+
+ if (elf != NULL)
+ (void) elf_end(elf);
+
+ (void) close(fd);
+ return (error);
+}